ITK 配准框架

ITK 配准框架示例

图像配准的基本过程如下: 
1.指定用于评估配准效果的相似度或误差测度; 
2.指定一个变换模型,如刚体变换、仿射变换、弹性变换(elastic)、
流体变换或B-样条等; 
3.指定插值策略,如最邻近插值(nearst neighbour)、三线性插值(trilinear)、sinc插值等; 
4.寻找变换参数以最大化相似性测度。 
如下图所示:

 frame

配准框架的基本流程如下: 
1.输入待配准的两幅图像,参考图 Fixed Image,浮动图 Moving Image. 
2.对参考图的指定区域进行几何坐标变换(Transform) 得到新的区域 ; 
3.通过插值方法(Image Interpolator)得到浮动图在上一步新区域的坐标; 
4.相似性测度模块计算参考图和插值图之间的相似度,是一个关于几何变换参数的函数; 
5.相似度函数输入到优化模块中进行最优化计算得到最终变换参数,这个过程一般通过 
   迭代来实现,即重复2~4步直到取得最大值; 
6.整个配准算法模块输出浮动图在最优变换下的插值图像。  
   配准过程是一个优化问题,配准过程每进行一次迭代,得到一测度值,将该测度值与 
我们所设定的值进行比较,如果达到预期的效果则停止迭代,得到最终配准结果。当然, 
迭代可能无限制进行,所以我们还需要设置一迭代上限。


下面以一个简单例子对 ITK 中的配准框架进行说明: 
ITK 的配准框架由如下几个组件组成:变换组件、相似性测度组件、插值组件和优化组件;各个组件通过一个称为“配准方法”的组件连接到一起,形成一个一个管道结构。

//代码:

 

 

[cpp]  view plain copy
  1. #if defined(_MSC_VER)  
  2. #pragma warning ( disable : 4786 )  
  3. #endif  
  4.   
  5.   
  6. //本例演示了使用刚体变换进行 2D 图像配准, 使用的变换为 itk::CenteredRigid2DTransform  
  7. #include "itkImageRegistrationMethod.h"  
  8. #include "itkMeanSquaresImageToImageMetric.h"  
  9. #include "itkLinearInterpolateImageFunction.h"  
  10. #include "itkRegularStepGradientDescentOptimizer.h"  
  11. #include "itkImage.h"  
  12. #include "itkCenteredRigid2DTransform.h"  
  13. #include "itkImageFileReader.h"  
  14. #include "itkImageFileWriter.h"  
  15. #include "itkResampleImageFilter.h"  
  16. #include "itkSubtractImageFilter.h"  
  17. #include "itkRescaleIntensityImageFilter.h"  
  18. #include "itkCommand.h"  
  19.   
  20. /********************************************************************  
  21. *类 CommandIterationUpdate:创建 Command/Observer 设计模式的简单方式  
  22. *本例中它的主要功能为监视配准过程的执行,每迭代一次,调用一次Execute() 方法,输出相应参数  
  23. *此处涉及三个类: itk::Object, itk::Command,itk::EventObject。  
  24. *Object 是大多数类的基类,该类维护一个着一个指针链表,指针指向事件观察者(event observer).   
  25. *Observer 的角色由 Command 类扮演, Observers 通过一个 Object 注册自己,声明当一特定事件发 
  26. *生时. 配准过程通过一 itk::Optimizer 执行一个迭代过程来控制. 大多数 optimizer 在每次迭代 
  27. *后都会调用一 itk::IterationEvent. 当一个事件发生时, 该对象遍历 registred observers(Command) 
  28. *链表,并检查哪一个对该事件感兴趣, 当找到一个对该事件感兴趣的 observer 时,则调用与其关联的  
  29. *Execute() 方法. 在这方面, Execute() 应该看做是一个 callback,所以它应该 遵循一般 callback  
  30. *的原则,如不应该执行计算机量大的任务,应该只完成一些快速且简单的任务.  
  31. ********************************************************************/   
  32.   
  33. class CommandIterationUpdate : public itk::Command   
  34. {  
  35. public:  
  36.     typedef  CommandIterationUpdate   Self;  
  37.     typedef  itk::Command             Superclass;  
  38.     typedef itk::SmartPointer<Self>  Pointer;  
  39.   
  40.     //itkNewMacro: 该宏包装了 New() 方法的所有代码  
  41.     itkNewMacro( Self );  
  42.   
  43. protected:  
  44.     CommandIterationUpdate() {};  
  45. public:  
  46.     typedef itk::RegularStepGradientDescentOptimizer     OptimizerType;  
  47.     typedef   const OptimizerType   *    OptimizerPointer;  
  48.   
  49.     void Execute(itk::Object *caller, const itk::EventObject & event)  
  50.     {  
  51.         Execute( (const itk::Object *)caller, event);  
  52.     }  
  53.       
  54.     //object: 指向激活事件的对象;event: 需要被激活的事件  
  55.     void Execute(const itk::Object * object, const itk::EventObject & event)  
  56.     {  
  57.         OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( object );  
  58.   
  59.         //CheckEvent() 检测是否是观察的事件  
  60.         if( ! itk::IterationEvent().CheckEvent( &event ) )  
  61.         {  
  62.             return;  
  63.         }  
  64.         std::cout << optimizer->GetCurrentIteration() << "   ";  
  65.         std::cout << optimizer->GetValue() << "   ";  
  66.         std::cout << optimizer->GetCurrentPosition() << std::endl;  
  67.     }  
  68. };  
  69.   
  70. int main( int argc, char *argv[] )  
  71. {  
  72.     if( argc < 4 )  
  73.     {  
  74.         std::cerr << "Missing Parameters " << std::endl;  
  75.         std::cerr << "Usage: " << argv[0];  
  76.         std::cerr << " fixedImageFile  movingImageFile ";  
  77.         std::cerr << " outputImagefile  [differenceAfterRegistration] ";  
  78.         std::cerr << " [differenceBeforeRegistration] ";  
  79.         std::cerr << " [initialStepLength] "<< std::endl;  
  80.         return EXIT_FAILURE;  
  81.     }  
  82.       
  83.     //1.定义待配准图像类型: 维数, 像素类型  
  84.     const    unsigned int    Dimension = 2;  
  85.     typedef  unsigned char   PixelType;  
  86.     typedef itk::Image< PixelType, Dimension >  FixedImageType;  
  87.     typedef itk::Image< PixelType, Dimension >  MovingImageType;  
  88.   
  89.     //2.定义配准框架的基本组件: 变换, 优化, 测度, 插值, 配准组件  
  90.     //用于 2D 图像的一个刚体变换,该变换的唯一参数为: 空间坐标的类型  
  91.     typedef itk::CenteredRigid2DTransform< double > TransformType;  
  92.     typedef itk::RegularStepGradientDescentOptimizer       OptimizerType;  
  93.     typedef itk::MeanSquaresImageToImageMetric< FixedImageType,   
  94.                                     MovingImageType > MetricType;  
  95.     typedef itk::LinearInterpolateImageFunction< MovingImageType,  
  96.                                     double >  InterpolatorType;  
  97.   
  98.     //配准组件: 该组件用于连接其它各组件  
  99.     typedef itk::ImageRegistrationMethod< FixedImageType,   
  100.                                 MovingImageType > RegistrationType;  
  101.   
  102.     MetricType::Pointer         metric        = MetricType::New();  
  103.     OptimizerType::Pointer      optimizer     = OptimizerType::New();  
  104.     InterpolatorType::Pointer   interpolator  = InterpolatorType::New();  
  105.     RegistrationType::Pointer   registration  = RegistrationType::New();  
  106.   
  107.     //3.使用配准组件将:变换, 优化, 测度, 插值 四个基本组件连接至一起  
  108.     registration->SetMetric(        metric        );  
  109.     registration->SetOptimizer(     optimizer     );  
  110.     registration->SetInterpolator(  interpolator  );  
  111.     TransformType::Pointer  transform = TransformType::New();  
  112.     registration->SetTransform( transform );  
  113.   
  114.     //4.设置待配准图像及变换区域  
  115.     //定义待配准两幅输入图像的 reader  
  116.     typedef itk::ImageFileReader< FixedImageType  > FixedImageReaderType;  
  117.     typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;  
  118.   
  119.     FixedImageReaderType::Pointer  fixedImageReader    
  120.                         = FixedImageReaderType::New();  
  121.     MovingImageReaderType::Pointer movingImageReader   
  122.                         = MovingImageReaderType::New();  
  123.     fixedImageReader->SetFileName(  argv[1] );  
  124.     movingImageReader->SetFileName( argv[2] );  
  125.   
  126.     //本例, 固定图像与浮动图像都来自文件  
  127.     //需要 itk::ImageRegistrationMethod 从 file readers 的输出获取输入  
  128.     registration->SetFixedImage(    fixedImageReader->GetOutput()    );  
  129.     registration->SetMovingImage(   movingImageReader->GetOutput()   );  
  130.     //更新 readers,确保在初始化变换时图像参数(size,origin,spacing)有效.  
  131.     fixedImageReader->Update();           
  132.   
  133.     //可以将配准限制在固定图像的一特定区域,通过将其作为测度(metric)计算的输入.  
  134.     //该区域通过方法SetFixedImageRegion() 定义. 通过使用这个特征, 可以避免图像  
  135.     //中某些不需要的的对象影响配准输出,或者减少计算时间,本例中使用整幅图像.   
  136.     //此区域通过 BufferedRegion 标识.  
  137.     registration->SetFixedImageRegion(   
  138.                     fixedImageReader->GetOutput()->GetBufferedRegion() );  
  139.   
  140.     //更新固定,浮动图像 reader, 使其 origin, size, spacing 有效,  
  141.     fixedImageReader->Update();  
  142.     movingImageReader->Update();  
  143.   
  144.     //5.设置各组件的参数,主要是变换、优化组件的参数  
  145.     //本例使用的为变换为: 先进行一个旋转变换,再进行一平移变换.  
  146.     typedef FixedImageType::SpacingType    SpacingType;  
  147.     typedef FixedImageType::PointType      OriginType;  
  148.     typedef FixedImageType::RegionType     RegionType;  
  149.     typedef FixedImageType::SizeType       SizeType;  
  150.   
  151.     FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput();  
  152.     const SpacingType fixedSpacing = fixedImage->GetSpacing();  
  153.     const OriginType  fixedOrigin  = fixedImage->GetOrigin();  
  154.     const RegionType  fixedRegion  = fixedImage->GetLargestPossibleRegion();   
  155.     const SizeType    fixedSize    = fixedRegion.GetSize();  
  156.   
  157.     //本例使用固定图像的中心点做为旋转中心  
  158.     //使用固定图与浮动图中心之间距离向量作为平移量  
  159.     //首先计算固定图像中心点  
  160.     TransformType::InputPointType centerFixed;  
  161.     centerFixed[0] = fixedOrigin[0] + fixedSpacing[0] * fixedSize[0] / 2.0;  
  162.     centerFixed[1] = fixedOrigin[1] + fixedSpacing[1] * fixedSize[1] / 2.0;  
  163.   
  164.     MovingImageType::Pointer movingImage = movingImageReader->GetOutput();  
  165.     const SpacingType movingSpacing = movingImage->GetSpacing();  
  166.     const OriginType  movingOrigin  = movingImage->GetOrigin();  
  167.     const RegionType  movingRegion  = movingImage->GetLargestPossibleRegion();  
  168.     const SizeType    movingSize    = movingRegion.GetSize();  
  169.   
  170.     //然后计算浮动图像中心点  
  171.     TransformType::InputPointType centerMoving;  
  172.     centerMoving[0] = movingOrigin[0] + movingSpacing[0] * movingSize[0] / 2.0;  
  173.     centerMoving[1] = movingOrigin[1] + movingSpacing[1] * movingSize[1] / 2.0;  
  174.   
  175.     //设置旋转中心  
  176.     transform->SetCenter( centerFixed );  
  177.     //设置平移量  
  178.     transform->SetTranslation( centerMoving - centerFixed );  
  179.     //设置初始旋转角度  
  180.     transform->SetAngle( 0.0 );  
  181.     //然后将当前的变换参数作为初始参数, 传递给配准过程  
  182.     registration->SetInitialTransformParameters( transform->GetParameters() );  
  183.   
  184.     //设置优化组件参数.  
  185.     //注意: 旋转和变换的"单位刻度" 是不同的,旋转用弧度度量, 平移以毫米度量  
  186.     typedef OptimizerType::ScalesType       OptimizerScalesType;  
  187.     OptimizerScalesType optimizerScales( transform->GetNumberOfParameters() );  
  188.     const double translationScale = 1.0 / 1000.0;  
  189.   
  190.     optimizerScales[0] = 1.0;  
  191.     optimizerScales[1] = translationScale;  
  192.     optimizerScales[2] = translationScale;  
  193.     optimizerScales[3] = translationScale;  
  194.     optimizerScales[4] = translationScale;  
  195.     optimizer->SetScales( optimizerScales );  
  196.   
  197.     //本例使用的优化器是 itk::RegularStepGradientDescentOptimizer,   
  198.     //梯度下降法的一种,下面定义优化参数:   
  199.     //relaxation fator, initial step length, minimal step length, number of iterations  
  200.     double initialStepLength = 0.1;             //初始步长  
  201.     if( argc > 6 )  
  202.     {  
  203.         initialStepLength = atof( argv[6] );  
  204.     }  
  205.     optimizer->SetRelaxationFactor( 0.6 );               //松驰因子  
  206.     optimizer->SetMaximumStepLength( initialStepLength );    //最大步长  
  207.     //最小步长和迭代最大次数, 用来限制优化过程迭代的执行  
  208.     optimizer->SetMinimumStepLength( 0.001 );            //最小步长  
  209.     optimizer->SetNumberOfIterations( 200 );         //最大迭代次数,以防止无限次迭代  
  210.   
  211.     /* 
  212.      *应该注意: 配准过程是一个优化的过程, 优化过程每迭代一次, 
  213.      *就与相似性测度进行一次比较 
  214.      *当相似性测度值达到我们设定的预期值,或者达到设定的迭代上限时 
  215.      *就停止迭代,得到最终结果. 
  216.      */  
  217.   
  218.     //6.实例化一 Command/Observer 对象, 监视配准过程的执行, 并触发配准过程的执行.  
  219.     //实例化一个 Command/Observer 对象, 将其注册为 optimizer 的观察者  
  220.     CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New();  
  221.     optimizer->AddObserver( itk::IterationEvent(), observer );  
  222.     try   
  223.     {   
  224.         registration->StartRegistration();   //触发配准过程的执行  
  225.     }   
  226.     catch( itk::ExceptionObject & err )   
  227.     {   
  228.         std::cerr << "ExceptionObject caught !" << std::endl;   
  229.         std::cerr << err << std::endl;   
  230.         return EXIT_FAILURE;  
  231.     }   
  232.   
  233.     //取得配准执行完毕的最终参数  
  234.     OptimizerType::ParametersType finalParameters =   
  235.                         registration->GetLastTransformParameters();  
  236.     const double finalAngle           = finalParameters[0];  
  237.     const double finalRotationCenterX = finalParameters[1];  
  238.     const double finalRotationCenterY = finalParameters[2];  
  239.     const double finalTranslationX    = finalParameters[3];  
  240.     const double finalTranslationY    = finalParameters[4];  
  241.   
  242.     const unsigned int numberOfIterations = optimizer->GetCurrentIteration();  
  243.     const double bestValue = optimizer->GetValue();  
  244.     const double finalAngleInDegrees = finalAngle * 180.0 / vnl_math::pi;  
  245.   
  246.     std::cout << "Result = " << std::endl;  
  247.     std::cout << " Angle (radians)   = " << finalAngle  << std::endl;  
  248.     std::cout << " Angle (degrees)   = " << finalAngleInDegrees  << std::endl;  
  249.     std::cout << " Center X      = " << finalRotationCenterX  << std::endl;  
  250.     std::cout << " Center Y      = " << finalRotationCenterY  << std::endl;  
  251.     std::cout << " Translation X = " << finalTranslationX  << std::endl;  
  252.     std::cout << " Translation Y = " << finalTranslationY  << std::endl;  
  253.     std::cout << " Iterations    = " << numberOfIterations << std::endl;  
  254.     std::cout << " Metric value  = " << bestValue          << std::endl;  
  255.   
  256.     //7.重采样, 将变换后的浮动图像映射到固定图像空间中,保存配准结果  
  257.     //一般情况,最后一步为: 利用最终的变换结果将浮动图像映射到固定图像空间  
  258.     //可通过 itk::ResampleImageFilter 完成  
  259.     typedef itk::ResampleImageFilter< MovingImageType,   
  260.                         FixedImageType >  ResampleFilterType;  
  261.   
  262.     TransformType::Pointer finalTransform = TransformType::New();  
  263.   
  264.     finalTransform->SetParameters( finalParameters );  
  265.     finalTransform->SetFixedParameters( transform->GetFixedParameters() );  
  266.   
  267.     //设置重采样过滤器的相应参数  
  268.     ResampleFilterType::Pointer resample = ResampleFilterType::New();  
  269.   
  270.     resample->SetTransform( finalTransform );  
  271.     //将浮动图连接至重采样过滤器的输入端  
  272.     resample->SetInput( movingImageReader->GetOutput() );       
  273.   
  274.     resample->SetSize(    fixedImage->GetLargestPossibleRegion().GetSize() );  
  275.     resample->SetOutputOrigin(  fixedImage->GetOrigin() );  
  276.     resample->SetOutputSpacing( fixedImage->GetSpacing() );  
  277.     resample->SetOutputDirection( fixedImage->GetDirection() );  
  278.     //设置默认灰度值,用来 "突出" 显示映射后在浮动图像之外的区域  
  279.     resample->SetDefaultPixelValue( 100 );  
  280.   
  281.     //保存配准后图像  
  282.     typedef itk::ImageFileWriter< FixedImageType >  WriterFixedType;  
  283.     WriterFixedType::Pointer      writer =  WriterFixedType::New();  
  284.     writer->SetFileName( argv[3] );  
  285.     writer->SetInput( resample->GetOutput()   );    //重采样过滤器的输出  
  286.   
  287.     try  
  288.     {  
  289.         writer->Update();  
  290.     }  
  291.     catch( itk::ExceptionObject & excp )  
  292.     {   
  293.         std::cerr << "ExceptionObject while writing the resampled image !" << std::endl;   
  294.         std::cerr << excp << std::endl;   
  295.         return EXIT_FAILURE;  
  296.     }   
  297.   
  298.     //通过 itk::SubtractImageFilter 比较"经过变换的浮动图像"与"固定图像"之间的差异  
  299.     typedef itk::Image< float, Dimension > DifferenceImageType;  
  300.     typedef itk::SubtractImageFilter< FixedImageType,  
  301.                 FixedImageType, DifferenceImageType > DifferenceFilterType;  
  302.     DifferenceFilterType::Pointer difference = DifferenceFilterType::New();  
  303.   
  304.     typedef  unsigned char  OutputPixelType;  
  305.     typedef itk::Image< OutputPixelType, Dimension > OutputImageType;  
  306.   
  307.     //由于两幅图像之间的差异可能对应非常小的亮度值  
  308.     //使用 itk::RescaleIntensityImageFilter 重新调节亮度值,使其更加明显  
  309.     typedef itk::RescaleIntensityImageFilter< DifferenceImageType,   
  310.                                 OutputImageType >   RescalerType;  
  311.     RescalerType::Pointer intensityRescaler = RescalerType::New();  
  312.     intensityRescaler->SetOutputMinimum(   0 );  
  313.     intensityRescaler->SetOutputMaximum( 255 );  
  314.   
  315.     difference->SetInput1( fixedImageReader->GetOutput() );  
  316.     difference->SetInput2( resample->GetOutput() );  
  317.   
  318.     resample->SetDefaultPixelValue( 1 );  
  319.     intensityRescaler->SetInput( difference->GetOutput() );    
  320.   
  321.     typedef itk::ImageFileWriter< OutputImageType >  WriterType;  
  322.     WriterType::Pointer      writer2 =  WriterType::New();  
  323.     writer2->SetInput( intensityRescaler->GetOutput() );  
  324.   
  325.     try  
  326.     {  
  327.         if( argc > 4 )  
  328.         {  
  329.             //保存配准后, 浮动图与固定图之间差异的对比  
  330.             writer2->SetFileName( argv[4] );  
  331.             writer2->Update();  
  332.         }  
  333.   
  334.         //保存配准前, 浮动图与固定图之间差异的对比, 这里仍然需要重采样  
  335.         //因为浮动图与固定图不一定有相同的 origin, size, spacing.   
  336.         //可以过一个恒等变换(Identity Transform)完成  
  337.         TransformType::Pointer identityTransform = TransformType::New();  
  338.         identityTransform->SetIdentity();  
  339.         resample->SetTransform( identityTransform );  
  340.         if( argc > 5 )  
  341.         {  
  342.             writer2->SetFileName( argv[5] );  
  343.             writer2->Update();  
  344.         }  
  345.     }  
  346.     catch( itk::ExceptionObject & excp )  
  347.     {  
  348.         std::cerr << "Error while writing difference images" << std::endl;  
  349.         std::cerr << excp << std::endl;  
  350.         return EXIT_FAILURE;  
  351.     }  
  352.   
  353.     return EXIT_SUCCESS;  
  354. }  

 

 

 

 

除去细节,可以看出,使用 ITK 的配准框架进行医学图像配准主要遵循以下步骤:

1.定义待配准图像类型: 维数, 像素类型 

2.定义配准框架的基本组件: 变换, 优化, 测度, 插值, 配准组件

3.使用配准组件将:变换, 优化, 测度, 插值 四个基本组件连接至一起

4.设置待配准图像及变换区域,有需要时进行适当处理

5.设置各组件的参数,变换、优化、测度,不同方法设置不同

6.实例化一个 Command/Observer 对象, 监视配准过程的执行, 并触发配准过程的执行.

7.重采样, 将变换后的浮动图像映射到固定图像空间中,保存配准结果

 

各个配准组件组成的管道结构如下所示:

pipeline

 

Command/Observer 观察者模式的执行过程如下图所示:

command

 

本例的 CMakeLists.txt 内容为:

CMAKE_MINIMUM_REQUIRED(VERSION 2.4)

PROJECT(ImageRegistration5)

FIND_PACKAGE(ITK)

IF(ITK_FOUND) 
    INCLUDE(${ITK_USE_FILE})

ELSE(ITK_FOUND) 
    MESSAGE(FATAL_ERROR 
            "ITK not found. Please set ITK_DIR.") 
ENDIF(ITK_FOUND)

ADD_EXECUTABLE(ImageRegistration5 ImageRegistration5.cxx )

TARGET_LINK_LIBRARIES(ImageRegistration5 ITKIO ITKNumerics)

 

程序所使用的两幅示例图像,固定图像,浮动图像分别如下:

BrainProtonDensitySliceBorder20 BrainProtonDensitySliceRotated10

程序执行后的过程及结果为:

Debug>ImageRegistration5.exe BrainProtonDensitySliceBorder20.png BrainProtonDensitySliceRotated10.png output.png after.png befor.png 
0   2098.33   [0.0252835, 110.5, 128.5, 0.0912944, -0.0320326] 
1   1766.73   [0.0618533, 110.501, 128.502, 0.177712, -0.0665167] 
2   1380.97   [0.104328, 110.501, 128.5, 0.135417, -0.0669017] 
3   877.601   [0.122006, 110.501, 128.494, 0.0784302, -0.0690638] 
4   647.837   [0.140307, 110.5, 128.487, 0.0219416, -0.0639346] 
5   410.321   [0.162961, 110.497, 128.479, -0.0313332, -0.0501843] 
6   153.093   [0.189839, 110.49, 128.483, -0.0120674, -0.00086769] 
7   115.912   [0.177587, 110.487, 128.494, 0.0427617, 0.0171322] 
8   61.0641   [0.177564, 110.489, 128.488, 0.0095898, 0.00463817] 
9   60.3813   [0.17645, 110.495, 128.489, 0.0217426, -0.0286424] 
10   61.411   [0.177373, 110.491, 128.488, 0.0108792, -0.0103758] 
11   60.4302   [0.177628, 110.488, 128.488, 0.00999985, 0.0108734] 
12   60.5575   [0.177367, 110.49, 128.488, 0.00930347, -0.00186576] 
13   60.3963   [0.177692, 110.489, 128.488, 0.011102, 0.00556995] 
14   60.3989   [0.177429, 110.489, 128.488, 0.00980777, 0.0011698] 
15   60.3822   [0.177691, 110.489, 128.488, 0.0109154, 0.00368068] 
16   60.3942   [0.177487, 110.489, 128.488, 0.0103087, 0.00215544] 
17   60.3781   [0.177817, 110.489, 128.488, 0.00869253, 0.00202342] 
18   60.4265   [0.17767, 110.489, 128.488, 0.00967173, 0.00209358] 
19   60.3867   [0.177458, 110.489, 128.488, 0.0106296, 0.00194103]

//配准完毕后的最终参数 
Result = 
Angle (radians)   = 0.177458 
Angle (degrees)   = 10.1676 
Center X      = 110.489 
Center Y      = 128.488 
Translation X = 0.0106296 
Translation Y = 0.00194103 
Iterations    = 21 
Metric value  = 60.3809

 

配准后的图像,配准前两幅图像的差异,配准后的差异:

output befor after

可以看到,配准后的两幅图像仍然有稍许没有对齐的部分。可以通过更复杂的测度,优化方法进行配准。

ITK 提供了大量不同的几何变换、测度方法、插值算法以及优化算法,主要的不同在于不同组件的参数设置。比较复杂的方法参数设置是件困难的事情,通常需要大量实验才能确定合适的参数,而且不同的实际问题参数设置也不尽相同,比较重要的参数通常需要在其它参数设置好以后再进行微调,才能得到合适的值。ITK 中还提供了使用多分辨策略的配准框架,弹性配准框架等等,现在刚刚开始研究,其它的慢慢研究。


转自zhangcunli的博文

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ITK(Insight Segmentation and Registration Toolkit)是一个强大的开源软件库,用于图像处理、分割和配准。互信息图像配准ITK中一个常用的配准算法之一。 互信息是一种统计量,用于度量两幅图像之间的相似性。它基于信息论的概念,通过将图像中的像素值看作随机变量来衡量图像之间的相关性。互信息越大,说明图像之间的相似性越高。 互信息图像配准在医学影像领域广泛应用。例如,在脑部MRI图像配准中,互信息可以帮助将两幅图像(例如,不同时间点的MRI扫描)对准以实现更精确的比较和分析。在执行互信息配准时,ITK提供了一些用于计算互信息的方法,例如直方图和正态分布。 ITK的互信息图像配准算法主要包括以下步骤: 1. 加载待配准的图像数据。 2. 预处理图像数据,例如裁剪、平滑和重采样。 3. 定义互信息度量方法,选择合适的参数。 4. 计算图像之间的互信息,可以利用直方图或概率密度函数来实现。 5. 通过最大化互信息来优化配准参数,例如调整图像的平移、旋转和缩放。 6. 应用优化后的参数,将图像进行配准,使其尽可能相似。 7. 检查配准结果是否满足要求,如需要可以进行后处理。 ITK的互信息图像配准提供了一个灵活且可扩展的框架使用户可以根据具体需求选择适合的参数和方法。同时,ITK还提供了其他类型的配准算法,如基于特征的配准和弹性配准,以便用户根据具体应用场景选择合适的方法。 总之,ITK互信息图像配准是一种有效的配准方法,在医学影像处理中具有广泛的应用和研究价值。它能够提供准确的图像对齐结果,从而帮助医生和研究人员更好地分析和理解图像数据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值