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

news2024/11/23 15:09:30

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1879946.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HTTPS是什么?原理是什么?用公钥加密为什么不能用公钥解密?

HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;是HTTP的安全版本&#xff0c;它通过在HTTP协议之上加入SSL/TLS协议来实现数据加密传输&#xff0c;确保数据在客户端和服务器之间的传输过程中不会被窃取或篡改。 HTTPS 的工作原理 客户端发起HTTPS请求&…

第三天:LINK3D核心原理讲解【第1部分】

第三天:LINK3D核心原理讲解 LINK3D学习笔记 目标 了解LINK3D velodyne64线激光雷达LINK3D质心点提取效果: 分布在车道与墙体的交界处。 课程内容 LINK3D论文精讲LINK3D聚合关键点提取代码讲解LINK3D描述子匹配代码讲解除了ALOAM的线特征、面特征,还有其他点云特征吗,是…

【项目】论坛系统项目自动化测试

论坛系统项目自动化测试 前述一、脑图二、代码编写1.公共类InitAndEnd1.登录页面测试ForumLoginTest正常登录&#xff1a;异常登录&#xff1a; 3.注册页面测试ForumRegisterTest注册成功&#xff1a;注册失败&#xff1a; 4论坛列表页面测试ForumListTest登录状态下&#xff1…

<电力行业> - 《第10课:变电》

1 变电 变电环节&#xff0c;顾名思义就是改变电压的环节&#xff0c;主要是在变电站和变电所完成的。变电站和变电所主要区别在于&#xff1a;变电站比变电所更大。 发电厂的变压器和配电变压器也属于“变电”&#xff0c;但我们在说电网环节时&#xff0c;变电特指电网公司…

python基础:设置代码格式

随着编写的程序越来越长&#xff0c;有必要了解一些代码格式的约定&#xff0c;让你的代码尽可以能易于阅读。 python代码编写规范为PEP8&#xff0c;有兴趣的朋友可以下载观看&#xff0c;这里仅作简要说明。 1、缩进 PEP8建议每级缩进都使用4个空格。多数情况下编程语言的…

无人机智能追踪反制系统技术详解

随着无人机技术的飞速发展&#xff0c;无人机在各个领域的应用越来越广泛。然而&#xff0c;无人机的无序飞行和非法使用也带来了一系列安全隐患和威胁。因此&#xff0c;无人机智能追踪反制系统应运而生&#xff0c;成为维护公共安全和防止无人机滥用的重要工具。本文将详细介…

深度学习评价指标:Precision, Recall, F1-score, mIOU, 和 mDice

在深度学习和机器学习中&#xff0c;评价模型性能是至关重要的一环。本文将详细讲解一些常见的评价指标&#xff0c;包括精确率&#xff08;Precision&#xff09;、召回率&#xff08;Recall&#xff09;、F1-score、平均交并比&#xff08;mIOU&#xff09;和平均Dice系数&am…

ConcurrentHashMap是如何保证线程安全的-put方法简要分析

简介 ConcurrentHashMap 是 Java 中并发编程中常用的线程安全的哈希表&#xff08;HashMap&#xff09;实现。它具有以下几个显著的特点和优点&#xff0c;适合在特定的并发场景中使用&#xff1a; 线程安全性&#xff1a; ConcurrentHashMap 提供了并发访问的线程安全保证&am…

AWT的菜单组件

AWT的菜单组件 前言一、菜单组件的介绍常见的菜单相关组件常见菜单相关组件集成体系图菜单相关组件使用小要点 二、AWT菜单组件的代码示例示例一示例二实现思路 前言 推荐一个网站给想要了解或者学习人工智能知识的读者&#xff0c;这个网站里内容讲解通俗易懂且风趣幽默&…

高考结束,踏上西北的美食之旅

高考的帷幕落下&#xff0c;暑期的阳光洒来&#xff0c;是时候放下书本&#xff0c;背上行囊&#xff0c;踏上一场充满期待的西北之旅。而在甘肃这片广袤的土地上&#xff0c;除了壮丽的自然风光&#xff0c;还有众多令人垂涎欲滴的美食等待着您的品尝。当您踏入甘肃&#xff0…

创建一个vue3+vite+ts项目

目录 创建项目 ​编辑 下载jsx 插件 在根目录在新建.env vue.config.js tsconfig.json tsconfig.node.json 下载ui组件库和路由&#xff08;组件库根据自己的项目需要选择&#xff09; 在根目录下新建views/index.tsx 在根目录下新建router/index.ts 修改App.vue 创建…

【C++】C++ 网店销售库存管理系统(源码+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

K8S之网络深度剖析(一)(持续更新ing)

K8S之网络深度剖析 一 、关于K8S的网络模型 在K8s的世界上,IP是以Pod为单位进行分配的。一个Pod内部的所有容器共享一个网络堆栈(相当于一个网络命名空间,它们的IP地址、网络设备、配置等都是共享的)。按照这个网络原则抽象出来的为每个Pod都设置一个IP地址的模型也被称作为I…

What does the error ‘module ‘langchain‘ has no attribute ‘verbose‘ refer to?

题意&#xff1a;错误 module langchain has no attribute verbose 指的是什么意思&#xff1f; 问题背景&#xff1a; Kind of new to Langchain/Qdrant but Im building a recommendation engine to recommend users based on the contents of their associated PDF files, …

Docker配置远程连接

前置条件&#xff1a;docker所在的服务器开放2375端口 文件&#xff1a;/usr/lib/systemd/system/docker.service 节点ExecStart 追加 -H tcp://0.0.0.0:2375

allure安装教程

1、下载 allure的官网下载地址&#xff1a; https://github.com/allure-framework/allure2/releases 注意&#xff1a;官网时常访问失败&#xff0c;可以访问以下网址&#xff1a; https://repo.maven.apache.org/maven2/io/qameta/allure/allure-commandline/ 选择一个版本&…

岗位实习最终篇(汇总)——人力资源管理系统(包含DDL,DML,视图,简单/复杂查询,触发器语句和存储过程语句)

DDL CREATE TABLE users (user_id INT AUTO_INCREMENT PRIMARY KEY COMMENT 员工ID,username VARCHAR(50) NOT NULL UNIQUE COMMENT 用户名,password VARCHAR(255) NOT NULL COMMENT 密码,first_name VARCHAR(50) NOT NULL COMMENT 名,last_name VARCHAR(50) NOT NULL COMMENT…

leetCode.97. 交错字符串

leetCode.97. 交错字符串 题目思路 代码 class Solution { public:bool isInterleave(string s1, string s2, string s3) {int n s1.size(), m s2.size();if ( s3.size() ! n m ) return false;vector<vector<bool>> f( n 1, vector<bool> (m 1));s1 …

【大数据导论】大数据序言

各位大佬好 &#xff0c;这里是阿川的博客&#xff0c;祝您变得更强 个人主页&#xff1a;在线OJ的阿川 大佬的支持和鼓励&#xff0c;将是我成长路上最大的动力 阿川水平有限&#xff0c;如有错误&#xff0c;欢迎大佬指正 目录 数据概念及类型及可用及组织形式数据概念数据…

阿里云oss实现图片上传

Bucket&#xff1a;存储空间是用户用于存储对象&#xff08;Object&#xff0c;就是文件&#xff09;的容器&#xff0c;所有的对象都必须隶属于某个存储空间。 SDK&#xff1a;Software Development Kit 的缩写&#xff0c;软件开发工具包&#xff0c;包括辅助软件开发的依赖…