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

        前段时间对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;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Kamailio-命令行指令kamctl与kamcmd

前文也有提到几种指令的用处&#xff0c;与web页面相比&#xff0c;它就是更原始、面向运维的&#xff0c;正常如果有管理页面也需要使用到&#xff1a; kamailio - SIP 服务器脚本kamdbctl - 创建和管理数据库的脚本&#xff0c;比如你使用MySQL作为其存储时就需要使用到这个…

每天五分钟计算机视觉:人体姿势识别

本文重点 人体姿势识别是计算机视觉领域的一个重要研究方向,旨在通过图像或视频数据自动检测并识别出人体的各种姿势和动作。随着深度学习技术的快速发展,基于神经网络的方法在这一领域取得了显著进展。神经网络,特别是卷积神经网络(CNN)和循环神经网络(RNN),因其强大…

安装opencv-python出错,怎么办?

安装opencv-python出错 解决方法&#xff1a; 具体版本号&#xff0c;python3.6对应的就是4.3.0.38 pip install opencv-python4.3.0.38 -i https://pypi.tuna.tsinghua.edu.cn/simple

检测水管缺水的好帮手-管道光电液位传感器

管道光电液位传感器是现代清水管道管理中的重要技术创新&#xff0c;不仅提高了检测液位的精确度&#xff0c;还解决了传统机械式和电容式传感器存在的诸多问题&#xff0c;成为检测管道缺水的可靠利器。 该传感器采用先进的光学感应原理&#xff0c;利用红外光学组件通过精密…

2G 3G 4G常用知识点

名词解释 LTE网络、WCDMA网络、2G、3G 4G 区别及联系? 2G (第二代移动通信技术) 2G是最早的数字移动电话标准&#xff0c;主要支持语音通话和短信服务。代表性技术有GSM (Global System for Mobile Communications) 和CDMA (Code Division Multiple Access)。 3G (第三代移动…

相亲交友APP系统婚恋交友社交软件开发语音视频聊天平台定制开发-婚恋相亲交友软件平台介绍——app小程序开发定制

互联网飞速发展的时代&#xff0c;相亲交友软件成为了许多年轻人首选的相亲方式&#xff0c;越来越多的单身男女希望在婚恋交友软件平台上寻找灵魂伴侣&#xff0c;相亲交友软件因此具有很高的市场价值。 多客婚恋相亲交友系统是一款定位高端&#xff0c;到手就能运营的成熟婚恋…

Java入门编码10个注意点,大家注意“避坑”

插&#xff1a; AI时代&#xff0c;程序员或多或少要了解些人工智能&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家(前言 – 人工智能教程 ) 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家…

FileZilla的安装和使用(快速上手版)

下载 登陆官网下载下载 - FileZilla中文网 服务端 我们选择一个中文安装最新版本下载 客户端 我们选择绿色免安装版进行下载 安装 安装服务端 双击运行下载好的服务端安装包 点击 我接受 点击 下一步 设置好安装路径&#xff0c;点击 下一步 这里默认即可&#xff0c;点击…

智慧园区可视化:构建全方位智能管理体系

通过图扑的 2D、 3D 和 GIS 可视化技术结合倾斜摄影、数字孪生和视频融合等技术&#xff0c;将园区各类数据集成展示&#xff0c;实时监控和分析环境与设施状况&#xff0c;提升管理效能和安全水平&#xff0c;实现智慧园区的全方位智能化运营。

属性加密技术:保障数据安全的新利器

随着信息技术的飞速发展&#xff0c;数据安全已成为我国乃至全球关注的焦点。在众多数据安全技术中&#xff0c;属性加密技术以其独特的优势&#xff0c;逐渐成为保障数据安全的新利器。本文将从属性加密技术的原理、特点及其应用场景三个方面进行介绍&#xff0c;以期为读者提…

SpringBoot 集成Swagger在线接口文档 接口注解

介绍 Swagger接口文档是一种自动生成、描述、调用和可视化的RESTful风格Web服务接口文档的工具。它通过一系列的规范和自动化工具&#xff0c;极大地简化了后端开发人员与前端开发人员之间的协作。 依赖 <!--swagger--> <dependency><groupId>io.springfo…

高考志愿填报,选热门专业还是选自己喜欢的专业

对于每一个结束高考的学生来说&#xff0c;都要面临选专业这个严峻的挑战。选专业可以说是妥妥的大工程&#xff0c;因为这关系到接下来的几年要学什么内容&#xff0c;关键是未来的几十年要从事什么样的工作。 所以在谈及选专业这个问题的时候&#xff0c;每个人的内心都有些…

加权 KNN 算法的原理与详解

加权kNN&#xff0c;k近邻算法的增强改进版本。 加权KNN算法 近邻算法&#xff08;k-Nearest Neighbors, kNN&#xff09;是一种用于分类和回归的非参数方法。它的基本思想是“看邻居”&#xff0c;即通过查找离目标点最近的 K 个数据点&#xff0c;来判断目标点的类别或数值。…

kimi,让论文写作不再是一场苦旅【下】

学境思源&#xff0c;一键生成论文初稿&#xff1a; AcademicIdeas - 学境思源AI论文写作 今天我们继续昨天的内容&#xff1a;kimi&#xff0c;让论文写作不在是一场苦旅【上】&#xff0c;为大家列举与Kimi互动的示例。 8. 文献综述&#xff1a; 1. 文献搜索策略&#xff1…

育才兴业,助力数字产业蓬勃发展

成都树莓集团通过校企合作、建设人才项目转化中心、推动一线多园战略以及提供全方位服务等举措&#xff0c;积极培养数字产业人才&#xff0c;为行业发展提供了有力支持。 一、校企合作&#xff0c;打造人才培养高地 树莓集团深知企业协同育人的重要性&#xff0c;积极与高校建…

ppt接单渠道大公开‼️

PPT 接单主要分两种&#xff1a;PPT 模板投稿和PPT 定制接单&#xff0c;我们先从简单的 PPT 模板投稿说起。 PPT 模板投稿 利用业余时间&#xff0c;做一些 PPT 模板上传到平台&#xff0c;只要有人下载你的模板&#xff0c;你就有收入。如果模板质量高&#xff0c;简直就是一…

Python特征工程 — 1.3 对数与指数变换

目录 1 对数变换 1.1 对数变换的概念 1.2 对数变换实战 2 指数变换 2.1 指数变换的概念 2.2 指数变换实战 3 Box-Cox变换 3.1 Box-Cox变换概念 3.2 Box-Cox变换实战 1 对数变换 1.1 对数变换的概念 特征对数变换和指数变换是数据预处理中的两种常用技术&#xff0c;…

制造企业真的需要数字化转型吗?一文讲透:为何做,如何做?

此前拜访了不少制造企业&#xff0c;其以中小型企业居多&#xff0c;在与企业负责人交流数字化转型话题时&#xff0c;感触最多的还是管理者对“数字化转型”的认知。 在数字化转型方面从国家层面到地方政府进行大量的宣传与政策支持&#xff0c;部分行业头部企业也从数字化转…

Appium Inspector介绍和使用

一、什么是Appium Inspector 官方介绍&#xff1a;Overview - Appium Inspector 检查器的主要目的是提供应用程序页面源代码的检查功能。它主要用于测试自动化开发&#xff0c;但也可用于应用程序开发 - 或者如果只是想查看应用程序的页面源代码&#xff01; 从本质上讲&…

RK3568驱动指南|第十六篇 SPI-第192章 mcp2515驱动编写:完善write和read函数

瑞芯微RK3568芯片是一款定位中高端的通用型SOC&#xff0c;采用22nm制程工艺&#xff0c;搭载一颗四核Cortex-A55处理器和Mali G52 2EE 图形处理器。RK3568 支持4K 解码和 1080P 编码&#xff0c;支持SATA/PCIE/USB3.0 外围接口。RK3568内置独立NPU&#xff0c;可用于轻量级人工…