实现基于手动设置地标的刚性配准。所谓的刚性配准是指变换前后图像中任意两点的距离不变。不考虑坐标轴尺度缩放时,刚性变换仅存在坐标轴的平移和旋转。
1、生成图像
参考图像:图像尺寸100X100,在以坐标点(10,10)和(20,20)所包围的区域内灰度值为255,其余区域灰度值为0;
待配准图像:图像尺寸100X100,在以坐标点(50,50)和(60,60)所包围区域内灰度值值为100,其余区域灰度值为0;
2、定义基于地标集合的变换类型,相当于上一篇文章的DeformationFieldSourceType。
并将该类型进行实例化,该对象与上一篇中的deformationFieldSource相对应。
3、创建参考图和待配准图的地标集
其中涉及到地标容器和地标点,如下所示:
LandmarkPointType fixedPoint;
LandmarkPointType movingPoint;
通过往容器中添加地标点以收集地标点集。
fixedLandmarks.push_back( fixedPoint );
movingLandmarks.push_back( movingPoint );
4、设置基于地标点的变换的地标集合。使得变换场与参考图和待配准图的地标点进行关联!
landmarkBasedTransformInitializer->SetFixedLandmarks( fixedLandmarks );
landmarkBasedTransformInitializer->SetMovingLandmarks( movingLandmarks );
5、定义刚性变换类型
Rigid2DTransformType::Pointer transform = Rigid2DTransformType::New();
transform->SetIdentity();
并将基于地标点的变换对象设置为刚性变换
landmarkBasedTransformInitializer->SetTransform(transform);
6、定义ResampleFilterType,相当于上一篇文章中的WarpImageFilterType,将其与变换对象进行关联
设置该滤波器的输入为待配准图像
resampleFilter->SetInput( movingImage );
设置其变换为刚性变换
resampleFilter->SetTransform( transform );//
7、将配准结果进行输出
writer->SetInput ( resampleFilter->GetOutput() );
代码如下:
#include "itkImageFileWriter.h" #include "itkImage.h" #include "itkVector.h" #include "itkResampleImageFilter.h" #include "itkLandmarkBasedTransformInitializer.h" #include "itkRigid2DTransform.h" const unsigned int Dimension = 2; typedef unsigned char PixelType; typedef itk::Image< PixelType, Dimension > ImageType; static void CreateFixedImage(ImageType::Pointer image); static void CreateMovingImage(ImageType::Pointer image); int main(int argc, char * argv[]) { typedef float VectorComponentType; typedef itk::Vector< VectorComponentType, Dimension > VectorType; typedef itk::Image< VectorType, Dimension > DeformationFieldType; //生成参考图和待配准图 ImageType::Pointer fixedImage = ImageType::New(); CreateFixedImage(fixedImage); ImageType::Pointer movingImage = ImageType::New(); CreateMovingImage(movingImage); //定义刚性变换类型 typedef itk::Rigid2DTransform< double > Rigid2DTransformType; //基于地标集合的变换类型。相当于上一篇文章的DeformationFieldSourceType typedef itk::LandmarkBasedTransformInitializer< Rigid2DTransformType, ImageType, ImageType > LandmarkBasedTransformInitializerType; //进行实例化,该对象与上一篇中的deformationFieldSource相对应 LandmarkBasedTransformInitializerType::Pointer landmarkBasedTransformInitializer = LandmarkBasedTransformInitializerType::New(); // Create source and target landmarks. typedef LandmarkBasedTransformInitializerType::LandmarkPointContainer LandmarkContainerType; typedef LandmarkBasedTransformInitializerType::LandmarkPointType LandmarkPointType; LandmarkContainerType fixedLandmarks; LandmarkContainerType movingLandmarks; LandmarkPointType fixedPoint; LandmarkPointType movingPoint; //添加参考图的地标点(10,10);待配准图(50,50) fixedPoint[0] = 10; fixedPoint[1] = 10; movingPoint[0] = 50; movingPoint[1] = 50; fixedLandmarks.push_back( fixedPoint ); movingLandmarks.push_back( movingPoint ); //添加第二个地标点:参考图中的(10,20)和待配准图中的(50,60) fixedPoint[0] = 10; fixedPoint[1] = 20; movingPoint[0] = 50; movingPoint[1] = 60; fixedLandmarks.push_back( fixedPoint ); movingLandmarks.push_back( movingPoint ); //添加第3个地标点 fixedPoint[0] = 20; fixedPoint[1] = 10; movingPoint[0] = 60; movingPoint[1] = 50; fixedLandmarks.push_back( fixedPoint ); movingLandmarks.push_back( movingPoint ); //添加第4个地标点 fixedPoint[0] = 20; fixedPoint[1] = 20; movingPoint[0] = 60; movingPoint[1] = 60; fixedLandmarks.push_back( fixedPoint ); movingLandmarks.push_back( movingPoint ); //设置基于地标点的变换的地标集合。使得变换场与参考图和待配准图的地标点进行关联! landmarkBasedTransformInitializer->SetFixedLandmarks( fixedLandmarks ); landmarkBasedTransformInitializer->SetMovingLandmarks( movingLandmarks ); //将已经初始化的基于地标点的变换设置为2D的刚性变换! Rigid2DTransformType::Pointer transform = Rigid2DTransformType::New(); transform->SetIdentity(); landmarkBasedTransformInitializer->SetTransform(transform); landmarkBasedTransformInitializer->InitializeTransform(); //相当于上一篇文章中的WarpImageFilterType,将其与变换对象进行关联 typedef itk::ResampleImageFilter<ImageType, ImageType, double > ResampleFilterType; ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New(); resampleFilter->SetInput( movingImage ); resampleFilter->SetTransform( transform );// resampleFilter->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() ); resampleFilter->SetOutputOrigin( fixedImage->GetOrigin() ); resampleFilter->SetOutputSpacing( fixedImage->GetSpacing() ); resampleFilter->SetOutputDirection( fixedImage->GetDirection() ); resampleFilter->SetDefaultPixelValue( 200 ); resampleFilter->GetOutput(); // Write the output typedef itk::ImageFileWriter< ImageType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetInput ( resampleFilter->GetOutput() ); writer->SetFileName( "output.png" ); writer->Update(); return EXIT_SUCCESS; } void CreateFixedImage(ImageType::Pointer image) { // Create a black image with a white square ImageType::IndexType start; start.Fill(0);// ImageType::SizeType size; size.Fill(100); ImageType::RegionType region; region.SetSize(size); region.SetIndex(start); image->SetRegions(region); image->Allocate(); image->FillBuffer(0); itk::ImageRegionIterator<ImageType> imageIterator(image,region); while(!imageIterator.IsAtEnd()) { if(imageIterator.GetIndex()[0] > 10 && imageIterator.GetIndex()[0] < 20 && imageIterator.GetIndex()[1] > 10 && imageIterator.GetIndex()[1] < 20) { imageIterator.Set(255); } ++imageIterator; } // Write the deformation field typedef itk::ImageFileWriter< ImageType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetInput ( image ); writer->SetFileName( "fixed.png" ); writer->Update(); } void CreateMovingImage(ImageType::Pointer image) { // Create a black image with a white square ImageType::IndexType start; start.Fill(0); ImageType::SizeType size; size.Fill(100); ImageType::RegionType region; region.SetSize(size); region.SetIndex(start); image->SetRegions(region); image->Allocate(); image->FillBuffer(0); itk::ImageRegionIterator<ImageType> imageIterator(image,region); while(!imageIterator.IsAtEnd()) { if(imageIterator.GetIndex()[0] > 50 && imageIterator.GetIndex()[0] < 60 && imageIterator.GetIndex()[1] > 50 && imageIterator.GetIndex()[1] < 60) { imageIterator.Set(100); } ++imageIterator; } // Write the deformation field typedef itk::ImageFileWriter< ImageType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetInput ( image ); writer->SetFileName( "moving.png" ); writer->Update(); }