ITK Viola-Wells 互信息测度配准示例

#if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif /************************************************************************* *多模态图像配准示例 ----- 使用 Viola-Wells Mutual Information *多模态图像配准是医学图像配准中最具挑战性的工作之一, 无法应用基于直接比较 *灰度级别的测度. 基于互信息的测度是解决多模态图像配准的有效手段 *与其前面使用刚体变换的单模态图像配准示例的不同之处为: *1.使用 itk::MutualInformationImageToImageMetric 互信息测度 *2.本例使用了 itk::GradientDescentOptimizer 梯度下降法进行优化. *由于互信息测度计算的随机性,使用 itk::RegularStepGradientDescentOptimizer *优化法无法成功. 因此这里使用更简单的 GradientDescentOptimizer *该优化带有一用户自定义的 learning rate *************************************************************************/ #include "itkImageRegistrationMethod.h" #include "itkTranslationTransform.h" #include "itkMutualInformationImageToImageMetric.h" #include "itkLinearInterpolateImageFunction.h" #include "itkGradientDescentOptimizer.h" #include "itkImage.h" //一种使互信息的计算简单化的方法是归一化两幅输入图像的统计分布 //过滤器 itk::NormalizeImageFilter 正适合此任务 #include "itkNormalizeImageFilter.h" //低通滤波的图像也会增加对噪音的健壮性. //本例使用的是 itk::DiscreteGaussianImageFilter #include "itkDiscreteGaussianImageFilter.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCheckerBoardImageFilter.h" #include "itkCommand.h" //Command/Observer 设计模式,本例中简单地用于监视配准过程的执行 class CommandIterationUpdate : public itk::Command { public: typedef CommandIterationUpdate Self; typedef itk::Command Superclass; typedef itk::SmartPointer<Self> Pointer; itkNewMacro( Self ); protected: CommandIterationUpdate() {}; public: typedef itk::GradientDescentOptimizer OptimizerType; typedef const OptimizerType * OptimizerPointer; void Execute(itk::Object *caller, const itk::EventObject & event) { Execute( (const itk::Object *)caller, event); } //每次迭代都执行该方法,输出我们想要观察的参数 void Execute(const itk::Object * object, const itk::EventObject & event) { OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( object ); if( ! itk::IterationEvent().CheckEvent( &event ) ) { return; } std::cout << optimizer->GetCurrentIteration() << " "; std::cout << optimizer->GetValue() << " "; std::cout << optimizer->GetCurrentPosition() << std::endl; } }; 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 "; std::cerr << "[checkerBoardBefore] [checkerBoardAfter]" << std::endl; return EXIT_FAILURE; } //1.定义待配准图像类型: 维数, 像素类型 const unsigned int Dimension = 2; typedef unsigned short PixelType; typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::Image< PixelType, Dimension > MovingImageType; //内部图像类型, 像素类型为 float, 有利于互信息测度的计算 typedef float InternalPixelType; typedef itk::Image< InternalPixelType, Dimension > InternalImageType; //2.定义配准框架的基本组件: 变换, 优化, 测度, 插值, 配准组件 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(); //3.使用配准组件将:变换, 优化, 测度, 插值 四个基本组件连接至一起 registration->SetOptimizer( optimizer ); registration->SetTransform( transform ); registration->SetInterpolator( interpolator ); MetricType::Pointer metric = MetricType::New(); registration->SetMetric( metric ); //设置测度组件的部分参数 //测度要求选择若干参数, 包括用于固定及浮动图密度估计的高斯核的 //标准差(the standard deviation of the Gaussian kernel) //以及用于计算密度及熵值(entropy)的样本数目 //经验表明对于归一化为零均值单位方差的图像, 0.4 工作的很好. //此处使用该经验值------比较复杂的测度,其参数的选取非常关键*** metric->SetFixedImageStandardDeviation( 0.4 ); metric->SetMovingImageStandardDeviation( 0.4 ); //4.设置待配准图像及变换区域,并进行适当处理 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] ); //实例化 normalization filters //输入为 "固定图像" 或 "浮动图像", 输出为 "内部图像" typedef itk::NormalizeImageFilter< FixedImageType, InternalImageType > FixedNormalizeFilterType; typedef itk::NormalizeImageFilter< MovingImageType, InternalImageType > MovingNormalizeFilterType; FixedNormalizeFilterType::Pointer fixedNormalizer = FixedNormalizeFilterType::New(); MovingNormalizeFilterType::Pointer movingNormalizer = MovingNormalizeFilterType::New(); //模糊过滤器(blurring filters) typedef itk::DiscreteGaussianImageFilter<InternalImageType, InternalImageType> GaussianFilterType; GaussianFilterType::Pointer fixedSmoother = GaussianFilterType::New(); GaussianFilterType::Pointer movingSmoother = GaussianFilterType::New(); //本例, 两个 blurring filters 的方差都设置为 2.0 fixedSmoother->SetVariance( 2.0 ); movingSmoother->SetVariance( 2.0 ); //连接各个过滤器 //readers 的输出作为 normalization filters 的输入 //并将其输出连接至 blurring filters 的输入端 fixedNormalizer->SetInput( fixedImageReader->GetOutput() ); movingNormalizer->SetInput( movingImageReader->GetOutput() ); fixedSmoother->SetInput( fixedNormalizer->GetOutput() ); movingSmoother->SetInput( movingNormalizer->GetOutput() ); //连接 blurring filters 的输出至 registration method 的输入端 registration->SetFixedImage( fixedSmoother->GetOutput() ); registration->SetMovingImage( movingSmoother->GetOutput() ); //设置需要考虑的图像区域 fixedNormalizer->Update(); FixedImageType::RegionType fixedImageRegion = fixedNormalizer->GetOutput()->GetBufferedRegion(); registration->SetFixedImageRegion( fixedImageRegion ); //5.设置各组件的参数,变换、测度、优化,不同的方法需要不同的设置 //设置变换组件的参数 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 ); //设置测度组件参数,另一部分 //现在定义测度计算考虑的空间样本数目. //该值通常很小,可取固定图像像素总数目的 1% //增加样本数目可以改进测度值在两次迭代间的平滑度,在与依赖连续测度值的 //优化器协作工作时非常有利. 但在每次评估测度值时的计算量会增加. //经验表明,样本数量对配准过程并不是最关键的,通常可以使用比较大的 //数目如 20%, 50% 进行测试,当成功配准后再减少样本数量,直至找到合适的值. //通常需要研究迭代过程测度值的变化,以求得最佳值 const unsigned int numberOfPixels = fixedImageRegion.GetNumberOfPixels(); const unsigned int numberOfSamples = static_cast< unsigned int >( numberOfPixels * 0.01 ); metric->SetNumberOfSpatialSamples( numberOfSamples ); //设置优化组件的参数 //较大的互信息值表示两幅图像匹配的更好, 因此需要最大化代价函数. //默认情况下, GradientDescentOptimizer class 用来最小化代价函数值. //因此有必要通过调用 MaximizeOn() 方法修改其默认行为. //另外, 需要定义 optimizer 的步长 //注意,learning rate的值大将导致optimizer不稳定. //值小,可能需要迭代过多的次数.通常需要进行实验才能选取合适的值 //理想的值为,迭代次数小,并且优化参数空间保持稳定. 需要注意的是, //该参数对梯度测度的效果是成倍增加的, //因此对优化器步长的影响是与测度值成正比的. //测度值大, 则需要使用较小的 learning rate 以保持相似的优化行为 optimizer->SetLearningRate( 15.0 ); optimizer->SetNumberOfIterations( 200 ); optimizer->MaximizeOn(); //6.实例化一 Command/Observer 对象,监视配准过程的执行,并触发配准过程的执行. //监视配准过程的执行 CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); optimizer->AddObserver( itk::IterationEvent(), observer ); try { registration->StartRegistration(); } catch( itk::ExceptionObject & err ) { std::cout << "ExceptionObject caught !" << std::endl; std::cout << err << std::endl; return EXIT_FAILURE; } //取得配准执行完毕的最终参数 ParametersType finalParameters = registration->GetLastTransformParameters(); double TranslationAlongX = finalParameters[0]; double TranslationAlongY = finalParameters[1]; unsigned int numberOfIterations = optimizer->GetCurrentIteration(); double bestValue = optimizer->GetValue(); std::cout << std::endl; std::cout << " Result = " << std::endl; std::cout << " Translation X = " << TranslationAlongX << std::endl; std::cout << " Translation Y = " << TranslationAlongY << std::endl; std::cout << " Iterations = " << numberOfIterations << std::endl; std::cout << " Metric value = " << bestValue << std::endl; std::cout << " Numb. Samples = " << numberOfSamples << std::endl; //7.重采样, 将变换后的浮动图像映射到固定图像空间中,保存配准结果 //一般情况,最后一步为: 利用最终的变换结果将浮动图像映射到固定图像空间 //可通过 itk::ResampleImageFilter 完成 typedef itk::ResampleImageFilter< MovingImageType, FixedImageType > ResampleFilterType; TransformType::Pointer finalTransform = TransformType::New(); finalTransform->SetParameters( finalParameters ); finalTransform->SetFixedParameters( transform->GetFixedParameters() ); ResampleFilterType::Pointer resample = ResampleFilterType::New(); resample->SetTransform( finalTransform ); resample->SetInput( movingImageReader->GetOutput() ); FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); resample->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() ); resample->SetOutputOrigin( fixedImage->GetOrigin() ); resample->SetOutputSpacing( fixedImage->GetSpacing() ); resample->SetOutputDirection( fixedImage->GetDirection() ); resample->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( resample->GetOutput() ); writer->SetInput( caster->GetOutput() ); writer->Update(); typedef itk::CheckerBoardImageFilter< FixedImageType > CheckerBoardFilterType; CheckerBoardFilterType::Pointer checker = CheckerBoardFilterType::New(); checker->SetInput1( fixedImage ); checker->SetInput2( resample->GetOutput() ); caster->SetInput( checker->GetOutput() ); writer->SetInput( caster->GetOutput() ); //保存配准前浮动图像与固定图像的差异 TransformType::Pointer identityTransform = TransformType::New(); identityTransform->SetIdentity(); resample->SetTransform( identityTransform ); if( argc > 4 ) { writer->SetFileName( argv[4] ); writer->Update(); } //配准后的浮动图像与固定图像的差异 resample->SetTransform( finalTransform ); if( argc > 5 ) { writer->SetFileName( argv[5] ); writer->Update(); } return EXIT_SUCCESS; }

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(优化,object,image,command,Parameters,translation)