VTK系列教程六:多平面重建
上一篇我们讲了在VTK中如何生成VR图像,这一篇我们来讲一下如何利用VTK生成MPR图像,多平面重建图像就是从不同的方向去看物体,根据方向的不同,生成的图像分别是:横断面、冠状面、矢状面。
前面我们讲过VTK的绘制管线:物体->Filter->Mapper->结果,在实现MPR功能时我们也可以依据这个思路进行:
物体:
这里的物体指的是从DICOM文件读取数据后在内存中构造的对象:
this->m_reader = vtkDICOMImageReader::New();
this->m_reader->SetDirectoryName(path);
this->m_reader->Update();
从reader中我们就可以获取各种原始数据相关的信息。
Filter:
MPR就是从原始数据中获取截面,在VTK中,可以通过vtkImageReslice实现MPR图像,通过其继承体系可知他本质上是一种图像算法,在VTK中有很多种算法,采样、缩放、Mask等,这也符合Filter的目的,就是要对图像进行某种过滤,当然多平面重建也是一种过滤,从三维体数据中过滤出某个平面,其继承体系如下:
那Filter是如何获取截面的呢?在三维数据中,这里可以通过指定方向和位置来确定截面:
在VTK中相机的方向和位置可以通过变换矩阵来实现,vtkMatrix4x4* m_resliceAxes;
this->m_reslice->SetResliceAxes(this->m_resliceAxes);
设定相机方向:
this->m_resliceAxes->DeepCopy(viewup[index]);
static double viewup[3][16] = {
{ 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1 },
{ 1, 0, 0, 0,
0, 0, 1, 0,
0,-1, 0, 0,
0, 0, 0, 1 },
{ 0, 0,-1, 0,
1, 0, 0, 0,
0,-1, 0, 0,
0, 0, 0, 1 } };
设定截面位置:
this->m_resliceAxes->SetElement(0, 3, voldata->m_center[0]);
this->m_resliceAxes->SetElement(1, 3, voldata->m_center[1]);
this->m_resliceAxes->SetElement(2, 3, voldata->m_center[2]);
m_center是原始数据在三个方向的中点位置,我们一开始就截取中点位置的截面,交互过程中也是通过改变这个值实现翻层的。
Mapper:
经过Filter层后我们就可以获取截面数据了,但此时仍然只是一堆CT值而已,要将CT值转换成灰度图像,仍然需要转换,而转换就是需要转换表,这就是窗宽、窗位的原理,在VTK中我们通过下面这两个类实现窗宽窗位功能:
vtkLookupTable* m_lktable;
vtkImageMapToColors* m_mapcolor;
this->m_lktable->SetRange(0, 255); // image intensity range
this->m_lktable->SetValueRange(0.0, 1.0); // from black to white
this->m_lktable->SetSaturationRange(0.0, 0.0); // no color saturation
this->m_lktable->SetRampToLinear();
this->m_lktable->Build();
this->m_mapcolor->SetLookupTable(this->m_lktable);
this->m_mapcolor->SetInputConnection(this->m_reslice->GetOutputPort());
this->m_actor->GetMapper()->SetInputConnection(this->m_mapcolor->GetOutputPort());
this->m_render->AddActor(this->m_actor);
到这里我们就可以显示MPR图像了,在VTK中有很多已经高度封装的类,我们可以充分利用,而不重复造轮子,例如,窗宽、窗位功能我们就可以使用vtkImageMapToWindowLevelColors来实现,而不用自己定义转换表,如果我们想更简单一些,那么可以用vtkResliceImageViewer类,这要设置DICOM文件的位置就可以了。
VTK系列教程六:多平面重建相关推荐
- [转]Android Studio系列教程六--Gradle多渠道打包
转自:http://www.stormzhang.com/devtools/2015/01/15/android-studio-tutorial6/ Android Studio系列教程六--Grad ...
- 以太坊构建DApps系列教程(六):使用定制代币进行投票
在本系列关于使用以太坊构建DApps教程的第5部分中,我们讨论了如何为Story添加内容,查看如何添加参与者从DAO购买代币的功能以及在Story中添加提交内容.现在是编写DAO最终形式的时候了:投票 ...
- 米思齐(Mixly)图形化系列教程(六)-for循环
目录 For执行过程 省略 省略'循环变量赋值' 省略'循环条件' 省略"循环变量增量" FOR循环使用举例 遍历数组 顺序输出数据 指定程序重复执行次数 死循环 求和 教程导航 ...
- PVE系列教程(六)、安装Windows11系统(专业版、企业版、家庭版通用)
为了更好的浏览体验,欢迎光顾勤奋的凯尔森同学个人博客 PVE系列教程(六).安装Windows11系统(专业版.企业版.家庭版通用) 一.创建win11的虚拟机,并设置参数 在PVE右上角点击创建虚拟 ...
- ClickHouse系列教程六:源码分析之Debug编译运行
ClickHouse系列教程: ClickHouse系列教程 根据官方文档的编译教程:How to Build ClickHouse on Linux - ClickHouse Documentati ...
- ASP.NET Core Web Razor Pages系列教程六:添加搜索功能
系列文章目录:系列教程:使用ASP.NET Core创建Razor Pages Web应用程序 - zhangpeterx的博客 系列教程代码的GitHub地址:ASP .Net Core Razor ...
- Redis系列教程(六):Redis缓存和MySQL数据一致性方案详解
需求起因 在高并发的业务场景下,数据库大多数情况都是用户并发访问最薄弱的环节.所以,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问MySQL等数据库. 这个业务场景,主要 ...
- NGUI_2.6.3_系列教程六(序列帧动画)
今天我给大家讲一下如何使用NGUI做序列帧动画.本节主要包括两方面内容,分别是使用UIspirit和使用UITexture 做序列帧动画.废话不说了,下面开始. 还要在啰嗦一句,首先大家要准备一些序列 ...
- twisted系列教程六–继续重构twisted poetry client
Poetry for Everyone 我们已经在我们的client取得了很大的进步,我们的2.0版本已经试用了Transports,Protocols 和Protocols Factories.但是 ...
最新文章
- jQuery判断当前元素显示状态并控制元素的显示与隐藏
- 【机器学习入门到精通系列】SVM与核函数(附程序模拟!)
- 构建安全的Xml Web Service系列之SSL篇
- Oracle条件查询语句-where
- 【Android应用开发】Android Studio 错误集锦 -- 将所有的 AS 错误集合到本文
- 纯JS制作的窗户雨滴效果
- python 做词云 -jupyter跟随王树义教程学习
- Halcon例程(基于多个标定图的单目相机标定)详解—— Camera_calibration_multi_image.hdev
- 献给那些离婚或准备离婚的人
- lintcode 734. 形式为a^i b^j c^k的子序列数量 题解
- 发自虎扑android客户端,巴斯托尼要长留我纯啊
- 我的第一个C++程序,还像个C++c程序的样子吧
- SAP License:药店ERP系统如何实施
- C#编码简单性之泛型篇(如何编写简短的C#代码,随时更新)
- 网页压缩ob_start('ob_gzhandler')
- 算法(0)—— 打造一个C开发库
- 权力的游戏登录显示服务器上限,权力与纷争登录不上怎么办 登录不上解决方案...
- mongodb 学习笔记--- 基础知识
- pyLDA系列︱gensim中的主题模型(Latent Dirichlet Allocation)
- 学霸是怎样炼成的?学了那么多还一无是处?如何克服学习阻力?一件枯燥讨厌的事但必须要做?内心强大的主观改造 自我加速(学以致用)与环境加速(学习型组织)