体绘制(Volume Rendering)概述之2:体数据详解!!!(包括下载网址)

摘抄“GPU Programming And Cg Language Primer 1rd Edition” 中文 名“GPU编程与CG语言之阳春白雪下里巴人”    

 

体数据( Volume Data

学习任何一门技术,首先要弄清楚这项技术的起源以及数据来源。技术的起源也就是技术最原始的需求,最原始的发展动力,了解了这一点就了解了这项技术的价值。而了解一门技术的数据来源,就把握了技术的最初脉络,是 持其牛耳 的一种方法,正如软件工程中的数据流分析方法一般。

我很想说,体数据与面数据的区别,就好像一个实心的铁球和一个空心的兵乓球的区别。不过这个比喻很显然有点俗,很难让人相信作者(我)是一个专业人士。于是我决定还是将与体数据相关的专业术语都阐述一遍。

不过,在此之前,我需要先消除大家的恐惧感,研究表明,动物对于未知事物总是存在恐惧感,这也是阻碍进一步学习的关键所在。体数据不是什么特别高深的火星符号,它是对一种数据类型的描述,只要是包含了体细节的数据,都可以称之为体数据。举个例子,有一堆混凝土,其中包含了碳物质( C )若干,水分子( H20 )若干,还有不明化学成分的胶状物,你用这种混凝土建造了块方砖,如果存在一个三维数组,将方砖 X Y Z 方向上的物质分布表示出来,则该数组可以被称为体数据。不要小看上面这个比喻,体数据本质上就是按照这个原理进行组织的!

体数据一般有 2 种来源:

1.        科学计算的结果,如:有限元的计算和流体物理计算;

2.        仪器测量数据,如: CT MRI 扫描数据、地震勘测数据、气象检测数据等。

与体数据相关的专业术语有:体素( Voxel )、体纹理( Volume Texture )。尤其要注意:所谓面数据,并不是说二维平面数据,而是说这个数据中只有表面细节,没有包含体细节,实际上体数据和面数据的本质区别,在于是否包含了体细节,而不是在维度方面。

14.4.2 体素( Voxel

Wikipedia 中对体属 voxel 的介绍为:

A voxel (a portmanteau of the words volumetric and pixel ) is a volume element, representing a value on a regular grid in three dimensional space. This is analogous to a pixel , which represents 2D image data in a bitmap

体素,是组成体数据的最小单元,一个体素表示体数据中三维空间某部分的值。体素相当于二维空间中像素的概念 42 中每个小方块代表一个体素。体素不存在绝对空间位置的概念,只有在体空间中的相对位置,这一点和像素是一样的。

通常我们看到的体数据都会有一个体素分布的描述,即,该数据由 n*m*t 个体素组成,表示该体数据在 X Y Z 方向上分别有 n m t 个体素。在数据表达上,体素代表三维数组中的一个单元。假设一个体数据在三维空间上 256*256*256 个体素组成,则,如果用三维数组表示,就必须在每一维上分配 256 个空间。

在实际的仪器采样中,会给出体素相邻间隔的数据描述,单位是毫米( mm ),例如 0.412mm 表示该体数据中相邻体素的间隔为 0.412 毫米


14.4.1 体纹理( Volume Texture

体数据最主要的文件格式是 体纹理( volume texture !故而,非常有必要对体纹理的概念进行详细的阐述。

目前,学术性文章中关于体纹理的概念描述存在不小的混乱,很多书籍或者网页资料没有明确的区分 2d texture 3d texture volume texture 之间的区别。导致不少人认为 只要是用于三维虚拟或仿真技术中的纹理都称之为 3d texture” 。这是一个误会。纹理上的 2 3 维之分本质上是根据其所描述的数据维数而定的,所谓 2d texture 指的是纹理只描述了空间的面数据,而 3d texture 则是描述了空间中的三维数据。 3d texture 另一个较为学术化的名称是: volume texture 。文献【 22 】上对体纹理的定义是:

3D texture (Three Dimensional Texture), also known as "volume texture," is a logical extension of the traditional (and better known) 2D texture. In this context, a texture is simply a bitmap image that is used to provide surface coloring for a 3D model. A 3D texture can be thought of as a number of thin pieces of texture used to generate a three dimensional image map. 3D textures are typically represented by 3 coordinates.

翻译成中文就是 三维纹理,即体纹理,是传统 2D 纹理在逻辑上的扩展。二维纹理是一张简单的位图图片,用于为三维模型提供表面点的颜色值;而一个三维纹理,可以被认为由很多张 2D 纹理组成的,用于描述三维空间数据的图片。三维纹理通过三维纹理坐标进行访问

从上面这句话,可以得到两点信息:

1.        三维纹理和体纹理是同一概念;三维纹理和二维纹理是不同的;

2.        三维纹理通过三维纹理坐标进行访问。

这时可能会有人提出问题了,图片都是平面的,怎么能表示三维数据?请注意,我们通常所看到的图片确实都是平面的,但是并不意味着 x,y 平面上的像素点不能存放三维数据,举一个例子:在高级语言编程中,我们完全可以用一维数组去存放三维数组中的数据,只要按照一定规则存放即可!

按照一定规则将三维数据存放在 XY 像素平面所得到的纹理,称之为 volume texture

体数据通常是由 CT 仪器进行扫描得到的,然后保存在图片的像素点上。目前国际上比较常用的体纹理格式有,基于 DirectX .dds 格式和 .raw 格式。注意,很多人会将 .raw 格式当作摄像器材使用的那种格式,其实这两个格式的后缀虽然都是 .raw ,但是其数据组织形式是不同的。用于体纹理的 .raw 格式,存放的是三维数据,用于摄像器材的 .raw 格式只是普通的二维图片。 43 从左到右分别是 University of Tübingen Germany )、 Viatronix Inc.(USA) Walter Reed Army Medical Center (USA) 三家机构的通过仪器扫描得到的体纹理数据的体绘制图片。


这三个体纹理数据的描述分别是: 256 x 320 x 128 /0.66, 0.66, 0.66 512 x 512 x 174/0.8398, 0.8398, 3.2 512 x 512 x 463/0.625, 0.625, 1.0

由于在国内的网站上很难找到体数据,所以下面我给出几个国外的网址,这些网址提供用于教学和研究只用的体纹理数据(只能用于教学和研究)。

http://wwwvis.informatik.uni-stuttgart.de/~engel/pre-integrated/data.html

http://www9.informatik.uni-erlangen.de/External/vollib/

http://www.volren.org/

 

14.5 体绘制算法

国际上留下的体绘制算法主要有:光线投射算法( Ray-casting )、错切 - 变形算法( Shear-warp )、频域体绘制算法( Frequency Domain )和抛雪球算法( Splatting )。其中又以光线投射算法最为重要和通用。

究其原因,无外乎有三点:其一,该算法在解决方案上基于射线扫描过程,符合人类生活常识,容易理解;其二,该算法可以达到较好的绘制效果;其三,该算法可以较为轻松的移植到 GPU 上进行实现,可以达到实时绘制的要求。

本书的第 15 章将重点阐述光线投射算法。

  • 2
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
### 回答1: 以下是一个基于DICOM序列图像的VTK绘制的C代码示例: ``` #include <vtkSmartPointer.h> #include <vtkDICOMImageReader.h> #include <vtkVolume.h> #include <vtkVolumeProperty.h> #include <vtkColorTransferFunction.h> #include <vtkPiecewiseFunction.h> #include <vtkFixedPointVolumeRayCastMapper.h> #include <vtkVolumeRayCastCompositeFunction.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> int main() { // 创建DICOM图像读取器 vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName("DICOM序列图像文件夹路径"); reader->Update(); // 创建颜色传递函数 vtkSmartPointer<vtkColorTransferFunction> colorTransferFunction = vtkSmartPointer<vtkColorTransferFunction>::New(); colorTransferFunction->AddRGBPoint(0, 0.0, 0.0, 0.0); colorTransferFunction->AddRGBPoint(255, 1.0, 1.0, 1.0); // 创建灰度传递函数 vtkSmartPointer<vtkPiecewiseFunction> opacityTransferFunction = vtkSmartPointer<vtkPiecewiseFunction>::New(); opacityTransferFunction->AddPoint(0, 0.0); opacityTransferFunction->AddPoint(255, 1.0); // 创建组合传递函数 vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->SetColor(colorTransferFunction); volumeProperty->SetScalarOpacity(opacityTransferFunction); volumeProperty->ShadeOff(); volumeProperty->SetInterpolationTypeToLinear(); // 创建数据映射器 vtkSmartPointer<vtkFixedPointVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>::New(); volumeMapper->SetInputConnection(reader->GetOutputPort()); // 创建积 vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New(); volume->SetMapper(volumeMapper); volume->SetProperty(volumeProperty); // 创建渲染器并添加积 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); renderer->AddVolume(volume); // 创建渲染窗口并设置渲染器 vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); // 创建交互式操作器并设置渲染窗口 vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); // 开始渲染 interactor->Initialize(); interactor->Start(); return 0; } ``` 该代码使用VTK库创建了一个DICOM图像的绘制的demo。首先,通过vtkDICOMImageReader读取DICOM序列图像的文件夹路径。然后,创建颜色传递函数和灰度传递函数用于对数据进行颜色和透明度的控制。接下来,使用vtkFixedPointVolumeRayCastMapper将DICOM图像数据映射为数据,并设置相应的传递函数。再创建一个vtkVolume对象来包含数据属性。然后,创建一个vtkRenderer并将积添加到其中。接下来,创建一个vtkRenderWindow并将渲染器添加到其中。最后,创建一个vtkRenderWindowInteractor,并将渲染窗口设置给它,并开始渲染。 ### 回答2: 以下是一个基于DICOM序列图像的C代码示例,用于vtk绘制和三维重建的演示。 ```c #include <vtkSmartPointer.h> #include <vtkDICOMImageReader.h> #include <vtkFixedPointVolumeRayCastMapper.h> #include <vtkColorTransferFunction.h> #include <vtkPiecewiseFunction.h> #include <vtkVolumeProperty.h> #include <vtkVolume.h> #include <vtkRenderWindow.h> #include <vtkRenderer.h> #include <vtkRenderWindowInteractor.h> int main(int argc, char* argv[]) { if (argc < 2) { std::cerr << "Usage: " << argv[0] << " <DICOM Directory>" << std::endl; return EXIT_FAILURE; } // 创建DICOM图像阅读器 vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName(argv[1]); reader->Update(); // 创建渲染Mapper vtkSmartPointer<vtkFixedPointVolumeRayCastMapper> mapper = vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>::New(); mapper->SetInputConnection(reader->GetOutputPort()); // 创建颜色转换函数 vtkSmartPointer<vtkColorTransferFunction> colorFun = vtkSmartPointer<vtkColorTransferFunction>::New(); colorFun->AddRGBPoint(0, 0.0, 0.0, 0.0); colorFun->AddRGBPoint(255, 1.0, 1.0, 1.0); // 创建灰度转换函数 vtkSmartPointer<vtkPiecewiseFunction> opacityFun = vtkSmartPointer<vtkPiecewiseFunction>::New(); opacityFun->AddPoint(0, 0.0); opacityFun->AddPoint(255, 1.0); // 创建属性 vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->SetColor(colorFun); volumeProperty->SetScalarOpacity(opacityFun); volumeProperty->ShadeOn(); volumeProperty->SetInterpolationTypeToLinear(); // 创建 vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New(); volume->SetMapper(mapper); volume->SetProperty(volumeProperty); // 创建渲染器和窗口 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); renderWindowInteractor->SetRenderWindow(renderWindow); // 将添加到渲染器中 renderer->AddViewProp(volume); // 渲染和开始交互 renderWindow->Render(); renderWindowInteractor->Start(); return EXIT_SUCCESS; } ``` 这个示例代码使用vtkDICOMImageReader加载DICOM序列图像,然后通过vtkFixedPointVolumeRayCastMapper创建渲染映射器。然后,使用vtkColorTransferFunction设置颜色转换函数和vtkPiecewiseFunction设置灰度转换函数来定义的颜色和透明度。创建一个vtkVolumeProperty,并将之前创建的转换函数和其他属性设置给它,然后创建一个vtkVolume并将之前创建的映射器和属性设置给它。最后,将该添加到vtkRenderer中,并通过创建vtkRenderWindow和vtkRenderWindowInteractor来显示渲染结果并启动交互。 ### 回答3: 以下是一个基于DICOM序列图像的C++代码示例,用于绘制vtk绘制(volume rendering)或三维重建的demo: ```c++ #include <vtkSmartPointer.h> #include <vtkDICOMImageReader.h> #include <vtkVolume.h> #include <vtkVolumeMapper.h> #include <vtkVolumeProperty.h> #include <vtkFixedPointVolumeRayCastMapper.h> #include <vtkPiecewiseFunction.h> #include <vtkColorTransferFunction.h> #include <vtkRenderWindow.h> #include <vtkRenderer.h> #include <vtkRenderWindowInteractor.h> int main(int argc, char *argv[]) { // 创建DICOM图像阅读器 vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName("DICOM文件夹路径"); // 修改为DICOM数据所在文件夹路径 reader->Update(); // 创建绘制的映射器和绘制属性 vtkSmartPointer<vtkFixedPointVolumeRayCastMapper> mapper = vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>::New(); mapper->SetInputConnection(reader->GetOutputPort()); vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->ShadeOff(); // 关闭阴影效果 // 创建透明度函数,并设置透明度映射 vtkSmartPointer<vtkPiecewiseFunction> opacityFunction = vtkSmartPointer<vtkPiecewiseFunction>::New(); opacityFunction->AddPoint(0, 0.0); opacityFunction->AddPoint(700, 0.1); opacityFunction->AddPoint(1400, 0.2); opacityFunction->AddPoint(2000, 0.4); volumeProperty->SetScalarOpacity(opacityFunction); // 创建颜色函数,并设置颜色映射 vtkSmartPointer<vtkColorTransferFunction> colorFunction = vtkSmartPointer<vtkColorTransferFunction>::New(); colorFunction->AddRGBPoint(0, 0.0, 0.0, 0.0); colorFunction->AddRGBPoint(700, 1.0, 0.5, 0.3); colorFunction->AddRGBPoint(1400, 1.0, 0.7, 0.5); colorFunction->AddRGBPoint(2000, 1.0, 1.0, 0.9); volumeProperty->SetColor(colorFunction); vtkSmartPointer<vtkVolume> volume = vtkSmartPointer<vtkVolume>::New(); volume->SetMapper(mapper); volume->SetProperty(volumeProperty); // 创建渲染器和渲染窗口 vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New(); vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New(); renderWindow->AddRenderer(renderer); // 创建交互器 vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New(); interactor->SetRenderWindow(renderWindow); // 将绘制添加到渲染器中 renderer->AddVolume(volume); renderer->SetBackground(1.0, 1.0, 1.0); // 设置背景颜色 // 启动交互器 interactor->Initialize(); interactor->Start(); return 0; } ``` 请将代码中的`"DICOM文件夹路径"`替换为实际的DICOM数据所在的文件夹路径,并确保已经正确安装和配置了VTK库。代码中的透明度函数和颜色函数是根据具需求进行设置,可以根据实际情况进行调整。运行该代码将显示一个包含绘制的渲染窗口,可以使用鼠标进行交互,可以使用鼠标滚轮进行缩放和旋转。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值