// 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()); }
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(); }
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 SetTransformParameters(TransformType::Pointer inputTransform) { transform->SetParameters( inputTransform->GetParameters() ); transform->SetFixedParameters( inputTransform->GetFixedParameters() ); buildSlices(); buildMaskSlices(); }