体绘制(Volume Rendering)概述之1:什么是体绘制?

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

1982 年2 月,美国国家科学基金会在华盛顿召开了科学可视化技术的首次会议,会议认为“科学家不仅需要分析由计算机得出的计算数据,而且需要了解在计算过程中的数据变换,而这些都需要借助于计算机图形学以及图像处理技术”。

---- 《三维数据场可视化》1.1 节科学计算可视化概述

自 20 世纪 80 年代科学计算可视化( Visualization in Scientific Computing )被提出后,三维体数据的可视化逐渐称为发展的重点,并最终形成了体绘制技术领域。

一些文章,甚至是优秀硕博士论文库上的文章,解释体绘制概念时,通常都说 “ 体绘制技术是直接根据三维体数据场信息产生屏幕上的二维图像 ” ,这种说法太过含糊,如果根据三维体数据场信息随便产生一张图像,难道也是体绘制吗?我查找相关文献后,发现这种说法是国外一些文献的误译,例如, M.Levoy 在文章 “Display of surfaces from volume data”( 文献【 14 】 ) 中提到 “volume rendering describes a wide range of techniques for generating images from three-dimensional scalar data” ,翻译过来就是 “ 体绘制描述了一系列的 “ 根据三维标量数据产生二维图片 ” 的技术 ” 。注意,人家文章中用的是 “ 描述 ” ,而不是对体绘制下定义。老实说,老外的这种说法虽然挑不出毛病,但是我依然感觉没有落实到重点。

体绘制的核心在于 “ 展示体细节!而不是表面细节 ” 。我给出的定义是:依据三维体数据,将所有体细节同时展现在二维图片上的技术,称之为体绘制技术。利用体绘制技术,可以在一幅图像中显示多种物质的综合分布情况,并且可以通过不透明度的控制,反应等值面的情况。

例如, CT 图片中展示的是人体的肌肉和骨骼信息,而不是表面信息(那是照片)。所以理解体绘制和面绘制技术的区别的 , 一个很直观的比喻是:普通照相机照出的相片和 CT 仪器拍出的 CT 照片,虽然都是二维图片,但是展现的对象是不同的!

国外自上世纪 80 年代末以来,在体绘制技术方面已经取得了长足的进步,西门子、东芝、通用电器,都有对 GPU 编程领域以及体绘制技术进行研究,并将体绘制技术运用到医疗器材中。然而,体绘制技术在中国的发展,如果说还处于萌芽阶段,实不为过!我在学习和研究过程中,在国内网站上甚至只找到了一个可用的体数据,还是国外代码中附带的演示数据,而国内的 openGPU 网站上关于体绘制的论坛板块则是根本是空白。国外已经常用的医疗器材和算法,在中国还没有成形,这实在是一种悲哀。一个讽刺的现象是,外国公司从事体绘制算法研究的却不乏中国人,这更是一种悲哀。写到这里,作为一名以 server the people 为毕生理想的有志青年,我有点伤感,有些沮丧,所以,还是先洗洗睡了,明天再来写下面的章节。

14.1 体绘制与科学可视化
科学可视化技术是运用计算机图形学、图像处理、计算机视觉等方法,将科学、工程学、医学等计算、测量过程中的符号、数字信息转换为直观的图形图像,并在屏幕上显示的理论、技术和方法。

体绘制是科学可视化领域中的一个技术方向。如前所述,体绘制的目标是在一副图片上展示空间体细节。举例而言,你面前有一间房子,房子中有家具、家电,站在房子外面只能看到外部形状,无法观察到房子的布局或者房子中的物体;假设房子和房子中的物体都是半透明的,这样你就可以同时查看到所有的细节。这就是体绘制所要达到的效果。

14.2 体绘制应用领域
人类发展史上的重大技术带来的影响大致分为两种:其一,技术首先改变生活本身,然后改变人类对世界的看法,例如电视、电话等;还有一种技术,是首先改变人类对世界的看法,然后改变生活本身,例如伦琴射线、望远镜。

体绘制技术应该属于后者,通过改变所见,而改变生活。体绘制计算的重要意义,首先在于可以在医疗领域 server the people, 有助于疾病的诊断,这一点应该不用多说,计算机断层扫描( CT )已经广泛应用于疾病的诊断。医疗领域的巨大需求推动了体绘制技术的告诉发展,如果了解 CT 的工作原理,也就大致了解了体绘制技术原理和流程,所以本书在附录 B 给出了医学体绘制的有关文献,作为补充阅读资料,当您对体素、光线投射等术语缺乏感性认识时,可以参阅理解;其二,体绘制计算可以用于地质勘探、气象分析、分子模型构造等科学领域。我在工作期间承担的一个较大的项目便是有关 “ 三维气象可视化 ” ,气象数据通常非常庞大,完全可以号称海量数据,每一个气压面上都有温度、湿度、风力风向等格点数据,气象研究人员希望可以同时观察到很多气压面的情况,这时就可以采用体绘制技术,对每个切面(气压面)进行同时显示。

体绘制技术也能用于强化视觉效果,自然界中很多视觉效果是不规则的体,如流体、云、烟等,它们很难用常规的几何元素进行建模,使用粒子系统的模拟方法也不能尽善尽美,而使用体绘制可以达到较好的模拟效果。如 图 41 所示,这是使用体绘制技术进行烟的模拟效果。

在这里插入图片描述

14.3 体绘制与光照模型
尽管光照模型通常用于面绘制,但是并不意味着体绘制技术中不能使用光照模型。实际上 , 体绘制技术以物体对光的吸收原理为理论基础,在实现方式上,最终要基于透明度合成计算模型。此外,经典的光照模型,例如 phong 模型, cook-torrance 模型都可以做为体绘制技术的补充,完善体绘制效果,增强真实感。

往往有初学者会分不清 “ 体绘制技术 ” 以及 “ 透明光照模型 ” 之间的区别。这个问题很有意思。实际上,体绘制技术与透明光照模型在感性认识上十分类似,在很多教程中对体绘制技术的阐述也涉及到透明物体。但是,透明光照模型,一般侧重于分析光在透明介质中的传播方式(折射,发散,散射,衰减等),并对这种传播方式所带来的效果进行模拟;而体绘制技术偏重于物体内部层次细节的真实展现。举例而言,对于一个透明的三棱镜,使用透明光照模型的目的在于 “ 模拟光的散射,折射现象(彩虹) ” ;而对于地形切片数据或者人体数据,则需要使用体绘制技术观察到其中的组织结构。此外,在实现方式上,透明光照模型一般是跟踪光线的交互过程,并在一系列的交互过程中计算颜色值;而体绘制技术是在同一射线方向上对体数据进行采样,获取多个体素的颜色值,然后根据其透明度进行颜色的合成。

总的来说,透明光照模型侧重于光照效果展现,并偏向艺术化;而体绘制技术侧重展现物质内部细节,要求真实!

不过,现在体绘制技术实际上也可以用于艺术领域,因为体绘制技术所使用的方法,实际上具有很强的通用性,尤其是传统的 ray-cast 方法,完全可以应用到透明光照模型中(绘制烟雾等)。不同的技术之间会存在共融性,将技术和领域的关系近固化,是研究人员的大忌。科学史上很多前例都说明了一个事实:不同领域的交合点,往往会出现重大发现或发明。在爱因斯坦之前,又有谁知道时间、空间和质量之间的关系呢?

  • 10
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答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库。代码中的透明度函数和颜色函数是根据具需求进行设置,可以根据实际情况进行调整。运行该代码将显示一个包含绘制的渲染窗口,可以使用鼠标进行交互,可以使用鼠标滚轮进行缩放和旋转。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值