int main( int argc, char *argv[] ) { if( argc < 4 ) { std::cerr << "Missing Parameters " << std::endl; std::cerr << "Usage: " << argv[0]; std::cerr << " fixedImageFile movingImageFile "; std::cerr << " outputImagefile [differenceBeforeRegistration] "; std::cerr << " [differenceAfterRegistration] "; std::cerr << " [sliceBeforeRegistration] "; std::cerr << " [sliceDifferenceBeforeRegistration] "; std::cerr << " [sliceDifferenceAfterRegistration] "; std::cerr << " [sliceAfterRegistration] " << std::endl; return EXIT_FAILURE; } const unsigned int Dimension = 3; typedef float PixelType; typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::Image< PixelType, Dimension > MovingImageType; // Software Guide : BeginLatex // // The Transform class is instantiated using the code below. The only // template parameter to this class is the representation type of the // space coordinates. // // \index{itk::Versor\-Rigid3D\-Transform!Instantiation} // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet // Software Guide : EndCodeSnippet typedef itk:: LinearInterpolateImageFunction< MovingImageType, double > InterpolatorType; typedef itk::ImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType; MetricType::Pointer metric = MetricType::New(); OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); registration->SetMetric( metric ); registration->SetOptimizer( optimizer ); registration->SetInterpolator( interpolator ); // Software Guide : BeginLatex // // The transform object is constructed below and passed to the registration // method. // // \index{itk::Versor\-Rigid3D\-Transform!New()} // \index{itk::Versor\-Rigid3D\-Transform!Pointer} // \index{itk::Registration\-Method!SetTransform()} // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet TransformType::Pointer transform = TransformType::New(); registration->SetTransform( transform ); // Software Guide : EndCodeSnippet typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType; FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); fixedImageReader->SetFileName( argv[1] ); movingImageReader->SetFileName( argv[2] ); registration->SetFixedImage( fixedImageReader->GetOutput() ); registration->SetMovingImage( movingImageReader->GetOutput() ); fixedImageReader->Update(); registration->SetFixedImageRegion( fixedImageReader->GetOutput()->GetBufferedRegion() ); // Software Guide : BeginLatex // // The input images are taken from readers. It is not necessary here to // explicitly call \code{Update()} on the readers since the // \doxygen{CenteredTransformInitializer} will do it as part of its // computations. The following code instantiates the type of the // initializer. This class is templated over the fixed and moving image type // as well as the transform type. An initializer is then constructed by // calling the \code{New()} method and assigning the result to a smart // pointer. // // \index{itk::Centered\-Transform\-Initializer!Instantiation} // \index{itk::Centered\-Transform\-Initializer!New()} // \index{itk::Centered\-Transform\-Initializer!SmartPointer} // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet // Software Guide : BeginLatex // // Let's execute this example over some of the images available in the ftp // site // // \url{ftp://public.kitware.com/pub/itk/Data/BrainWeb} // // Note that the images in the ftp site are compressed in \code{.tgz} files. // You should download these files an uncompress them in your local system. // After decompressing and extracting the files you could take a pair of // volumes, for example the pair: // // \begin{itemize} // \item \code{brainweb1e1a10f20.mha} // \item \code{brainweb1e1a10f20Rot10Tx15.mha} // \end{itemize} // // The second image is the result of intentionally rotating the first image // by $10$ degrees around the origin and shifting it $15mm$ in $X$. The // registration takes $24$ iterations and produces: // // \begin{center} // \begin{verbatim} // [-6.03744e-05, 5.91487e-06, -0.0871932, 2.64659, -17.4637, -0.00232496] // \end{verbatim} // \end{center} // // That are interpreted as // // \begin{itemize} // \item Versor = $(-6.03744e-05, 5.91487e-06, -0.0871932)$ // \item Translation = $(2.64659, -17.4637, -0.00232496)$ millimeters // \end{itemize} // // This Versor is equivalent to a rotation of $9.98$ degrees around the $Z$ // axis. // // Note that the reported translation is not the translation of $(15.0,0.0,0.0)$ // that we may be naively expecting. The reason is that the // \code{VersorRigid3DTransform} is applying the rotation around the center // found by the \code{CenteredTransformInitializer} and then adding the // translation vector shown above. // // It is more illustrative in this case to take a look at the actual // rotation matrix and offset resulting form the $6$ parameters. // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet transform->SetParameters( finalParameters ); TransformType::MatrixType matrix = transform->GetMatrix(); TransformType::OffsetType offset = transform->GetOffset(); std::cout << "Matrix = " << std::endl << matrix << std::endl; std::cout << "Offset = " << std::endl << offset << std::endl; // Software Guide : EndCodeSnippet // Software Guide : BeginLatex // // The output of this print statements is // // \begin{center} // \begin{verbatim} // Matrix = // 0.984795 0.173722 2.23132e-05 // -0.173722 0.984795 0.000119257 // -1.25621e-06 -0.00012132 1 // // Offset = // [-15.0105, -0.00672343, 0.0110854] // \end{verbatim} // \end{center} // // From the rotation matrix it is possible to deduce that the rotation is // happening in the X,Y plane and that the angle is on the order of // $\arcsin{(0.173722)}$ which is very close to 10 degrees, as we expected. // // Software Guide : EndLatex // Software Guide : BeginLatex // // \begin{figure} // \center // \includegraphics[width=0.44\textwidth]{BrainProtonDensitySliceBorder20} // \includegraphics[width=0.44\textwidth]{BrainProtonDensitySliceR10X13Y17} // \itkcaption[CenteredTransformInitializer input images]{Fixed and moving image // provided as input to the registration method using // CenteredTransformInitializer.} // \label{fig:FixedMovingImageRegistration8} // \end{figure} // // // \begin{figure} // \center // \includegraphics[width=0.32\textwidth]{ImageRegistration8Output} // \includegraphics[width=0.32\textwidth]{ImageRegistration8DifferenceBefore} // \includegraphics[width=0.32\textwidth]{ImageRegistration8DifferenceAfter} // \itkcaption[CenteredTransformInitializer output images]{Resampled moving // image (left). Differences between fixed and moving images, before (center) // and after (right) registration with the // CenteredTransformInitializer.} // \label{fig:ImageRegistration8Outputs} // \end{figure} // // Figure \ref{fig:ImageRegistration8Outputs} shows the output of the // registration. The center image in this figure shows the differences // between the fixed image and the resampled moving image before the // registration. The image on the right side presents the difference between // the fixed image and the resampled moving image after the registration has // been performed. Note that these images are individual slices extracted // from the actual volumes. For details, look at the source code of this // example, where the ExtractImageFilter is used to extract a slice from the // the center of each one of the volumes. One of the main purposes of this // example is to illustrate that the toolkit can perform registration on // images of any dimension. The only limitations are, as usual, the amount of // memory available for the images and the amount of computation time that it // will take to complete the optimization process. // // \begin{figure} // \center // \includegraphics[height=0.32\textwidth]{ImageRegistration8TraceMetric} // \includegraphics[height=0.32\textwidth]{ImageRegistration8TraceAngle} // \includegraphics[height=0.32\textwidth]{ImageRegistration8TraceTranslations} // \itkcaption[CenteredTransformInitializer output plots]{Plots of the metric, // rotation angle, center of rotation and translations during the // registration using CenteredTransformInitializer.} // \label{fig:ImageRegistration8Plots} // \end{figure} // // Figure \ref{fig:ImageRegistration8Plots} shows the plots of the main // output parameters of the registration process. The metric values at every // iteration. The Z component of the versor is plotted as an indication of // how the rotation progress. The X,Y translation components of the // registration are plotted at every iteration too. // // Shell and Gnuplot scripts for generating the diagrams in // Figure~\ref{fig:ImageRegistration8Plots} are available in the directory // // \code{InsightDocuments/SoftwareGuide/Art} // // You are strongly encouraged to run the example code, since only in this // way you can gain a first hand experience with the behavior of the // registration process. Once again, this is a simple reflection of the // philosophy that we put forward in this book: // // \emph{If you can not replicate it, then it does not exist!}. // // We have seen enough published papers with pretty pictures, presenting // results that in practice are impossible to replicate. That is vanity, not // science. // // Software Guide : EndLatex typedef itk::ResampleImageFilter< MovingImageType, FixedImageType > ResampleFilterType; TransformType::Pointer finalTransform = TransformType::New(); finalTransform->SetCenter( transform->GetCenter() ); finalTransform->SetParameters( finalParameters ); finalTransform->SetFixedParameters( transform->GetFixedParameters() ); ResampleFilterType::Pointer resampler = ResampleFilterType::New(); resampler->SetTransform( finalTransform ); resampler->SetInput( movingImageReader->GetOutput() ); FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); resampler->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() ); resampler->SetOutputOrigin( fixedImage->GetOrigin() ); resampler->SetOutputSpacing( fixedImage->GetSpacing() ); resampler->SetOutputDirection( fixedImage->GetDirection() ); resampler->SetDefaultPixelValue( 100 ); typedef unsigned char OutputPixelType; typedef itk::Image< OutputPixelType, Dimension > OutputImageType; typedef itk::CastImageFilter< FixedImageType, OutputImageType > CastFilterType; typedef itk::ImageFileWriter< OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); CastFilterType::Pointer caster = CastFilterType::New(); writer->SetFileName( argv[3] ); caster->SetInput( resampler->GetOutput() ); writer->SetInput( caster->GetOutput() ); writer->Update(); typedef itk::SubtractImageFilter< FixedImageType, FixedImageType, FixedImageType > DifferenceFilterType; DifferenceFilterType::Pointer difference = DifferenceFilterType::New(); typedef itk::RescaleIntensityImageFilter< FixedImageType, OutputImageType > RescalerType; RescalerType::Pointer intensityRescaler = RescalerType::New(); intensityRescaler->SetInput( difference->GetOutput() ); intensityRescaler->SetOutputMinimum( 0 ); intensityRescaler->SetOutputMaximum( 255 ); difference->SetInput1( fixedImageReader->GetOutput() ); difference->SetInput2( resampler->GetOutput() ); resampler->SetDefaultPixelValue( 1 ); WriterType::Pointer writer2 = WriterType::New(); writer2->SetInput( intensityRescaler->GetOutput() ); // Compute the difference image between the // fixed and resampled moving image. if( argc > 5 ) { writer2->SetFileName( argv[5] ); writer2->Update(); } typedef itk::IdentityTransform< double, Dimension > IdentityTransformType; IdentityTransformType::Pointer identity = IdentityTransformType::New(); // Compute the difference image between the // fixed and moving image before registration. if( argc > 4 ) { resampler->SetTransform( identity ); writer2->SetFileName( argv[4] ); writer2->Update(); } // // Here we extract slices from the input volume, and the difference volumes // produced before and after the registration. These slices are presented as // figures in the Software Guide. // // typedef itk::Image< OutputPixelType, 2 > OutputSliceType; typedef itk::ExtractImageFilter< OutputImageType, OutputSliceType > ExtractFilterType; ExtractFilterType::Pointer extractor = ExtractFilterType::New(); extractor->SetDirectionCollapseToSubmatrix(); extractor->InPlaceOn(); FixedImageType::RegionType inputRegion = fixedImage->GetLargestPossibleRegion(); FixedImageType::SizeType size = inputRegion.GetSize(); FixedImageType::IndexType start = inputRegion.GetIndex(); // Select one slice as output size[2] = 0; start[2] = 90; FixedImageType::RegionType desiredRegion; desiredRegion.SetSize( size ); desiredRegion.SetIndex( start ); extractor->SetExtractionRegion( desiredRegion ); typedef itk::ImageFileWriter< OutputSliceType > SliceWriterType; SliceWriterType::Pointer sliceWriter = SliceWriterType::New(); sliceWriter->SetInput( extractor->GetOutput() ); if( argc > 6 ) { extractor->SetInput( caster->GetOutput() ); resampler->SetTransform( identity ); sliceWriter->SetFileName( argv[6] ); sliceWriter->Update(); } if( argc > 7 ) { extractor->SetInput( intensityRescaler->GetOutput() ); resampler->SetTransform( identity ); sliceWriter->SetFileName( argv[7] ); sliceWriter->Update(); } if( argc > 8 ) { resampler->SetTransform( finalTransform ); sliceWriter->SetFileName( argv[8] ); sliceWriter->Update(); } if( argc > 9 ) { extractor->SetInput( caster->GetOutput() ); resampler->SetTransform( finalTransform ); sliceWriter->SetFileName( argv[9] ); sliceWriter->Update(); } return EXIT_SUCCESS; }
// perform B-spline registration for 2D image void runBspline2D(StringVector& args) { typedef itk::BSplineTransform<double, 2, 3> TransformType; typedef itk::LBFGSOptimizer OptimizerType; typedef itk::MeanSquaresImageToImageMetric<RealImage2, RealImage2> MetricType; typedef itk:: LinearInterpolateImageFunction<RealImage2, double> InterpolatorType; typedef itk::ImageRegistrationMethod<RealImage2, RealImage2> RegistrationType; MetricType::Pointer metric = MetricType::New(); OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); // The old registration framework has problems with multi-threading // For now, we set the number of threads to 1 registration->SetNumberOfThreads(1); registration->SetMetric( metric ); registration->SetOptimizer( optimizer ); registration->SetInterpolator( interpolator ); TransformType::Pointer transform = TransformType::New(); registration->SetTransform( transform ); ImageIO<RealImage2> io; // Create the synthetic images RealImage2::Pointer fixedImage = io.ReadImage(args[0]); RealImage2::Pointer movingImage = io.ReadImage(args[1]); // Setup the registration registration->SetFixedImage( fixedImage ); registration->SetMovingImage( movingImage); RealImage2::RegionType fixedRegion = fixedImage->GetBufferedRegion(); registration->SetFixedImageRegion( fixedRegion ); TransformType::PhysicalDimensionsType fixedPhysicalDimensions; TransformType::MeshSizeType meshSize; for( unsigned int i=0; i < 2; i++ ) { fixedPhysicalDimensions[i] = fixedImage->GetSpacing()[i] * static_cast<double>( fixedImage->GetLargestPossibleRegion().GetSize()[i] - 1 ); } unsigned int numberOfGridNodesInOneDimension = 18; meshSize.Fill( numberOfGridNodesInOneDimension - 3 ); transform->SetTransformDomainOrigin( fixedImage->GetOrigin() ); transform->SetTransformDomainPhysicalDimensions( fixedPhysicalDimensions ); transform->SetTransformDomainMeshSize( meshSize ); transform->SetTransformDomainDirection( fixedImage->GetDirection() ); typedef TransformType::ParametersType ParametersType; const unsigned int numberOfParameters = transform->GetNumberOfParameters(); ParametersType parameters( numberOfParameters ); parameters.Fill( 0.0 ); transform->SetParameters( parameters ); // We now pass the parameters of the current transform as the initial // parameters to be used when the registration process starts. registration->SetInitialTransformParameters( transform->GetParameters() ); std::cout << "Intial Parameters = " << std::endl; std::cout << transform->GetParameters() << std::endl; // Next we set the parameters of the LBFGS Optimizer. optimizer->SetGradientConvergenceTolerance( 0.005 ); optimizer->SetLineSearchAccuracy( 0.9 ); optimizer->SetDefaultStepLength( .1 ); optimizer->TraceOn(); optimizer->SetMaximumNumberOfFunctionEvaluations( 1000 ); std::cout << std::endl << "Starting Registration" << std::endl; try { registration->Update(); std::cout << "Optimizer stop condition = " << registration->GetOptimizer()->GetStopConditionDescription() << std::endl; } catch( itk::ExceptionObject & err ) { std::cerr << "ExceptionObject caught !" << std::endl; std::cerr << err << std::endl; return; } OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters(); std::cout << "Last Transform Parameters" << std::endl; std::cout << finalParameters << std::endl; transform->SetParameters( finalParameters ); typedef itk::ResampleImageFilter<RealImage2, RealImage2> ResampleFilterType; ResampleFilterType::Pointer resample = ResampleFilterType::New(); resample->SetTransform( transform ); resample->SetInput( movingImage ); resample->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() ); resample->SetOutputOrigin( fixedImage->GetOrigin() ); resample->SetOutputSpacing( fixedImage->GetSpacing() ); resample->SetOutputDirection( fixedImage->GetDirection() ); resample->SetDefaultPixelValue( 100 ); resample->Update(); io.WriteImage(args[2], resample->GetOutput()); }
bool mitk::NavigationDataLandmarkTransformFilter::FindCorrespondentLandmarks(LandmarkPointContainer& sources, const LandmarkPointContainer& targets) const { if (sources.size() < 6 || targets.size() < 6) return false; //throw std::invalid_argument("ICP correspondence finding needs at least 6 landmarks"); /* lots of type definitions */ typedef itk::PointSet<mitk::ScalarType, 3> PointSetType; //typedef itk::BoundingBox<PointSetType::PointIdentifier, PointSetType::PointDimension> BoundingBoxType; typedef itk::EuclideanDistancePointMetric< PointSetType, PointSetType> MetricType; //typedef MetricType::TransformType TransformBaseType; //typedef MetricType::TransformType::ParametersType ParametersType; //typedef TransformBaseType::JacobianType JacobianType; //typedef itk::Euler3DTransform< double > TransformType; typedef itk::VersorRigid3DTransform< double > TransformType; typedef TransformType ParametersType; typedef itk::PointSetToPointSetRegistrationMethod< PointSetType, PointSetType > RegistrationType; /* copy landmarks to itk pointsets for registration */ PointSetType::Pointer sourcePointSet = PointSetType::New(); unsigned int i = 0; for (LandmarkPointContainer::const_iterator it = sources.begin(); it != sources.end(); ++it) { PointSetType::PointType doublePoint; mitk::itk2vtk(*it, doublePoint); // copy mitk::ScalarType point into double point as workaround to ITK 3.10 bug sourcePointSet->SetPoint(i++, doublePoint /**it*/); } i = 0; PointSetType::Pointer targetPointSet = PointSetType::New(); for (LandmarkPointContainer::const_iterator it = targets.begin(); it != targets.end(); ++it) { PointSetType::PointType doublePoint; mitk::itk2vtk(*it, doublePoint); // copy mitk::ScalarType point into double point as workaround to ITK 3.10 bug targetPointSet->SetPoint(i++, doublePoint /**it*/); } /* get centroid and extends of our pointsets */ //BoundingBoxType::Pointer sourceBoundingBox = BoundingBoxType::New(); //sourceBoundingBox->SetPoints(sourcePointSet->GetPoints()); //sourceBoundingBox->ComputeBoundingBox(); //BoundingBoxType::Pointer targetBoundingBox = BoundingBoxType::New(); //targetBoundingBox->SetPoints(targetPointSet->GetPoints()); //targetBoundingBox->ComputeBoundingBox(); TransformType::Pointer transform = TransformType::New(); transform->SetIdentity(); //transform->SetTranslation(targetBoundingBox->GetCenter() - sourceBoundingBox->GetCenter()); itk::LevenbergMarquardtOptimizer::Pointer optimizer = itk::LevenbergMarquardtOptimizer::New(); optimizer->SetUseCostFunctionGradient(false); RegistrationType::Pointer registration = RegistrationType::New(); // Scale the translation components of the Transform in the Optimizer itk::LevenbergMarquardtOptimizer::ScalesType scales(transform->GetNumberOfParameters()); const double translationScale = 5000; //sqrtf(targetBoundingBox->GetDiagonalLength2()) * 1000; // dynamic range of translations const double rotationScale = 1.0; // dynamic range of rotations scales[0] = 1.0 / rotationScale; scales[1] = 1.0 / rotationScale; scales[2] = 1.0 / rotationScale; scales[3] = 1.0 / translationScale; scales[4] = 1.0 / translationScale; scales[5] = 1.0 / translationScale; //scales.Fill(0.01); unsigned long numberOfIterations = 80000; double gradientTolerance = 1e-10; // convergence criterion double valueTolerance = 1e-10; // convergence criterion double epsilonFunction = 1e-10; // convergence criterion optimizer->SetScales( scales ); optimizer->SetNumberOfIterations( numberOfIterations ); optimizer->SetValueTolerance( valueTolerance ); optimizer->SetGradientTolerance( gradientTolerance ); optimizer->SetEpsilonFunction( epsilonFunction ); registration->SetInitialTransformParameters( transform->GetParameters() ); //------------------------------------------------------ // Connect all the components required for Registration //------------------------------------------------------ MetricType::Pointer metric = MetricType::New(); registration->SetMetric( metric ); registration->SetOptimizer( optimizer ); registration->SetTransform( transform ); registration->SetFixedPointSet( targetPointSet ); registration->SetMovingPointSet( sourcePointSet ); try { //registration->StartRegistration(); registration->Update(); } catch( itk::ExceptionObject & e ) { MITK_INFO << "Exception caught during ICP optimization: " << e; return false; //throw e; } MITK_INFO << "ICP successful: Solution = " << transform->GetParameters() << std::endl; MITK_INFO << "Metric value: " << metric->GetValue(transform->GetParameters()); /* find point correspondences */ //mitk::PointLocator::Pointer pointLocator = mitk::PointLocator::New(); // <<- use mitk::PointLocator instead of searching manually? //pointLocator->SetPoints() for (LandmarkPointContainer::const_iterator sourcesIt = sources.begin(); sourcesIt != sources.end(); ++sourcesIt) { } //MetricType::MeasureType closestDistances = metric->GetValue(transform->GetParameters()); //unsigned int index = 0; LandmarkPointContainer sortedSources; for (LandmarkPointContainer::const_iterator targetsIt = targets.begin(); targetsIt != targets.end(); ++targetsIt) { double minDistance = itk::NumericTraits<double>::max(); LandmarkPointContainer::iterator minDistanceIterator = sources.end(); for (LandmarkPointContainer::iterator sourcesIt = sources.begin(); sourcesIt != sources.end(); ++sourcesIt) { TransformInitializerType::LandmarkPointType transformedSource = transform->TransformPoint(*sourcesIt); double dist = targetsIt->EuclideanDistanceTo(transformedSource); MITK_INFO << "target: " << *targetsIt << ", source: " << *sourcesIt << ", transformed source: " << transformedSource << ", dist: " << dist; if (dist < minDistance ) { minDistanceIterator = sourcesIt; minDistance = dist; } } if (minDistanceIterator == sources.end()) return false; MITK_INFO << "minimum distance point is: " << *minDistanceIterator << " (dist: " << targetsIt->EuclideanDistanceTo(transform->TransformPoint(*minDistanceIterator)) << ", minDist: " << minDistance << ")"; sortedSources.push_back(*minDistanceIterator); // this point is assigned sources.erase(minDistanceIterator); // erase it from sources to avoid duplicate assigns } //for (LandmarkPointContainer::const_iterator sortedSourcesIt = sortedSources.begin(); targetsIt != sortedSources.end(); ++targetsIt) sources = sortedSources; return true; }
void MutualInformationRegistration::updateRegistration() { if(!isReady()) return; convertVolumes(); //typedef itk::RegularStepGradientDescentOptimizer OptimizerType; typedef itk::VersorRigid3DTransformOptimizer OptimizerType; typedef OptimizerType::ScalesType OptimizerScalesType; typedef itk::LinearInterpolateImageFunction< InternalImageType, double > InterpolatorType; typedef itk::MattesMutualInformationImageToImageMetric< InternalImageType, InternalImageType > MetricType; typedef itk::MultiResolutionImageRegistrationMethod< InternalImageType, InternalImageType > RegistrationType; typedef itk::MultiResolutionPyramidImageFilter< InternalImageType, InternalImageType > FixedImagePyramidType; typedef itk::MultiResolutionPyramidImageFilter< InternalImageType, InternalImageType > MovingImagePyramidType; OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); MetricType::Pointer metric = MetricType::New(); FixedImagePyramidType::Pointer fixedImagePyramid = FixedImagePyramidType::New(); MovingImagePyramidType::Pointer movingImagePyramid = MovingImagePyramidType::New(); registration->SetOptimizer(optimizer); registration->SetTransform(transform_); registration->SetInterpolator(interpolator); registration->SetMetric(metric); registration->SetFixedImagePyramid(fixedImagePyramid); registration->SetMovingImagePyramid(movingImagePyramid); OptimizerScalesType optimizerScales( transform_->GetNumberOfParameters() ); float rotScale = 1.0 / 1000.0f; optimizerScales[0] = 1.0f; optimizerScales[1] = 1.0f; optimizerScales[2] = 1.0f; optimizerScales[3] = rotScale; optimizerScales[4] = rotScale; optimizerScales[5] = rotScale; optimizer->SetScales( optimizerScales ); optimizer->SetMaximumStepLength(0.2); optimizer->SetMinimumStepLength(0.0001); InternalImageType::Pointer fixed = voreenToITK<float>(fixedVolumeFloat_); InternalImageType::Pointer moving = voreenToITK<float>(movingVolumeFloat_); registration->SetFixedImage(fixed); registration->SetMovingImage(moving); registration->SetFixedImageRegion( fixed->GetBufferedRegion() ); registration->SetInitialTransformParameters( transform_->GetParameters() ); metric->SetNumberOfHistogramBins(numHistogramBins_.get()); size_t numVoxels = hmul(fixedVolumeFloat_->getDimensions()); metric->SetNumberOfSpatialSamples(numVoxels * numSamples_.get()); metric->ReinitializeSeed( 76926294 ); //// Define whether to calculate the metric derivative by explicitly //// computing the derivatives of the joint PDF with respect to the Transform //// parameters, or doing it by progressively accumulating contributions from //// each bin in the joint PDF. metric->SetUseExplicitPDFDerivatives(explicitPDF_.get()); optimizer->SetNumberOfIterations(numIterations_.get()); optimizer->SetRelaxationFactor(relaxationFactor_.get()); // Create the Command observer and register it with the optimizer. CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); optimizer->AddObserver( itk::IterationEvent(), observer ); typedef RegistrationInterfaceCommand<RegistrationType> CommandType; CommandType::Pointer command = CommandType::New(); registration->AddObserver( itk::IterationEvent(), command ); registration->SetNumberOfLevels(numLevels_.get()); try { registration->StartRegistration(); std::cout << "Optimizer stop condition: " << registration->GetOptimizer()->GetStopConditionDescription() << std::endl; } catch( itk::ExceptionObject & err ) { std::cout << "ExceptionObject caught !" << std::endl; std::cout << err << std::endl; //return EXIT_FAILURE; } ParametersType finalParameters = registration->GetLastTransformParameters(); transform_->SetParameters(finalParameters); unsigned int numberOfIterations = optimizer->GetCurrentIteration(); double bestValue = optimizer->GetValue(); // Print out results std::cout << "Result = " << std::endl; std::cout << " Versor " << finalParameters[0] << " " << finalParameters[1] << " " << finalParameters[2] << std::endl; std::cout << " Translation " << finalParameters[1] << " " << finalParameters[4] << " " << finalParameters[5] << std::endl; std::cout << " Iterations = " << numberOfIterations << std::endl; std::cout << " Metric value = " << bestValue << std::endl; invalidate(INVALID_RESULT); }
RealImage::Pointer bsplineRegistration(RealImage::Pointer srcImg, RealImage::Pointer dstImg) { const unsigned int SpaceDimension = ImageDimension; const unsigned int SplineOrder = 3; typedef double CoordinateRepType; typedef itk::BSplineTransform<CoordinateRepType, SpaceDimension, SplineOrder> TransformType; typedef itk::LBFGSOptimizer OptimizerType; typedef itk::MeanSquaresImageToImageMetric<ImageType, ImageType> MetricType; typedef itk::LinearInterpolateImageFunction<ImageType, double> InterpolatorType; typedef itk::ImageRegistrationMethod<ImageType, ImageType> RegistrationType; MetricType::Pointer metric = MetricType::New(); OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); // The old registration framework has problems with multi-threading // For now, we set the number of threads to 1 // registration->SetNumberOfThreads(1); registration->SetMetric( metric ); registration->SetOptimizer( optimizer ); registration->SetInterpolator( interpolator ); TransformType::Pointer transform = TransformType::New(); registration->SetTransform( transform ); // Setup the registration registration->SetFixedImage( dstImg ); registration->SetMovingImage( srcImg); ImageType::RegionType fixedRegion = srcImg->GetBufferedRegion(); registration->SetFixedImageRegion( fixedRegion ); // Here we define the parameters of the BSplineDeformableTransform grid. We // arbitrarily decide to use a grid with $5 \times 5$ nodes within the image. // The reader should note that the BSpline computation requires a // finite support region ( 1 grid node at the lower borders and 2 // grid nodes at upper borders). Therefore in this example, we set // the grid size to be $8 \times 8$ and place the grid origin such that // grid node (1,1) coincides with the first pixel in the fixed image. TransformType::PhysicalDimensionsType fixedPhysicalDimensions; TransformType::MeshSizeType meshSize; for (unsigned int i=0; i < ImageDimension; i++) { fixedPhysicalDimensions[i] = dstImg->GetSpacing()[i] * static_cast<double>(dstImg->GetLargestPossibleRegion().GetSize()[i] - 1 ); meshSize[i] = dstImg->GetLargestPossibleRegion().GetSize()[i] / 8 - SplineOrder; } // unsigned int numberOfGridNodesInOneDimension = 15; // meshSize.Fill( numberOfGridNodesInOneDimension - SplineOrder ); transform->SetTransformDomainOrigin( dstImg->GetOrigin() ); transform->SetTransformDomainPhysicalDimensions( fixedPhysicalDimensions ); transform->SetTransformDomainMeshSize( meshSize ); transform->SetTransformDomainDirection( dstImg->GetDirection() ); typedef TransformType::ParametersType ParametersType; const unsigned int numberOfParameters = transform->GetNumberOfParameters(); ParametersType parameters( numberOfParameters ); parameters.Fill( 0.0 ); transform->SetParameters( parameters ); // We now pass the parameters of the current transform as the initial // parameters to be used when the registration process starts. registration->SetInitialTransformParameters( transform->GetParameters() ); std::cout << "Intial Parameters = " << std::endl; std::cout << transform->GetParameters() << std::endl; // Next we set the parameters of the LBFGS Optimizer. optimizer->SetGradientConvergenceTolerance(0.1); optimizer->SetLineSearchAccuracy(0.09); optimizer->SetDefaultStepLength(.1); optimizer->TraceOn(); optimizer->SetMaximumNumberOfFunctionEvaluations(1000); std::cout << std::endl << "Starting Registration" << std::endl; try { registration->Update(); std::cout << "Optimizer stop condition = " << registration->GetOptimizer()->GetStopConditionDescription() << std::endl; } catch (itk::ExceptionObject & err) { std::cerr << "ExceptionObject caught !" << std::endl; std::cerr << err << std::endl; return RealImage::Pointer(); } OptimizerType::ParametersType finalParameters = registration->GetLastTransformParameters(); std::cout << "Last Transform Parameters" << std::endl; std::cout << finalParameters << std::endl; transform->SetParameters( finalParameters ); typedef itk::ResampleImageFilter<ImageType, ImageType> ResampleFilterType; ResampleFilterType::Pointer resample = ResampleFilterType::New(); resample->SetTransform( transform ); resample->SetInput( srcImg ); resample->SetSize( dstImg->GetLargestPossibleRegion().GetSize() ); resample->SetOutputOrigin( dstImg->GetOrigin() ); resample->SetOutputSpacing( dstImg->GetSpacing() ); resample->SetOutputDirection( dstImg->GetDirection() ); resample->SetDefaultPixelValue( 100 ); resample->Update(); return resample->GetOutput(); }
void MRFRegistrationDisplay::startRegistration() { //////////////////////////////////////////////////////////////// // We move through the list of moving images registering them // to the fixed image //////////////////////////////////////////////////////////////// ImageType::Pointer workingImage = itkMovingImages.front()->GetOutput(); int numImages = this->itkMovingImages.size(); for(int imageNum = 0; imageNum < numImages; imageNum++) { typedef itk::BSplineInterpolateImageFunction<ImageType, double> InterpolatorType; GridImageType::Pointer gridImage = GridImageType::New(); createGridImage(gridImage); // create a new registration object RegistrationType::Pointer registration = RegistrationType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); // set the registration parameters registration->SetFixedImage(this->itkFixedImage); registration->SetMovingImage(workingImage); registration->SetInterpolator(interpolator); registration->SetBSplineGrid(gridImage); registration->SetImageLevels(this->resolutionLevels); registration->SetLabelSteps(this->labelSteps); registration->SetLabelScaleFactor(this->labelInc); registration->SetSparseSampling(this->useSparseSampling); registration->SetMaximumDisplacement(this->maxDisplacement); registration->SetLinkMaximumDisplacementToGrid(false); registration->SetOptimiserIterations(this->optimiserIterations); registration->SetRegularisationLambda(this->regularisationAmount); registration->SetPotentialType(RegistrationType::NCC); try { registration->Update(); } catch(itk::ExceptionObject &e) { std::cout << "F**k" << std::endl; std::cout << e << std::endl; return; } } // create the grid image GridImageType::Pointer gridImage = GridImageType::New(); this->createGridImage(gridImage); }
void QAngioSubstractionExtension::computeAutomateSingleImage() { QApplication::setOverrideCursor(Qt::WaitCursor); const unsigned int Dimension = 2; typedef Volume::ItkPixelType PixelType; typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::Image< PixelType, Dimension > MovingImageType; typedef float InternalPixelType; typedef itk::Image< InternalPixelType, Dimension > InternalImageType; typedef itk::TranslationTransform< double, Dimension > TransformType; typedef itk::GradientDescentOptimizer OptimizerType; typedef itk::LinearInterpolateImageFunction< InternalImageType, double > InterpolatorType; typedef itk::ImageRegistrationMethod< InternalImageType, InternalImageType > RegistrationType; typedef itk::MutualInformationImageToImageMetric< InternalImageType, InternalImageType > MetricType; TransformType::Pointer transform = TransformType::New(); OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); registration->SetOptimizer(optimizer); registration->SetTransform(transform); registration->SetInterpolator(interpolator); MetricType::Pointer metric = MetricType::New(); registration->SetMetric(metric); metric->SetFixedImageStandardDeviation(0.4); metric->SetMovingImageStandardDeviation(0.4); metric->SetNumberOfSpatialSamples(50); typedef itk::ExtractImageFilter< Volume::ItkImageType, FixedImageType > FilterType; FilterType::Pointer extractFixedImageFilter = FilterType::New(); Volume::ItkImageType::RegionType inputRegion = m_mainVolume->getItkData()->GetLargestPossibleRegion(); Volume::ItkImageType::SizeType size = inputRegion.GetSize(); //Dividim la mida per dos per tal de quedar-nos només amb la part central // ja que si no ens registre el background size[0] = size[0] / 2; size[1] = size[1] / 2; size[2] = 0; Volume::ItkImageType::IndexType start = inputRegion.GetIndex(); const unsigned int sliceReference = m_imageSelectorSpinBox->value(); //comencem a un quart de la imatge start[0] = size[0] / 2; start[1] = size[1] / 2; start[2] = sliceReference; Volume::ItkImageType::RegionType desiredRegion; desiredRegion.SetSize(size); desiredRegion.SetIndex(start); extractFixedImageFilter->SetExtractionRegion(desiredRegion); extractFixedImageFilter->SetInput(m_mainVolume->getItkData()); extractFixedImageFilter->Update(); FilterType::Pointer extractMovingImageFilter = FilterType::New(); Volume::ItkImageType::IndexType startMoving = inputRegion.GetIndex(); const unsigned int sliceNumber = m_2DView_1->getViewer()->getCurrentSlice(); startMoving[0] = size[0] / 2; startMoving[1] = size[1] / 2; startMoving[2] = sliceNumber; Volume::ItkImageType::RegionType desiredMovingRegion; desiredMovingRegion.SetSize(size); desiredMovingRegion.SetIndex(startMoving); extractMovingImageFilter->SetExtractionRegion(desiredMovingRegion); extractMovingImageFilter->SetInput(m_mainVolume->getItkData()); extractMovingImageFilter->Update(); typedef itk::NormalizeImageFilter< FixedImageType, InternalImageType > FixedNormalizeFilterType; typedef itk::NormalizeImageFilter< MovingImageType, InternalImageType > MovingNormalizeFilterType; FixedNormalizeFilterType::Pointer fixedNormalizer = FixedNormalizeFilterType::New(); MovingNormalizeFilterType::Pointer movingNormalizer = MovingNormalizeFilterType::New(); typedef itk::DiscreteGaussianImageFilter< InternalImageType, InternalImageType > GaussianFilterType; GaussianFilterType::Pointer fixedSmoother = GaussianFilterType::New(); GaussianFilterType::Pointer movingSmoother = GaussianFilterType::New(); fixedSmoother->SetVariance(2.0); movingSmoother->SetVariance(2.0); fixedNormalizer->SetInput(extractFixedImageFilter->GetOutput()); movingNormalizer->SetInput(extractMovingImageFilter->GetOutput()); fixedSmoother->SetInput(fixedNormalizer->GetOutput()); movingSmoother->SetInput(movingNormalizer->GetOutput()); registration->SetFixedImage(fixedSmoother->GetOutput()); registration->SetMovingImage(movingSmoother->GetOutput()); fixedNormalizer->Update(); registration->SetFixedImageRegion( fixedNormalizer->GetOutput()->GetBufferedRegion()); typedef RegistrationType::ParametersType ParametersType; ParametersType initialParameters(transform->GetNumberOfParameters()); initialParameters[0] = 0.0; // Initial offset in mm along X initialParameters[1] = 0.0; // Initial offset in mm along Y registration->SetInitialTransformParameters(initialParameters); optimizer->SetLearningRate(20.0); optimizer->SetNumberOfIterations(200); optimizer->MaximizeOn(); try { registration->Update(); } catch(itk::ExceptionObject & err) { std::cout << "ExceptionObject caught !" << std::endl; std::cout << err << std::endl; return; } ParametersType finalParameters = registration->GetLastTransformParameters(); double TranslationAlongX = finalParameters[0]; double TranslationAlongY = finalParameters[1]; // Print out results // DEBUG_LOG(QString("Result = ")); DEBUG_LOG(QString(" Translation X = %1").arg(TranslationAlongX)); DEBUG_LOG(QString(" Translation Y = %1").arg(TranslationAlongY)); DEBUG_LOG(QString(" Iterations = %1").arg(optimizer->GetCurrentIteration())); DEBUG_LOG(QString(" Metric value = %1").arg(optimizer->GetValue())); double spacing[3]; m_mainVolume->getSpacing(spacing); DEBUG_LOG(QString(" Translation X (in px) = %1").arg(TranslationAlongX / spacing[0])); DEBUG_LOG(QString(" Translation Y (in px) = %1").arg(TranslationAlongY / spacing[1])); //Actualitzem les dades de la transdifference tool m_toolManager->triggerTool("TransDifferenceTool"); TransDifferenceTool* tdTool = static_cast<TransDifferenceTool*> (m_2DView_2->getViewer()->getToolProxy()->getTool("TransDifferenceTool")); if(m_tdToolData == 0){ m_tdToolData = static_cast<TransDifferenceToolData*> (tdTool->getToolData()); } if(m_tdToolData->getInputVolume() != m_mainVolume){ m_tdToolData->setInputVolume(m_mainVolume); } tdTool->setSingleDifferenceImage(TranslationAlongX / spacing[0],TranslationAlongY / spacing[1]); m_toolManager->triggerTool("SlicingTool"); /* typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::Image< PixelType, Dimension > MovingImageType; typedef itk::TranslationTransform< double, Dimension > TransformType; typedef itk::RegularStepGradientDescentOptimizer OptimizerType; typedef itk::MattesMutualInformationImageToImageMetric< FixedImageType, MovingImageType > MetricType; typedef itk:: LinearInterpolateImageFunction< MovingImageType, double > InterpolatorType; typedef itk::ImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType; MetricType::Pointer metric = MetricType::New(); TransformType::Pointer transform = TransformType::New(); OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); registration->SetMetric(metric); registration->SetOptimizer(optimizer); registration->SetTransform(transform); registration->SetInterpolator(interpolator); metric->SetNumberOfHistogramBins(50); metric->SetNumberOfSpatialSamples(10000); typedef itk::ExtractImageFilter< Volume::ItkImageType, FixedImageType > FilterType; FilterType::Pointer extractFixedImageFilter = FilterType::New(); Volume::ItkImageType::RegionType inputRegion = m_mainVolume->getItkData()->GetLargestPossibleRegion(); Volume::ItkImageType::SizeType size = inputRegion.GetSize(); //Dividim la mida per dos per tal de quedar-nos només amb la part central // ja que si no ens registre el background size[0] = size[0] / 2; size[1] = size[1] / 2; size[2] = 0; Volume::ItkImageType::IndexType start = inputRegion.GetIndex(); const unsigned int sliceReference = m_imageSelectorSpinBox->value(); //comencem a un quart de la imatge start[0] = size[0] / 2; start[1] = size[1] / 2; start[2] = sliceReference; Volume::ItkImageType::RegionType desiredRegion; desiredRegion.SetSize(size); desiredRegion.SetIndex(start); extractFixedImageFilter->SetExtractionRegion(desiredRegion); extractFixedImageFilter->SetInput(m_mainVolume->getItkData()); extractFixedImageFilter->Update(); FilterType::Pointer extractMovingImageFilter = FilterType::New(); Volume::ItkImageType::IndexType startMoving = inputRegion.GetIndex(); const unsigned int sliceNumber = m_2DView_1->getViewer()->getCurrentSlice(); startMoving[0] = size[0] / 2; startMoving[1] = size[1] / 2; startMoving[2] = sliceNumber; Volume::ItkImageType::RegionType desiredMovingRegion; desiredMovingRegion.SetSize(size); desiredMovingRegion.SetIndex(startMoving); extractMovingImageFilter->SetExtractionRegion(desiredMovingRegion); extractMovingImageFilter->SetInput(m_mainVolume->getItkData()); extractMovingImageFilter->Update(); registration->SetFixedImage(extractFixedImageFilter->GetOutput()); registration->SetMovingImage(extractMovingImageFilter->GetOutput()); typedef RegistrationType::ParametersType ParametersType; ParametersType initialParameters(transform->GetNumberOfParameters()); //Potser seria millor posar la transformada que té actualment initialParameters[0] = 0.0; // Initial offset in mm along X initialParameters[1] = 0.0; // Initial offset in mm along Y registration->SetInitialTransformParameters(initialParameters); optimizer->SetMaximumStepLength(4.00); optimizer->SetMinimumStepLength(0.005); optimizer->SetNumberOfIterations(200); try { registration->StartRegistration(); } catch(itk::ExceptionObject & err) { DEBUG_LOG(QString("ExceptionObject caught !")); std::cout<<err<<std::endl; return; } ParametersType finalParameters = registration->GetLastTransformParameters(); const double TranslationAlongX = finalParameters[0]; const double TranslationAlongY = finalParameters[1]; const unsigned int numberOfIterations = optimizer->GetCurrentIteration(); const double bestValue = optimizer->GetValue(); DEBUG_LOG(QString("Result = ")); DEBUG_LOG(QString(" Translation X = %1").arg(TranslationAlongX)); DEBUG_LOG(QString(" Translation Y = %1").arg(TranslationAlongY)); DEBUG_LOG(QString(" Iterations = %1").arg(numberOfIterations)); DEBUG_LOG(QString(" Metric value = %1").arg(bestValue)); typedef unsigned char OutputPixelType; typedef itk::Image< OutputPixelType, Dimension > OutputImageType; typedef itk::RescaleIntensityImageFilter< FixedImageType, FixedImageType > RescaleFilterType; typedef itk::ResampleImageFilter< FixedImageType, FixedImageType > ResampleFilterType; typedef itk::CastImageFilter< FixedImageType, OutputImageType > CastFilterType; typedef itk::ImageFileWriter< OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); CastFilterType::Pointer caster = CastFilterType::New(); ResampleFilterType::Pointer resample = ResampleFilterType::New(); RescaleFilterType::Pointer rescaler = RescaleFilterType::New(); rescaler->SetOutputMinimum(0); rescaler->SetOutputMaximum(255); TransformType::Pointer finalTransform = TransformType::New(); finalTransform->SetParameters(finalParameters); resample->SetTransform(finalTransform); resample->SetSize(extractMovingImageFilter->GetOutput()->GetLargestPossibleRegion().GetSize()); resample->SetOutputOrigin(extractMovingImageFilter->GetOutput()->GetOrigin()); resample->SetOutputSpacing(extractMovingImageFilter->GetOutput()->GetSpacing()); resample->SetDefaultPixelValue(100); writer->SetFileName("prova.jpg"); rescaler->SetInput(extractMovingImageFilter->GetOutput()); resample->SetInput(rescaler->GetOutput()); caster->SetInput(resample->GetOutput()); writer->SetInput(caster->GetOutput()); writer->Update(); */ QApplication::restoreOverrideCursor(); }