VTK学习日志:基于VTK9.3.0+Visual Studio c++实现DICOM影像MPR多平面重建+V R体绘制4个视图展示功能的实现(二)

目录

 一、体绘制4视图展示     

二、基于VTK的MPR+VR实现的简单项目创建

三、核心代码展示


一、体绘制4视图展示     

        前段时间对VTK9.3.0进行了编译,开发了MPR+VR实现的demo,显示效果不是很理想,正好趁着周末有时间,再度对之前的程序进行优化和完善,先展示下效果:

VTK实现MPR+VR四视图

二、基于VTK的MPR+VR实现的简单项目创建

再次讲解下基于VTK的MPR+VR实现的简单项目创建过程:

1、在vtk官网https://vtk.org/download/下载vtk库,我下载的是9.3.0版本,如下:

2、下载后解压,用Cmake进行编译,具体编译过程我就不详细说明了.

3、我选择的是Visual Studio 2022 64位开发工具,Cmake编译完成后就生成了VTK.sln解决方案:

编译生成即可,编译过程遇到的问题在我其他几篇博客里已经做了记录,需要可以查看。

4、右键VTK中的“INSTALL”生成VTK的库目录和包含目录,如下:

5、右键VTK项目解决方案,选择 添加新项目,再选择 c++控制台项目即可

6、在新添加的MPR demo项目中添加包含目录、库目录和依赖项,如下:

到此我们已经创建了一个基于VTK9.3.0+Visual Studio的C++控制台项目,在生成的cpp源文件中就可以编写具体的DICOM影像MPR多平面重建+V R体绘制的代码了。

三、核心代码展示

class vtkImageInteractionCallback : public vtkCommand
{
public:
	static vtkImageInteractionCallback* New()
	{
		return new vtkImageInteractionCallback();
	}
 
	vtkImageInteractionCallback()
		: ImageReslice(nullptr), Slicing(0) {}
 
	void SetImageReslice(vtkImageReslice* reslice) { this->ImageReslice = reslice; }
 
	virtual void Execute(vtkObject* caller, unsigned long eventId, void* callData) override
	{
		vtkRenderWindowInteractor* interactor = vtkRenderWindowInteractor::SafeDownCast(caller);
		if (!interactor) return;
 
		int x, y;
		interactor->GetEventPosition(x, y);
 
		if (eventId == vtkCommand::MouseMoveEvent)
		{
			if (this->Slicing)
			{
				this->ProcessSlicing(interactor, x, y);
			}
		}
		else if (eventId == vtkCommand::LeftButtonPressEvent)
		{
			this->Slicing = 1;
		}
		else if (eventId == vtkCommand::LeftButtonReleaseEvent)
		{
			this->Slicing = 0;
		}
	}
 
protected:
	void ProcessSlicing(vtkRenderWindowInteractor* interactor, int x, int y)
	{
		// 获取当前切片的中心位置
		double sliceCenter[3];
		this->ImageReslice->GetOutput()->GetCenter(sliceCenter);
 
		// 获取鼠标移动的增量
		int lastX = interactor->GetLastEventPosition()[0];
		int lastY = interactor->GetLastEventPosition()[1];
		int deltaY = y - lastY;
 
		// 根据移动的方向和增量调整切片位置
		double newSlicePosition = sliceCenter[2] + deltaY * 0.1; // 比例因子可以调整
		sliceCenter[2] = newSlicePosition;
 
		// 设置新的切片位置
		this->ImageReslice->SetResliceAxesOrigin(sliceCenter);
		interactor->Render(); // 渲染更新后的图像
	}
 
	vtkImageReslice* ImageReslice;
	int Slicing;
};
 
void initImageActor(double* Matrix, double* center, vtkSmartPointer<vtkImageCast> pImageCast,
	vtkSmartPointer<vtkImageReslice> imageReslice, vtkSmartPointer<vtkImageActor> actor)
{
	vtkSmartPointer<vtkMatrix4x4> AxialResliceMatrix = vtkSmartPointer<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);
	imageReslice->SetResliceAxes(AxialResliceMatrix);
	imageReslice->SetInterpolationModeToLinear();
	imageReslice->Update();
 
	actor->GetMapper()->SetInputConnection(imageReslice->GetOutputPort());
	actor->SetPosition(0, 0, 0);
}
 
void addImageInteractionCallback(vtkRenderWindowInteractor* interactor, vtkImageReslice* imageReslice)
{
	vtkSmartPointer<vtkImageInteractionCallback> callback = vtkSmartPointer<vtkImageInteractionCallback>::New();
	callback->SetImageReslice(imageReslice);
 
	vtkSmartPointer<vtkInteractorStyleImage> imagestyle = vtkSmartPointer<vtkInteractorStyleImage>::New();
	interactor->SetInteractorStyle(imagestyle);
 
	imagestyle->AddObserver(vtkCommand::MouseMoveEvent, callback);
	imagestyle->AddObserver(vtkCommand::LeftButtonPressEvent, callback);
	imagestyle->AddObserver(vtkCommand::LeftButtonReleaseEvent, callback);
}
 
int main()
{
	vtkSmartPointer<vtkImageReslice> pImageResliceX = vtkSmartPointer<vtkImageReslice>::New();
	vtkSmartPointer<vtkImageReslice> pImageResliceY = vtkSmartPointer<vtkImageReslice>::New();
	vtkSmartPointer<vtkImageReslice> pImageResliceZ = vtkSmartPointer<vtkImageReslice>::New();
 
	vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New();
	reader->SetDirectoryName("D:\\image\\images\\011\\CT\\20200115\\67728\\1.3.46.670589.33.1.63714685715192329600004.5577472948825480582");
	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 };
 
	vtkSmartPointer<vtkImageCast> pImageCast = vtkSmartPointer<vtkImageCast>::New();
	pImageCast->SetInputConnection(reader->GetOutputPort());
	pImageCast->SetOutputScalarTypeToUnsignedChar();
	pImageCast->ClampOverflowOn();
	pImageCast->Update();
 
	vtkSmartPointer<vtkImageActor> pImageActorX = vtkSmartPointer<vtkImageActor>::New();
	vtkSmartPointer<vtkImageActor> pImageActorY = vtkSmartPointer<vtkImageActor>::New();
	vtkSmartPointer<vtkImageActor> pImageActorZ = vtkSmartPointer<vtkImageActor>::New();
 
	initImageActor(Axial, center, pImageCast, pImageResliceX, pImageActorX);
	initImageActor(Coronal, center, pImageCast, pImageResliceY, pImageActorY);
	initImageActor(Sagittal, center, pImageCast, pImageResliceZ, pImageActorZ);
 
	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();
 
	pRendererX->AddActor(pImageActorX);
	pRendererY->AddActor(pImageActorY);
	pRendererZ->AddActor(pImageActorZ);
 
	// 设置渲染器背景颜色
	pRendererX->SetBackground(0, 0, 0);
	pRendererY->SetBackground(0, 0, 0);
	pRendererZ->SetBackground(0, 0, 0);
	pRenderer->SetBackground(0.1, 0.2, 0.4);
 
	// 为每个渲染器设置视口
	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(rtView);
	pRendererX->SetViewport(lbView);
	pRendererY->SetViewport(rbView);
	pRendererZ->SetViewport(ltView);
 
	pRenderWindow->AddRenderer(pRendererX);
	pRenderWindow->AddRenderer(pRendererY);
	pRenderWindow->AddRenderer(pRendererZ);
	pRenderWindow->AddRenderer(pRenderer);
 
	// 设置体积渲染
	vtkSmartPointer<vtkPiecewiseFunction> volumeScalarOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
	volumeScalarOpacity->AddPoint(0, 0.0);
	volumeScalarOpacity->AddPoint(80, 0.0);
	volumeScalarOpacity->AddPoint(400, 1.0);
 
	vtkSmartPointer<vtkColorTransferFunction> volumeColor = vtkSmartPointer<vtkColorTransferFunction>::New();
	volumeColor->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
	volumeColor->AddRGBPoint(80.0, 1.0, 1.0, 1.0);
	volumeColor->AddRGBPoint(400.0, 1.0, 1.0, 1.0);
 
	vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
	volumeProperty->SetColor(volumeColor);
	volumeProperty->SetScalarOpacity(volumeScalarOpacity);
	volumeProperty->ShadeOn();
	volumeProperty->SetInterpolationTypeToLinear();
 
	vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
	volumeMapper->SetInputConnection(reader->GetOutputPort());
 
	vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New();
	volume->SetMapper(volumeMapper);
	volume->SetProperty(volumeProperty);
 
	pRenderer->AddVolume(volume);
 
	vtkSmartPointer<vtkRenderWindowInteractor> pRenderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	pRenderWindow->SetInteractor(pRenderWindowInteractor);
 
	pRenderWindow->SetSize(800, 800);
 
	// 为横断面视窗添加交互回调
	vtkSmartPointer<vtkRenderWindowInteractor> interactorX = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactorX->SetRenderWindow(pRenderWindow);
	addImageInteractionCallback(interactorX, pImageResliceX);
 
	vtkSmartPointer<vtkRenderWindowInteractor> interactorY = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactorY->SetRenderWindow(pRenderWindow);
	addImageInteractionCallback(interactorY, pImageResliceY);
 
	vtkSmartPointer<vtkRenderWindowInteractor> interactorZ = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactorZ->SetRenderWindow(pRenderWindow);
	addImageInteractionCallback(interactorZ, pImageResliceZ);
 
	// 为体绘制窗口添加交互回调
	vtkSmartPointer<vtkRenderWindowInteractor> interactorVolume = vtkSmartPointer<vtkRenderWindowInteractor>::New();
	interactorVolume->SetRenderWindow(pRenderWindow);
 
	vtkSmartPointer<vtkInteractorStyleTrackballCamera> volumeStyle = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
	interactorVolume->SetInteractorStyle(volumeStyle);
 
	pRenderWindow->Render();
	pRenderWindowInteractor->Initialize();
	pRenderWindowInteractor->Start();
 
	return 0;
}

上一篇:基于VTK9.3.0+Visual Studio2017 c++实现DICOM影像MPR多平面重建+V R体绘制4个视图展示功能的实现_vtk实现四视图渲染-CSDN博客

要使用Python和VTK实现CT医学影像DICOM文件的绘制和面绘制三维重建,你可以参考以下源码: ``` python import vtk # 创建一个渲染窗口并设置交互方式 renWin = vtk.vtkRenderWindow() iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) # 读取DICOM文件 reader = vtk.vtkDICOMImageReader() reader.SetDirectoryName("path/to/dicom/files") reader.Update() # 创建绘制素数据集 volumeMapper = vtk.vtkFixedPointVolumeRayCastMapper() volumeMapper.SetInputConnection(reader.GetOutputPort()) # 设置绘制的颜色和透明度传输函数 volumeProperty = vtk.vtkVolumeProperty() volumeProperty.ShadeOn() volumeProperty.SetColor(vtk.vtkColorTransferFunction()) volumeProperty.SetScalarOpacity(vtk.vtkPiecewiseFunction()) # 创建绘制的可视化对象 volume = vtk.vtkVolume() volume.SetMapper(volumeMapper) volume.SetProperty(volumeProperty) # 创建面绘制的等值面数据集 contourFilter = vtk.vtkMarchingCubes() contourFilter.SetInputConnection(reader.GetOutputPort()) contourFilter.SetValue(0, thresholdValue) # 设置阈值,提取等值面 # 创建面绘制的Mapper和Actor contourMapper = vtk.vtkPolyDataMapper() contourMapper.SetInputConnection(contourFilter.GetOutputPort()) contourActor = vtk.vtkActor() contourActor.SetMapper(contourMapper) # 创建渲染器和渲染窗口 renderer = vtk.vtkRenderer() renWin.AddRenderer(renderer) renderer.AddActor(volume) renderer.AddActor(contourActor) renderer.SetBackground(0, 0, 0) # 设置背景颜色为黑色 # 设置相机视角 camera = renderer.GetActiveCamera() camera.SetPosition(0, 0, -1) # 设置相机位置 camera.SetFocalPoint(0, 0, 0) # 设置焦点 camera.SetViewUp(0, -1, 0) # 设置视角 # 激活渲染器和交互操作 renderer.ResetCamera() renWin.Render() iren.Start() ``` 请注意,上述代码只提供了一个基本的框架,实际使用时需要根据具需求进行调整。同时,你需要将代码中的"path/to/dicom/files"替换为实际的DICOM文件路径,并根据需要设置绘制和面绘制的参数。 希望以上内容对你有所帮助!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

猿享天开

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值