体绘制_光线投射算法+固定点光线投射算法+基于GPU加速的光线投射算法+二维纹理映射+三维纹理映射

参考链接:VTK修炼之道61:体绘制_光线投影+最大密度投影+等值面法-优快云博客

1.总类vtkVolumeMapper

vtkVolumeMapper是所有体绘制Mapper类的虚基类,提供接口函数,并由其子类实现具体功能。该类的继承关系如下图所示:

应该掌握一些常用的体绘制类。

1.光线投射:vtkVolumeRayCastMapper (新版本vtk已没)

光线投射法是最常用的体绘制方法。它是一种基于图像序列的直接体绘制方法。
光线投影法的基本原理是从投影图像平面(通常为平面)的每个像素沿着视线方向发射一条穿过体数据的射线,然后在射线上按照一定的步长进行等距采样,对每个采样点采用插值技术来计算其体素值,根据颜色传输函数和不透明度传输函数来获取相应的颜色值和不透明度,最后利用光线吸收模型将颜色值进行累加直至管线穿过体数据。这样,就可以得到当前平面像素的渲染颜色,最终生成显示图像。
光线投影法的优点是能够比较精确地模拟原始体数据,精度高。缺点是计算量较大,渲染速度相对比较慢,做实时体绘制时对计算机硬件的要求比较高。
在VTK中,VTKVolumeRayCastMapper类可用于实现光线投影体算法,并生成渲染图元数据传递给vtkVolume对象进行渲染。
vtkVolumeRayCastMapper类内部实现了三类非常重要的函数:

  • SetInput(vtkImageData*):该函数用于设置输入图像数据;
  • SetVolumeRayCastFunction(vtkVolumeRayCastFunction*):该类用于设置光线投射函数(光线合成函数)。
  •  SetSampleDistance(float);SetImageSampleDistance(float);SetImageSampleDistance(float);:设置采样步长和图像采样步长

每条光线在通过体数据后的颜色是通过定义的vtkVolumeRayCastFunction对象来实现的。  vtkVolumeRayCastFunction是一个虚基类,他包含三个子类。

1.1合成函数

1.1.1 vtkVolumeRauCastCompositeFunction(光线投影)

该方式通过Alpha合成技术 生成每个像素的颜色值。对于每条光线在穿过体数据时,先根据设置的采样步长进行采样,通过插值技术来计算每个采样点的像素值;然后根据vtkVolumeProperty中设置颜色传输函数和不透明度传输函数来计算采样点的颜色和不透明度。最后,对所有采样点采用Alpha合成方法计算最终的颜色。
另外,该方式还可以设置插值优先还是分类优先。 插值优先是指对投射光线进行采样,计算采样点的颜色值时,先通过插值方式计算该采样点的标量值(灰度值),然后再根据颜色传输函数和不透明度传输函数计算该点的颜色值和不透明度 。 分类优先是指在计算采样点时,先根据颜色传输函数和不透明度传输函数计算包含该采样点的立方体的8个顶点颜色值和不透明度,然后通过插值方法获取当前采样点的颜色值与不透明度 选择插值优先还是分类优先要通过一下两个函数:

  • SetCompositeMethodToInterpolateFirst()
  • SetCompositeMethodToClassifyFirst()

从显示效果上来说,插值优先具有较好的显示效果,但在一些情况下也会存在问题。 例如,CT图像中,低于20的值属于空气,20~80的部分是软组织,大于80部分是骨骼。如果先进行插值,那么空气与谷歌之间永远不会相邻,因为他们之间一定存在软组织。但是,我们的牙齿是和空气直接接触的,当使用插值优先策略并使用比较高的采样率进行体绘制时,渲染结果会使牙齿看起来像是覆盖了一层皮肤。

1.1.2 vtkVolumeRayCastMIPFunction(最大密度投影)

最大密度投影函数主要用于对体数据中高灰度值的结构进行可视化。当光线穿过体数据时,在光线上进行等距采样。取采样点中属性最大值为该条光线的输出。光线对应的屏幕像素颜色值就可以通过该值进行颜色映射获得。默认情况下,这个属性是指体数据的像素值或者体数据的不透明度,其设置函数为:
SetMaximizeMethodToScalarValue()
SetMaximizedMethodToOpacity()
当采用标量(灰度)属性时,先经过体数据的光线进行等距离采样,然后通过插值计算每个采样点的标量值,最后取标量值为最大的采样点对应的颜色和不透明度作为输出;当采样不透明度作为输出时,投射光线上每次采样都要计算一次不透明度,最后取不透明度最大值的采样点的颜色和不透明度作为输出。
通常,最大强度投影算法不计算明暗信息和深度信息,成像类似于X光,该方法常用于显示血管的三维结构。该类的使用方法也是非常简单的,和vtkVolumeRayCastCompositeFunction一致。

1.1.3 vtkVolumeRayCastIsosurfaceFunction(等值面法)

等值面绘制函数能够渲染体数据中特定等值面,其中,SetIsoValue(double)函数用于设置等值面的值。在进行体绘制,所有小于该值的像素不透明度都设置为0.通过设定等值面的值,可以重建出某一特定的组织,如皮肤、骨骼等,渲染结果类似与面绘制。

三种体绘制输出结果如下:

1.光线投影法输出图像:效果最好;
2.最大密度投影法输出图像:缺乏深度信息(更像X光输出);
3.等值面法体绘制输出结果:与面绘制结果类似。

1.2设置采样步长 

 1.2.1投影光线上的采样步长

光线投影体绘制中,投影光线上的采样点的步长是一个重要参数,决定了体绘制的精度和速度。步长越小,采样点就越多,绘制效果越好,但同时计算量也会增加。vtkVolumeRayCastMapper中设置步长的函数为:
        SetSampleDistance(float);
vtkVolumeRayCastMapper中默认采样步长为1,单位为世界坐标系
需要注意的是,等值面绘制函数不需要进行采样,而其他另个绘制函数都需要进行采样。在实际应用中,调整采样步长主要考虑的因素有样本间距、标量数据以及标量数据映射的颜色和不同明度变化率。
下面显示了步长为1和步长为4的两种情况对比:

左侧为步长等于1的情况;非常精细。
右侧为步长等于4的卿狂,比较粗糙。
实际应用过程中,如果体数据变化比较剧烈,应该适当减小采样步长以获得比较精细的渲染结果,代价就是速度的降低。

1.2.2图像采样间距(投影光线间隔)

默认情况下,图像采样间距为1,即每个像素对应一条投影光线;如果设为0.5,那么每个像素对应4条投射光线;如果设置为2,则每四个像素对应一条投影光线。设置图像采样距离的函数

void SetImageSampleDistance(float);

需要格外注意的是,当使用这个函数的时候,必须先关闭自动调节采样距离功能代码如下:

SetAutoAdjustSampleDistance(0); //关闭自动调整采样

默认的情况下,该函数的功能是开启的,以保证在图像旋转等交互时,能够自动调整采样距离保证实时性。如果关闭此功能,在旋转图像等交互过程中,体绘制渲染过程会变得很慢
当然,即使我们采用自动调整图像采样距离,也可以设定它的范围,控制函数为:

void SetMaximunImageSampleDistance(float);
void SetMinimumImageSampleDistance(float);

 下图显示的是不同图像采样距离的渲染结果:

左图的图像采样距离为1;右图的图像采样间距为4.同样,步长越小,渲染越精细,渲染时间越长。

2.固定点光线投影算法:vtkFixedPointVolumeRayCastMapper

vtkFixedPointVolumeRayCastMapper是一个较好的vtkVolumeRayCastMapper的替代者。该类能够实现基于Alpha合成的体绘制方法和最大密度投影体绘制方法,能够支持任意类型的一元或者独立多元数据。
例如,当输入为二元独立数据时,第一源数据用于颜色映射,而第二元作为不透明度映射。
该类使用了空间跳跃技术来加速体绘制渲染过程,而在内部计算时,统一使用了float数据类型。

vtkFixedPointVolumeRayCastFMapper与vtkVolumeRayCastMapper对比
两个类的使用方法基本一致,都支持设置光线采样步长、图像采样距离、自动调整图像采样距离等操作。
当然两者也存在以下区别:
1.vtkFixedPointVolumeRayCastFMapper只支持基于Alpha合成的体绘制方法和最大密度体绘制方法,可以通过基类vtkVolumeMapper的接口函数来设置。

void SetBlendModeToComposite();
void SetBlendModeToMaximumIntensity();
void SetBlendModeToMinimumIntensity();
void SetBlendModeToAddictive();

2.该类仅支持先插值在分类操作;
3.该类支持更多种数据类型。

3.基于GPU加速的光线投射体绘制算法vtkGPUVolumeRayCastMappe

vtkGPUVolumeRayCastMapper类实现了基于GPU加速的光线投影体绘制算法。该类的使用方法与上面两各类基本一致。同样可以实现光线采样步长、图像采样距离、自动调整图像采样距离等。

示例代码:


#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL); 
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkInteractionStyle);
 
#include <vtkSmartPointer.h>
#include <vtkStructuredPoints.h>
#include <vtkStructuredPointsReader.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVolumeProperty.h>
#include <vtkVolumeRayCastIsosurfaceFunction.h>
 
int main(int argc, char *argv[])
{
	vtkSmartPointer<vtkStructuredPointsReader> reader =
		vtkSmartPointer<vtkStructuredPointsReader>::New();
	reader->SetFileName("mummy.128.vtk");
	reader->Update();
 
 
	vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper =
		vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
	volumeMapper->SetInputData(reader->GetOutput());;
	volumeMapper->SetSampleDistance(volumeMapper->GetSampleDistance()/2);	//设置光线采样距离
	//volumeMapper->SetAutoAdjustSampleDistances(0);//设置图像采样步长
	//volumeMapper->SetImageSampleDistance(4);
	/*************************************************************************/
	vtkSmartPointer<vtkVolumeProperty> volumeProperty =
		vtkSmartPointer<vtkVolumeProperty>::New();
	volumeProperty->SetInterpolationTypeToLinear();
	volumeProperty->ShadeOn();  //打开或者关闭阴影测试
	volumeProperty->SetAmbient(0.4);
	volumeProperty->SetDiffuse(0.6);  //漫反射
	volumeProperty->SetSpecular(0.2); //镜面反射
	//设置不透明度
	vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity =
		vtkSmartPointer<vtkPiecewiseFunction>::New();
	compositeOpacity->AddPoint(70, 0.00);
	compositeOpacity->AddPoint(90, 0.40);
	compositeOpacity->AddPoint(180, 0.60);
	volumeProperty->SetScalarOpacity(compositeOpacity); //设置不透明度传输函数
	//设置梯度不透明属性
	vtkSmartPointer<vtkPiecewiseFunction> volumeGradientOpacity =
		vtkSmartPointer<vtkPiecewiseFunction>::New();
	volumeGradientOpacity->AddPoint(10, 0.0);
	volumeGradientOpacity->AddPoint(90, 0.5);
	volumeGradientOpacity->AddPoint(100, 1.0);
	volumeProperty->SetGradientOpacity(volumeGradientOpacity);//设置梯度不透明度效果对比
	//设置颜色属性
	vtkSmartPointer<vtkColorTransferFunction> color =
		vtkSmartPointer<vtkColorTransferFunction>::New();
	color->AddRGBPoint(0.000, 0.00, 0.00, 0.00);
	color->AddRGBPoint(64.00, 1.00, 0.52, 0.30);
	color->AddRGBPoint(190.0, 1.00, 1.00, 1.00);
	color->AddRGBPoint(220.0, 0.20, 0.20, 0.20);
	volumeProperty->SetColor(color);
	/********************************************************************************/
	vtkSmartPointer<vtkVolume> volume =
		vtkSmartPointer<vtkVolume>::New();
	volume->SetMapper(volumeMapper);
	volume->SetProperty(volumeProperty);
 
	vtkSmartPointer<vtkRenderer> ren = vtkSmartPointer<vtkRenderer>::New();
	ren->SetBackground(0, 1, 0);
	ren->AddVolume(volume);
 
	vtkSmartPointer<vtkRenderWindow> rw = vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(ren);
	rw->SetSize(640, 480);
	rw->Render();
	rw->SetWindowName("VolumeRendering");
 
	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	rwi->SetRenderWindow(rw);
 
	ren->ResetCamera();
	rw->Render();
	rwi->Start();
 
	return 0;

运行结果如下:

4.二维纹理映射:vtkVolumeTextureMapper2D

VTK修炼之道63:纹理映射体绘制_二维纹理映射_c++ vtk 三维测量-优快云博客

5.三维纹理映射:vtkVolumeTexture3D

VTK修炼之道64:纹理映射体绘制_三维纹理映射-优快云博客

6.体绘制各算法比较

VTK中不同的vtkVolumeMapper支持不同的数据类型。
vtkVolumeRayCastMapper和vtkVolumeTextureMapper2D仅支持VTK_UNSIGNED_CHAR 和VTK_UNSIGNED_SHORT类型数据。当涉及到其他类型数据时,需要做数据强制转换,可以考虑使用vtkImageCast或vtkImageShiftScale类。
vtkVolumeTextureMapper3D则支持任意类型数据,当然必须输单组分数据或者是多元独立数据。
VTKFixedPointVolumeRayCastMapper灵活性最高,支持所有类型数据,最该可以支持四元数据。
 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值