一个读取CT图像序列,并进行表面重建的C++代码

        这篇文章中,介绍使用VTK进行读取CT图像(一个序列),然后进行表面重建。为什么不使用DCMTK呢?因为使用DCMTK需要一张一张读取,要自己写一个代码,还要创建一个容器来放读入的CT数据,比较复杂。在实际的工程中,我们需要寻找合适的工具来造出漂亮的项目。


        1 为什么使用VTK

VTK自己就带有DICOM文件读取类,同时VTK中的imagedata 类可以存储一个图像矩阵,是一个很受欢迎的容器。VTK中还有表面重建算法marchingcubes,也很好用的。

1.1 vtkImageData的特点
  1. 数据结构:vtkImageData是基于结构化网格的数据表示形式,数据点被组织成一个规则的二维或三维数组。这些数据点称为像素或格点,每个像素包含一个或多个数值表示的属性信息。vtkImageData使用这种结构方便地表示二维图像和三维体数据。
  2. 数据类型:vtkImageData支持多种数据类型,如VTK_FLOAT、VTK_INT、VTK_SHORT、VTK_UNSIGNED_CHAR等,可以满足不同图像数据的存储需求。
  3. 维度信息:vtkImageData对象的维度描述了其包含像素的行数、列数和深度(对于三维图像)。这些维度信息决定了数据在空间中的范围和形状。
  4. 原点与间距:vtkImageData具有原点和间距属性,它们定义了空间中像素的位置和大小。原点表示数据中第一个像素的位置坐标,间距定义了相邻像素在各个方向上的间隔距离。
  5. 灵活性:vtkImageData提供了丰富的方法和属性,用于访问和修改单个像素的数值,进行图像处理以及数据分析。同时,它还支持与其他VTK类进行集成,实现更复杂的可视化和分析任务。
1.2  vtkMarchingCubes类的特点
  1. 等值面提取
    vtkMarchingCubes类主要用于从三维规则体数据中提取等值面。它通过分析体数据中的每个体素(小立方体),并根据给定的等值面值,构造出逼近等值面的三角面片。

  2. 算法效率
    Marching Cubes算法实际上是一个分而治之的方法,它将等值面的抽取分布于每一个体素中进行。这种分布式处理使得算法在处理大规模数据时具有较高的效率。

  3. 适用性广泛
    vtkMarchingCubes类不仅适用于医学图像重建,如CT和MRI数据,还广泛应用于地质勘探、气象预报、流体力学等领域中的三维数据可视化。

  4. 法向量计算
    vtkMarchingCubes类在提取等值面的同时,还可以计算每个三角面片的法向量。法向量的计算对于提高渲染质量和实现光照效果至关重要。

  5. 集成性强
    vtkMarchingCubes类与VTK库中的其他类具有良好的集成性,可以方便地与其他可视化工具结合使用,实现更复杂的可视化任务。

2 CPP代码实践

    string filePath="../data";  //定义文件路径(CT序列存放的位置)// 定义一个reader指针,指向vtkDICOMIMageReader类vtkSmartPointer<vtkDICOMImageReader> reader=vtkSmartPointer<vtkDICOMImageReader>::New();reader->SetDirectoryName(filePath.c_str());  //设置路径reader->Update();                            //读取float* ipp;                                  //定义一个指向ImagePositionPatient类的指针,该方法不安全ipp=reader->GetImagePositionPatient();// 定义一个指向ImageData容器类的指针,用来存储读入的CT图像。vtkSmartPointer<vtkImageData> originalData = reader->GetOutput();int dim[3];    // 维度double spa[3], ori[3];   //空间分辨率,原点originalData->GetDimensions(dim);originalData->GetSpacing(spa);originalData->GetOrigin(ori);//输出cout<<"Origin: "<<ori[0]<<","<<ori[1]<<","<<ori[2]<<endl;cout<<"ImagePositionPatient: "<<ipp[0]<<","<<ipp[1]<<","<<ipp[2]<<endl;cout<<"Dimension: "<<dim[0]<<","<<dim[1]<<","<<dim[2]<<endl;cout<<"Spacing: "<<spa[0]<<","<<spa[1]<<","<<spa[2]<<endl;

输出结果为:

Origin: 0,0,0
ImagePositionPatient: -449.414,-449.414,-80
Dimension: 384,384,64
Spacing: 1.17188,1.17188,2.5

我们可以看到原点在0,0,0,这个是VTK图像自定义的原点,在图像体积的左下角,如下图所示:

        图1 VTK中默认的坐标系位置(红色到绿色到蓝色坐标系分别为X,Y,Z,右手系)

在实际的应用中,我们知道CT扫描的时候是有一个物理坐标系的。它的中心点(0,0,0)大致在CT孔颈的中心处,同时处在那一层的CT图像就是0层面。因为在实际的临床运用中,是需要坐标系的,比如远距离放射治疗,立体定向手术等。

使用vtkMarchingCubes类来获取表面重建

// 定义MarchingCubes指针vtkSmartPointer<vtkMarchingCubes> mc=vtkSmartPointer<vtkMarchingCubes>::New();mc->SetInputData(originalData);   //输入mc->SetValue(0,-100);             //阈值mc->Update();                     //数据更新vtkSmartPointer<vtkPolyDataMapper> mapper=vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(mc->GetOutputPort());   //相当于演员的衣服vtkSmartPointer<vtkActor> actor=vtkSmartPointer<vtkActor>::New();  //演员actor->SetMapper(mapper);    //演员穿衣服
vtkSmartPointer<vtkAxesActor> axes=vtkSmartPointer<vtkAxesActor>::New();  //坐标轴axes->SetPosition(0,0,0);      //位置axes->AxisLabelsOff();         // 不显示X,Y,Z(很丑)axes->SetTotalLength(150,150,150);   // 坐标轴长度// 舞台vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();renderer->AddActor(axes);  //加入坐标轴renderer->AddActor(actor);  //加入演员vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();   //渲染窗口(可以调整大小)vtkSmartPointer<vtkRenderWindowInteractor> iren=vtkSmartPointer<vtkRenderWindowInteractor>::New();   //与窗口内容交互vtkSmartPointer<vtkInteractorStyleTrackballCamera> style=vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();  //交互模式(我比较喜欢)renWin->AddRenderer(renderer);renWin->SetSize(600,600);//renWin->Render();iren->SetInteractorStyle(style);iren->SetRenderWindow(renWin);iren->Initialize();iren->Start();

输出的结果如下:

图2 CT图像表面重建结果(CatPhantom 503 模体)

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

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

相关文章

亳州自闭症寄宿制学校,关注孩子的学习和生活

在特殊教育领域&#xff0c;自闭症儿童的教育与成长一直是社会各界关注的焦点。近年来&#xff0c;随着对自闭症认识的加深&#xff0c;越来越多的寄宿制学校应运而生&#xff0c;致力于为这些特殊的孩子提供全面、个性化的教育服务。在安徽亳州&#xff0c;这样的学校正努力为…

Metasploit渗透测试之后渗透

简介 Metasploit拥有300多个后渗透模块&#xff0c;是渗透测试的最佳框架之一&#xff0c;覆盖了从信息收集到后渗透甚至报告的每个阶段。本章将重点介绍提权、持久化、获取凭证和横向移动等内容。 # 1、后渗透模块 在Metasploit框架升级后&#xff0c;用于自动化后渗透任务…

C++——类和对象(二)

1. 类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;编译器会自动生成的成员函数称为默认成员函数。⼀个类&#xff0c;我们不写的情况下编译器会默认生成以下6个默认成员函数&#xff0c;需要注意的是这6个中最重要的是前4个&#xff0c;最后两个取地址重载不…

某国有资本运营中心人才选拔项目纪实

某国有资本运营中心人才选拔项目纪实 【客户行业】 政府与事业单位 【问题类型】 人才招聘选拔 【客户背景】 在三年国企改革过程中&#xff0c;南方某省政府为响应国家政策&#xff0c;提出组建专业化国有资本投资运营公司&#xff0c;大力开展专业化资本运营&#xff0c;…

移除元素(算法题分享)

移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作&#xf…

MySQL从0到1基础语法笔记(上)

博客主页&#xff1a;誓则盟约系列专栏&#xff1a;Java Web关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 MySQL笔记&#xff1a; 一、注释&#xff1a; 二、SQL四大类&#xff…

什么是安全漏洞?最全的漏洞分类!

01 — “ 什么是漏洞**”** 漏洞是指一个系统存在的弱点或缺陷&#xff0c;系统对特定威胁攻击或危险事件的敏感性&#xff0c;或进行攻击的威胁作用的可能性。漏洞可能来自应用软件或操作系统设计时的缺陷或编码时产生的错误&#xff0c;也可能来自业务在交互处理过程中的设…

丝杆支撑座预压标准解析

丝杆支撑座预压的主要目的是提高轴的旋转精度、刚性和运行性能&#xff0c;同时防止轴在运转过程中产生震动和异响&#xff0c;从而提高系统的整体精度和稳定性。那么&#xff0c;丝杆支撑座的预压标准是什么呢&#xff1f; 丝杆支撑座的预压可以分为标准型轻预压和标准型重预压…

自动生成实体类,mapper类,mapper.xml文件

使用mybatis generator&#xff08;无需安装&#xff0c;对于外网有限制的真的很友好&#xff09; 1. 在pom文件中配置mysql相关依赖&#xff0c;并添加plugin <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId…

GIS专业的就业前景

地理信息系统&#xff08;GIS&#xff09;作为一门跨学科的领域&#xff0c;随着技术的发展和应用领域的拓宽&#xff0c;其就业前景日益广阔。GIS专业毕业生可以在多个行业中找到合适的职位&#xff0c;并且随着经验的积累&#xff0c;薪资和职业发展空间都相当可观。 1. 就业…

H7-TOOL的1拖4脱机烧录SPI Flash芯片XM25QU64在1.8V供电时满速下载的稳定性测试

XM25QU64规格&#xff1a; XM25QU64C实测1.8V&#xff08;脱机烧录上位机这里和微型数控电源界面都设置TVCC为1.8V&#xff09; &#xff0c;1拖4转接板方式&#xff0c;直接将芯片放入转接板&#xff0c;稳定好用&#xff1a; 时钟电平1.8V实际效果&#xff1a;

centos7安装node18及升级glbic

centos7安装node18及升级glbic CentOS7安装nodejs18及以上版本会报错&#xff0c;glibc版本过低 安装nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash source ~/.nvm/nvm.shnvm install 18 nvm use 18#设置默认版本 nvm alias defau…

hznu.dodo C++ 实验A 文件

1.【描述】 输入10个整数存入文本文件example.txt中&#xff0c;文件每行存放5个整数&#xff0c;每行整数之间用一个空格间隔。行末不能有多余的空格。 【输入】 输入10个整数。 【输出】 生成文件example.txt&#xff0c;里面存放输入的10个整数。 不需要在屏幕上显示整数。 …

CISP vs CISSP | 不知道选哪个?这篇告诉你答案

CISP与CISSP有什么区别&#xff1f;我到底考哪个呢&#xff1f;哪个难一点&#xff1f;哪个含金量高&#xff1f; 这些问题一篇为你全部解答&#xff01; 01 概念和发证机构的差异 CISP&#xff0c;“Certified Information Security Professional”&#xff0c;即注册信息安…

postman自动化实战总结

Postman实战总结 简介 本次实战内容主要包括如下几点&#xff1a; l 背景介绍 l Postman使用&#xff0c;侧重于自动化实现&#xff0c;基础使用不做介绍 l 可视化Newman介绍 l 框架特色 l 实战中的坑 背景 随着国内软件技术的高速发展&#xff0c;越来越多的手工测试…

【JavaScript】JS核心语法及函数

文章目录 一、初识 JS二、JS 核心语法2-1 变量2-2 数据类型typeofString 对象 2-3 数组创建数组常用属性方法 2-4 运算符号加号运算符 减号运算符 -比较运算符逻辑运算符 2-5 控制语句for-inbreakcontinue 三、函数3-1 常用系统函数3-2 自定义函数函数声明函数调用 3-3 创建对象…

Spring WebFlux 响应式概述(1)

1、响应式编程概述 1.1、响应式编程介绍 1.1.1、为什么需要响应式 传统的命令式编程在面对当前的需求时的一些限制。在应用负载较高时&#xff0c;要求应用需要有更高的可用性&#xff0c;并提供低的延迟时间。 1、Thread per Request 模型 比如使用Servlet开发的单体应用&a…

MatrixVT: Efficient Multi-Camera to BEV Transformation for 3D Perception

本文提出了一种高效的多摄像头到鸟瞰图 (BEV) 视图转换方法&#xff0c;用于 3D 感知&#xff0c;称为 MatrixVT。现有的视图转换器要么转换效率低下&#xff0c;要么依赖于特定于设备的操作符&#xff0c;阻碍了 BEV 模型的广泛应用。相比之下&#xff0c;我们的方法仅使用卷积…

达梦8-主备集群故障之故障备库剔除与重新加入

实验环境 操作系统版本 银河麒麟Linux kylin10 4.19.90-24.4.v2101.ky10.x86_64 数据库版本 DM Database Server 64 V8 ##主库信息 内网IP-[MAL_HOST 192.168.50.100]外网IP-[MAL_INST_HOST 192.168.101.11] 主库实例名-[DM01] OGUID45335 ##备库信息 内网IP-[MAL_HOST …

这些都伦敦银结算时间 第二个尤其值得关注

伦敦银结算时间是什么时候呢&#xff1f;伦敦银虽说号称是24小时交易的品种&#xff0c;实际上每个平台都会在一个交易日中选定一定的时间停盘进行结算&#xff0c;在这些时间投资者没法交易&#xff0c;市场也不会波动。那么&#xff0c;伦敦银结算时间是什么时候&#xff1f;…