ITK配准:基于手动设置地标的刚性配准

实现基于手动设置地标的刚性配准。所谓的刚性配准是指变换前后图像中任意两点的距离不变。不考虑坐标轴尺度缩放时,刚性变换仅存在坐标轴的平移和旋转。

1、生成图像

参考图像:图像尺寸100X100,在以坐标点(10,10)和(20,20)所包围的区域内灰度值为255,其余区域灰度值为0;

待配准图像:图像尺寸100X100,在以坐标点(50,50)和(60,60)所包围区域内灰度值值为100,其余区域灰度值为0;

2、定义基于地标集合的变换类型,相当于上一篇文章的DeformationFieldSourceType。

并将该类型进行实例化,该对象与上一篇中的deformationFieldSource相对应。

3、创建参考图和待配准图的地标集

其中涉及到地标容器和地标点,如下所示:

LandmarkContainerType fixedLandmarks;
LandmarkContainerType movingLandmarks;

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();
}


配准结果如下图所示:


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值