/*========================================================================= medInria Copyright (c) INRIA 2013. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. =========================================================================*/ #include "itkProcessRegistrationOptimus.h" #include // ///////////////////////////////////////////////////////////////// // // ///////////////////////////////////////////////////////////////// #include "itkImageRegistrationMethod.h" #include "itkImage.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "time.h" #include #include // ///////////////////////////////////////////////////////////////// // itkProcessRegistrationOptimusOptimusPrivate // ///////////////////////////////////////////////////////////////// class itkProcessRegistrationOptimusPrivate { public: itkProcessRegistrationOptimus * proc; template int update(void); template bool writeTransform(const QString& file); void * registrationMethod ; void deleteRegMethod(void); unsigned int iterations; unsigned int nbOfHistogramBins; unsigned int nbOfSpatialSamples; unsigned int nbOfInterpolations; float rhoStart; float rhoEnd; float scalingCoefficient; }; // ///////////////////////////////////////////////////////////////// // itkProcessRegistrationOptimus // ///////////////////////////////////////////////////////////////// itkProcessRegistrationOptimus::itkProcessRegistrationOptimus(void) : itkProcessRegistration(), d(new itkProcessRegistrationOptimusPrivate) { d->proc = this; d->registrationMethod = NULL ; this->setProperty("transformType","rigid"); } itkProcessRegistrationOptimus::~itkProcessRegistrationOptimus(void) { d->proc = NULL; switch(fixedImageType()){ // case itkProcessRegistration::UCHAR: // { // typedef itk::Image< float, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::CHAR: // { // typedef itk::Image< char, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::USHORT: // { // typedef itk::Image< unsigned short, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::SHORT: // { // typedef itk::Image< short, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::UINT: // { // typedef itk::Image< unsigned int, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::INT: // { // typedef itk::Image< int, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::ULONG: // { // typedef itk::Image< unsigned long, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::LONG: // { // typedef itk::Image< long, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // case itkProcessRegistration::DOUBLE: // { // typedef itk::Image< double, 3 > RegImageType; // delete static_cast *>(d->registrationMethod); // } // break; // we only work on float at the moment. default: { typedef itk::Image< float, 3 > RegImageType; delete static_cast *>(d->registrationMethod); } break; } d->registrationMethod = NULL; delete d; d = NULL; } bool itkProcessRegistrationOptimus::registered(void) { return dtkAbstractProcessFactory::instance()->registerProcessType("itkProcessRegistrationOptimus", createitkProcessRegistrationOptimus); } QString itkProcessRegistrationOptimus::description(void) const { return "Optimus"; } QString itkProcessRegistrationOptimus::identifier(void) const { return "itkProcessRegistrationOptimus"; } // ///////////////////////////////////////////////////////////////// // Templated Version of update // ///////////////////////////////////////////////////////////////// template int itkProcessRegistrationOptimusPrivate::update(void) { typedef itk::Image< PixelType, 3 > FixedImageType; typedef itk::Image< PixelType, 3 > MovingImageType; typename rpi::Optimus * registration = new rpi::Optimus (); registrationMethod = registration; registration->SetFixedImage((const FixedImageType*) proc->fixedImage().GetPointer()); registration->SetMovingImage((const MovingImageType*) proc->movingImages()[0].GetPointer()); registration->SetNumberOfIterations(iterations); registration->SetNumberOfHistogramBins(nbOfHistogramBins); registration->SetNumberOfInterpolations(nbOfInterpolations); registration->SetNumberOfSpatialSamples(nbOfSpatialSamples); registration->SetRhoStart(rhoStart); registration->SetRhoEnd(rhoEnd); registration->SetScalingCoefficient(scalingCoefficient); // Run the registration time_t t1 = clock(); try { registration->StartRegistration(); } catch( std::exception & err ) { qDebug() << "ExceptionObject caught ! (startRegistration)" << err.what(); return 1; } time_t t2 = clock(); qDebug() << "Elasped time: " << (double)(t2-t1)/(double)CLOCKS_PER_SEC; emit proc->progressed(70); typedef itk::ResampleImageFilter< MovingImageType,MovingImageType > ResampleFilterType; typename ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetTransform(registration->GetTransformation()); resampler->SetInput((const MovingImageType*)proc->movingImages()[0].GetPointer()); resampler->SetSize( proc->fixedImage()->GetLargestPossibleRegion().GetSize() ); resampler->SetOutputOrigin( proc->fixedImage()->GetOrigin() ); resampler->SetOutputSpacing( proc->fixedImage()->GetSpacing() ); resampler->SetOutputDirection( proc->fixedImage()->GetDirection() ); resampler->SetDefaultPixelValue( 0 ); try { resampler->Update(); } catch (itk::ExceptionObject &e) { qDebug() << e.GetDescription(); return 1; } itk::ImageBase<3>::Pointer result = resampler->GetOutput(); result->DisconnectPipeline(); if (proc->output()) proc->output()->setData (result); return 0; } int itkProcessRegistrationOptimus::update(itkProcessRegistration::ImageType imgType) { if(fixedImage().IsNull() || movingImages().isEmpty() || movingImages()[0].IsNull()) { qWarning() << "Either the fixed image or the moving image is Null"; return 1; } if (imgType != itkProcessRegistration::FLOAT) { qWarning() << "the imageType should be float, and it's :"<update(); // if(fixedImage().IsNull() || movingImages().isEmpty() // || movingImages()[0].IsNull()) // return 1; // switch (imgType){ // case itkProcessRegistration::UCHAR: // return d->update(); // break; // case itkProcessRegistration::CHAR: // return d->update(); // break; // case itkProcessRegistration::USHORT: // return d->update(); // break; // case itkProcessRegistration::SHORT: // return d->update(); // break; // case itkProcessRegistration::UINT: // return d->update(); // break; // case itkProcessRegistration::INT: // return d->update(); // break; // case itkProcessRegistration::ULONG: // return d->update(); // break; // case itkProcessRegistration::LONG: // return d->update(); // break; // case itkProcessRegistration::DOUBLE: // return d->update(); // break; // default: // return d->update(); // break; // } } itk::Transform::Pointer itkProcessRegistrationOptimus::getTransform() { typedef float PixelType; typedef double TransformScalarType; typedef itk::Image< PixelType, 3 > RegImageType; //normaly should use long switch cases, but here we know we work with float3 data. if (rpi::Optimus * registration = static_cast *>(d->registrationMethod)) { return registration->GetTransformation(); } return nullptr; } QString itkProcessRegistrationOptimus::getTitleAndParameters(){ typedef float PixelType; typedef itk::Image< PixelType, 3 > FixedImageType; typedef itk::Image< PixelType, 3 > MovingImageType; typedef rpi::Optimus RegistrationType; RegistrationType * registration = static_cast(d->registrationMethod); QString titleAndParameters; titleAndParameters += "Optimus\n"; titleAndParameters += " Max number of iterations : " + QString::number(registration->GetNumberOfIterations()) + "\n"; titleAndParameters += " Number of histogram bins : " + QString::number(registration->GetNumberOfHistogramBins()) + "\n"; titleAndParameters += " Number of spatial samples : " + QString::number(registration->GetNumberOfSpatialSamples()) + "\n"; titleAndParameters += " Number of interpolations : " + QString::number(registration->GetNumberOfInterpolations()) + "\n"; titleAndParameters += " Rho start : " + QString::number(registration->GetRhoStart()) + "\n"; titleAndParameters += " Rho end : " + QString::number(registration->GetRhoEnd()) + "\n"; titleAndParameters += " Scaling coefficient : " + QString::number(registration->GetScalingCoefficient()) + "\n"; return titleAndParameters; } bool itkProcessRegistrationOptimus::writeTransform(const QString& file) { if(!d->registrationMethod) return false; switch (this->fixedImageType()){ // case itkProcessRegistration::UCHAR: // return d->writeTransform(file); // break; // case itkProcessRegistration::CHAR: // return d->writeTransform(file); // break; // case itkProcessRegistration::USHORT: // return d->writeTransform(file); // break; // case itkProcessRegistration::SHORT: // return d->writeTransform(file); // break; // case itkProcessRegistration::UINT: // return d->writeTransform(file); // break; // case itkProcessRegistration::INT: // return d->writeTransform(file); // break; // case itkProcessRegistration::ULONG: // return d->writeTransform(file); // break; // case itkProcessRegistration::LONG: // return d->writeTransform(file); // break; // case itkProcessRegistration::DOUBLE: // return d->writeTransform(file); // break; default: return d->writeTransform(file); break; } } template bool itkProcessRegistrationOptimusPrivate::writeTransform(const QString& file) { //typedef float PixelType; typedef double TransformScalarType; typedef itk::Image< PixelType, 3 > RegImageType; if (rpi::Optimus * registration = static_cast *>(registrationMethod)) { try{ rpi::writeLinearTransformation( registration->GetTransformation(), file.toStdString()); } catch (std::exception) { return false; } return true; } else { return false; } } void itkProcessRegistrationOptimus::setNumberOfIterations(unsigned int iterations) { d->iterations = iterations; } void itkProcessRegistrationOptimus::setNumberOfInterpolations(unsigned int nbInterpolations) { d->nbOfInterpolations = nbInterpolations; } void itkProcessRegistrationOptimus::setNumberOfHistogramBins(unsigned int nbOfHistBins) { d->nbOfHistogramBins = nbOfHistBins; } void itkProcessRegistrationOptimus::setNumberOfSpatialSamples(unsigned int nbOfSpatSamp) { d->nbOfSpatialSamples = nbOfSpatSamp; } void itkProcessRegistrationOptimus::setRhoStart(float rhoStart) { d->rhoStart = rhoStart; } void itkProcessRegistrationOptimus::setRhoEnd(float rhoEnd) { d->rhoEnd = rhoEnd; } void itkProcessRegistrationOptimus::setScalingCoefficient(float scalingCoeff) { d->scalingCoefficient = scalingCoeff; } // ///////////////////////////////////////////////////////////////// // Type instanciation // ///////////////////////////////////////////////////////////////// dtkAbstractProcess *createitkProcessRegistrationOptimus(void) { return new itkProcessRegistrationOptimus; }