VTK Python MPR 三维重建(一) 多层面重建 四视图

目录

概述:

MPR,全称是multi-planar reformation / reconstruction,是常用的医学图像后处理技术

优化后的视频: 

 vtkImageReslice

参考资料


概述:

本文实现了 C++ Qt版本的 四视图,MPR 和三维重建;

同时有Python 版本;

除了MPR之外,在CT重建后处理中还有很多别的常用方法,包括

  • 多层面重建(MPR)
  • 最大密度投影(MIP)
  • 最小密度投影(MinIP)
  • 表面阴影遮盖(SSD)
  • 容积漫游技术(VRT)
  • 曲面重建(CPR)
  • 虚拟内镜技术(VE)

后面有时间我会慢慢补;

MPR,全称是multi-planar reformation / reconstruction,是常用的医学图像后处理技术

1、多平面重建(MPR)是将扫描范围内所有的轴位图像叠加起来再对某些标线标定的重组线所指定的组织进行冠状、矢状位、任意角度斜位图像重组。
优点:
(1)能任意产生新的断层图像,而无需重复扫描。
(2)原图像的密度值被忠实保持到了结果图像上。
(3)曲面重组能在一幅图像里展开显示弯曲物体的全长。
缺点:

(1)难以表达复杂的空间结构
(2)曲面重组易造成假阳性。

 MPR VTK 三维重建(二)multi-planner reformation 定位线 十字线_恋恋西风的博客-CSDN博客

优化后的视频: 

 

python-mpr-stone

 vtkImageReslice

vtkImageReslice类可以从体数据内的一点沿着不同的方向切出一个平面图像;
vtkImageReslice是图像几何过滤器的瑞士军刀:它可以以合理高效的任意组合排列、旋转、翻转、缩放、重采样、变形和填充图像数据。置换、重采样和填充等简单操作的效率与专用vtkImagePermute、vtkImageResample和vtkImagePad过滤器类似。 vtkimanageslice非常适合执行以下任务:
1) 对图像进行简单的旋转、缩放和平移。通常,最好先使用vtkImageChangeInformation使图像居中,这样缩放和旋转就发生在图像的中心而不是左下角。
2) 通过SetInformationInput()方法对一个数据集进行重采样,以匹配第二个数据集的体素采样,例如为了比较两个图像或合并两个图像。如果两幅图像不在同一坐标空间中,可以通过SetResliceTransform()方法同时应用线性或非线性变换。
3) 从图像体中提取切片。使用vtkImageReslice可以从体数据中获取到指定的正交、斜切方向的上的切面图像;最方便的方法是使用SetResliceAxesDirectionCosines()指定切片的方向。方向余弦表示输出体积的x、y和z轴。SetOutputDimensionality(2)方法用于指定要输出切片而不是Volume的对象。SetResliceAxesOrigin()方法用于提供切片将通过的(x,y,z)点。可以同时使用ResliceAxes和ResliceTransform,以便从已应用转换的Volume中提取切片。
3)内容是比较常用的内容,可以提取平行于XY平面、YZ平面、XZ平面的切片,还可以提取斜切切片;
 

使用 vtkImageReslice 重建 callback 用来处理鼠标,切换图层;

初始化三个 Actor

void initImageActor(double* Matrix,double * center, vtkSmartPointer<vtkImageCast>pImageCast,
	vtkSmartPointer<vtkImageReslice> imageReslice,vtkSmartPointer<vtkImageActor> actor)
{
	vtkMatrix4x4 *AxialResliceMatrix = vtkMatrix4x4::New();
	AxialResliceMatrix->DeepCopy(Matrix);

	AxialResliceMatrix->SetElement(0, 3, center[0]);
	AxialResliceMatrix->SetElement(1, 3, center[1]);
	AxialResliceMatrix->SetElement(2, 3, center[2]);

	//设置体数据来源
	imageReslice->SetInputConnection(pImageCast->GetOutputPort());
	//设置输出是一个切片,而不是一个卷
	imageReslice->SetOutputDimensionality(2);
	//pImageResliceX->SetResliceAxesDirectionCosines(sagittalX, sagittalY, sagittalZ);
	//设置vtkImageReslice的切面坐标系矩阵
	imageReslice->SetResliceAxes(AxialResliceMatrix);
	//pImageResliceX->SetResliceAxesOrigin(center);
	//设置切面算法的插值方式为线性插值
	imageReslice->SetInterpolationModeToLinear();
	imageReslice->Update();
	//pImageMapToColorsX->SetLookupTable(pWindowLevelLookupTable);
	//pImageMapToColorsX->SetInputConnection(pImageResliceX->GetOutputPort());
	actor->SetInputData(imageReslice->GetOutput());
	actor->SetPosition(0, 0, 0);
	actor->Update();
}

主函数:

先通过vtkMetaImageReader读取一副三维图像,获取图像范围、原点和像素间隔,由这三个参数可以计算图像的中心位置。
接下来定义了切面的变换矩阵axialElements,该矩阵的前三列分别表示X、Y和Z方向矢量,第四列为切面坐标系原点。通过修改切面坐标系原点,可以得到不同位置的切面图像。
然后将读取的图像作为vtkImageReslice的输入,通过函数SetResliceAxes()设置变换矩阵resliceAxis
 

int main()
{
	vtkSmartPointer<vtkImageReslice> pImageResliceX = vtkSmartPointer<vtkImageReslice>::New();
	vtkSmartPointer<vtkImageReslice> pImageResliceY = vtkSmartPointer<vtkImageReslice>::New();
	vtkSmartPointer<vtkImageReslice> pImageResliceZ = vtkSmartPointer<vtkImageReslice>::New();

	vtkSmartPointer<vtkXMLImageDataReader> pXMLImageDataReader = vtkSmartPointer<vtkXMLImageDataReader>::New();
	vtkSmartPointer<vtkImageCast> pImageCast = vtkSmartPointer<vtkImageCast>::New();


	vtkSmartPointer<vtkImageActor> pImageActorX = vtkSmartPointer<vtkImageActor>::New();
	vtkSmartPointer<vtkImageActor> pImageActorY = vtkSmartPointer<vtkImageActor>::New();
	vtkSmartPointer<vtkImageActor> pImageActorZ = vtkSmartPointer<vtkImageActor>::New();

	vtkSmartPointer<vtkRenderer> pRendererX = vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderer> pRendererY = vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderer> pRendererZ = vtkSmartPointer<vtkRenderer>::New();
	 
	vtkSmartPointer<vtkRenderer> pRenderer = vtkSmartPointer<vtkRenderer>::New();
	vtkSmartPointer<vtkRenderWindow> pRenderWindow = vtkSmartPointer<vtkRenderWindow>::New();

	//vtkSmartPointer<vtkMetaImageReader> reader =
	//	vtkSmartPointer<vtkMetaImageReader>::New();
	//reader->SetFileName("D:/datasource/brain.mhd");
	//reader->Update();
	vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetDirectoryName("D:/datasource/fei/ScalarVolume_13");
	reader->Update();

	int extent[6];
	double spacing[3];
	double origin[3];

	reader->GetOutput()->GetExtent(extent);
	reader->GetOutput()->GetSpacing(spacing);
	reader->GetOutput()->GetOrigin(origin);

	// 计算中心位置。
	double center[3];
	center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
	center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
	center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);
   
	//轴状面
	double Axial[16] = {
			1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 1, 0,
			0, 0, 0, 1 };
	//冠状面
	double Coronal[16] = {
			1, 0, 0, 0,
			0, 0, -1, 0,
			0, 1, 0, 0,
			0, 0, 0, 1 };
	//矢状面
	double Sagittal[16] = {
			0, 0, 1, 0,
			1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 0, 1 };

 
	pImageCast->SetInputConnection(reader->GetOutputPort());
	pImageCast->SetOutputScalarTypeToChar();
	pImageCast->ClampOverflowOn();
	pImageCast->Update();
	//pImageCast->SetUpdateExtentToWholeExtent();

	//x
	initImageActor(Axial, center, pImageCast, pImageResliceX, pImageActorX);
 
	//y
	initImageActor(Coronal, center, pImageCast, pImageResliceY, pImageActorY);
  
	//z
	initImageActor(Sagittal, center, pImageCast, pImageResliceZ, pImageActorZ);
 
	 float fOpac = 0.5;


	pRendererX->AddActor(pImageActorX);
	pRendererY->AddActor(pImageActorY);
	pRendererZ->AddActor(pImageActorZ);

 
	//pRenderer->SetBackground(1, 1, 1);
	pRendererX->SetBackground(0, 0, 0);
	pRendererY->SetBackground(0, 0, 0);
	pRendererZ->SetBackground(0, 0, 0);

	/*
	    #  renderer 0: BOTTOM LEFT
		#  renderer 1: BOTTOM RIGHT
		#  renderer 2: TOP LEFT
		#  renderer 3: TOP RIGHT
	*/
	double ltView[4] = { 0, 0, 0.5, 0.5 }; 
	double rtView[4] = { 0.5, 0, 1, 0.5 }; 
	double lbView[4] = { 0, 0.5, 0.5, 1 }; 
	double rbView[4] = { 0.5, 0.5, 1, 1 }; 

	//pRenderer->SetViewport(0, 0, 0.6, 1);
	//pRendererX->SetViewport(0.6, 0.66, 1, 1);
	//pRendererY->SetViewport(0.6, 0.33, 1, 0.66);
	//pRendererZ->SetViewport(0.6, 0, 1, 0.33);

	pRenderer->SetViewport(rtView);
	pRendererX->SetViewport(lbView);
	pRendererY->SetViewport(rbView);
	pRendererZ->SetViewport(ltView);

	pRenderWindow->AddRenderer(pRendererX);
	pRenderWindow->AddRenderer(pRendererY);
	pRenderWindow->AddRenderer(pRendererZ);
	pRenderWindow->AddRenderer(pRenderer);

	vtkSmartPointer<vtkRenderWindowInteractor> pRenderWindowInteractor =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();

	pRenderWindow->SetSize(600, 600);
  
	// add observer;
	vtkSmartPointer<vtkInteractorStyleImage> imagestyle =
		vtkSmartPointer<vtkInteractorStyleImage>::New();

	pRenderWindowInteractor->SetInteractorStyle(imagestyle);
	pRenderWindowInteractor->SetRenderWindow(pRenderWindow);
	pRenderWindowInteractor->Initialize();

	vtkSmartPointer<vtkImageInteractionCallback> callback =
		vtkSmartPointer<vtkImageInteractionCallback>::New();
	//callback->SetImageReslice(reslice);
	callback->ImageReslicex = pImageResliceX;
	callback->ImageReslicey = pImageResliceY;
	callback->ImageReslicez = pImageResliceZ;
	callback->SetInteractor(pRenderWindowInteractor);
	//callback->SetImageMapToColors(colorMap);

	imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback);
	imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback);
	imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback);

	pRenderWindow->Render();
   
	pRenderWindowInteractor->Initialize();
	pRenderWindowInteractor->Start();
 
	return 0;
}

参考资料

1.vtkImageReslice Class ReferenceMPR

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

恋恋西风

up up up

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值