体绘制

常用的体绘制方法

体绘制,有时又称三维重建(区别与投影图像的三维重建),是一种直接利用体内数据来生成二维图像的绘制技术,与面绘制不同,体绘制技术不需要提取体数据内部的等值面,它是一个对三维体数据进行采样和合成的过程。体绘制能够通过设置不透明度值来显示体内数据内部的不同成分和细节,例如显示人体CT图像和不同器官和组织。体绘制也是VTK中一个重要内容。下面会讲到关于体绘制几个重要方法

vtkVolumeRayCastMapper

光线透射法是最常用的体绘制方法。它是基于图像序列的直接体绘制方法,其基本原理是从投影图像平面的每个像素沿着视线方向发射一条穿过体数据的射线,然后在射线上按照一定的步长进行等距采样,对每个采样点采用插值技术来计算其体素值,根据颜色传输函数和不透明度传输函数来获取相应的颜色值和不透明度,最后利用光线吸收模型将颜色值进行累加直至光线穿过体数据,即可得到当前平面像素的渲染颜色,生成最终的显示图像,光线投射法的优点是能够比较精确地模拟原始体数据,但计算量比较大,实时体绘制对计算机硬件的要求比较高。

在vtk中,vtkVolumeRayCastMapper类可用于实现投射体算法,并生成渲染图元数据传递给vtkVolume对象进行渲染。vtkVolumeRayCastMapper采用软件方法实现光线投射算法,精度高但是计算量比较大,因此渲染速度相对比较慢,里面的两个最重要函数。

vtkVolumeRayCastMapper::SetInputData(vtkImageData * );
vtkVolumeRayCastMapper::SetVolumeRayCastFunction(vtkVolumeRayCastFunction *);

该函数用于设置光线投射函数。

vtkVolumeRayCastMapper 中计算光线在通过体数据后的颜色是通过定义的vtkVolumeRayCastFunction对象实现的,因此必须为vtkVolumeRayCastMapper指定一个vtkVolumeRayCastFunction对象。投射函数类vtkVolumeRayCastFunction是一个虚基类,它有三个子类。

1.vtkVolumeRayCastCompositeFunction

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

void SetCompositeMethodToInterpolateFirst();
void SetCompositeMethodToClassToClassifyFirst();

上图是光线透射法体绘制效果

2. vtkVlolumeRayCastMIPFunction

最大密度投射函数主要用于对体数据中高灰度值的结构进行可视化。当光线穿过体数据时,在光线上进行等距采样,取采样点中属性最大值为该条光线的输出光线对应的屏幕像素颜色值即可通过该值进行颜色映射获取,默认情况下,这个属性是指体数据的像素值或者标量值,也可以指定不透明度,其设置函数如下:

void SetMaximizeMethodToScalarValue();
void SetMaximizeMethodToOpacity();

当采用标量属性时,先经过体数据的光线进行等距离采样,然后通过插值计算每个采样点的标量值,最后取标量值为最大的采样点对应的颜色和不透明度输出;当采用不透明度为参考时,投射光线上每次采样都要计算一次不透明度,最后取不透明度为最大值的采样点的颜色和不透明度输出。通常最大强度投影算法不计算明暗信息和深度信息,成像类似于X光图像。 该函数进行体绘制时只需要将部分代码替换即可:

vtkSmartPointer<vtkVolumeRayCastCompositeFunction> rayCastFun=vtkSmartPointer<vtkVolumeRayCastCompositeFunction>::New();

// 替换为:
vtkSmartPointer<vtkVolumeRayCastMIPFunction> rayCastFun=vtkSmartPointer<vtkVolumeRayCastMIPFunction>::New()

这里写图片描述

上图为最大密度透射法体绘制效果

3.vtkVolumeRayCastIsosurfaceFunction

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

vtkSmartPointer<vtkVolumeRayCastCompositeFunction> rayCastFun=vtkSmartPointer<vtkVolumeRayCastCompositeFunction>::New();

//替换为:

vtkSmartPointer<vtkVolumeRayCastIsosurfaceFunction> rayCastFun=vtkSmartPointer<vtkVolumeRayCastIsosurfaceFunction>::New();
rayCastFun->SetIsoValue(100);//设置要进行显示的等值面的值。

这里写图片描述

上图为等值面体绘制效果

光线投射体绘制中,投射光线上的采样点的步长是一个重要的参数,决定了体绘制的精度和速度。步长越小,采样点就越多,但体绘制效果提高的同时计算量也会增加。vtkVolumeRayCastMapper 中设置步长的函数为:

void SetSampleDistance(float);

这里写图片描述
采样距离为1

这里写图片描述

采样距离为4


从效果上看,光线透射法的体绘制效果更好;最大密度投影法缺乏深度信息,因此更像一个X光图像;而等值面体绘制可以对数据的某一等值面进行显示和观察,与面绘制效果类似。

代码如下:

#include<iostream>
#include"vtkSmartPointer.h"
#include"vtkImageData.h"
#include"vtkStructuredPoints.h"
#include"vtkStructuredPointsReader.h"
#include"vtkVolumeRayCastCompositeFunction.h"
#include"vtkGPUVolumeRayCastMapper.h"
#include"vtkVolumeRayCastMapper.h"
#include"vtkColorTransferFunction.h"
#include"vtkPiecewiseFunction.h"
#include"vtkRenderer.h"
#include"vtkRenderWindow.h"
#include"vtkRenderWindowInteractor.h"
#include"vtkVolumeProperty.h"
#include"vtkAxesActor.h"
#include"vtkImageShiftScale.h"
#include"vtkImageCast.h"
#include"vtkFixedPointVolumeRayCastMapper.h"
#include"vtkAutoInit.h"
#include"vtkVolumeRayCastMIPFunction.h"
#include"vtkVolumeRayCastIsosurfaceFunction.h"
#include"vtkVolumeTextureMapper3D.h"
#include"vtkInteractorStyleImage.h"
#include"vtkImageReslice.h"
#include"vtkMetaImageReader.h"
#include"vtkMatrix4x4.h"
#include"vtkLookupTable.h"
#include"vtkImageMapToColors.h"
#include"vtkImageActor.h"
#include"vtkPolyDataReader.h"
#include"vtkSurfaceReconstructionFilter.h"
#include"vtkContourFilter.h"
#include"vtkVertexGlyphFilter.h"
#include"vtkProgrammableSource.h"
#include"vtkProperty.h"
#include"vtkPolyDataMapper.h"



VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL)

int main(int argc,char *argv[])
{
    if (argc < 2)
    {
        cout << "Input Arg Is Error!" << endl;
        exit(1);
    }
    vtkSmartPointer<vtkStructuredPointsReader> reader = vtkSmartPointer<vtkStructuredPointsReader>::New();

    reader->SetFileName(argv[1]);
    reader->Update();
    // vtkVolumeRayCastCompositeFunction  定义光线经过体数据后颜色的计算方式。
vtkSmartPointer<vtkVolumeRayCastMIPFunction>::New();
    vtkSmartPointer<vtkVolumeRayCastCompositeFunction> rayCastFun=vtkSmartPointer<vtkVolumeRayCastCompositeFunction>::New();
    //rayCastFun->SetIsoValue(100);
    // 定义光线投射体绘制Mapper  1.输入图像数据 2.设置光线投射类型。
    vtkSmartPointer<vtkVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkVolumeRayCastMapper>::New();


    // 输入图形数据
    volumeMapper->SetInputData(reader->GetOutput());

    // 设置光线投射类型。
    volumeMapper->SetVolumeRayCastFunction(rayCastFun);
    volumeMapper->SetSampleDistance(4);



    // 定义体绘制属性对象,决定体绘制的渲染效果。
    vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
    // 设置线性插值类型。
    volumeProperty->SetInterpolationTypeToLinear();
    // 是否打开阴影效果
    volumeProperty->ShadeOn();  
    // 设置环境光系数
    volumeProperty->SetAmbient(0.4);
    // 设置散射光系数
    volumeProperty->SetDiffuse(0.6);
    // 设置反射光系数
    volumeProperty->SetSpecular(0.2);
    // 当环境光系数占主导时,阴影效果不明显;
    //当散射光占主导时,显示效果会比较粗糙;
    //当反射光占主导时,显示效果会比较光滑。
    // 一般情况下三值之和等于1,有时候为了提高亮度,三值和会大于1。 
//vtkVolumeProperty::SetSpecularPower()控制体绘制的外观平滑程度。

    // 定义标量线性分段函数。
    // 1.直接添加断点 AddPoint(x,y)  x是自变量,指灰度值;y是指映射指,不透明度。
    // RemovePoint(x) 删除断点。RemoveAllPoint() 删除所有断点。
    vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New();
    compositeOpacity->AddPoint(70,0.00);   // 当灰度值小于70时候,不透明度映射为0。
    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);

    // 颜色传输函数。x 表示像素灰度值,rgb 为映射的RGB分量
    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(1.0,1.0,1.0);
    ren->AddVolume(volume);

    vtkSmartPointer<vtkRenderWindow> renwin = vtkSmartPointer<vtkRenderWindow>::New();
    renwin->AddRenderer(ren);
    renwin->SetSize(640,480);
    renwin->Render();
    renwin->SetWindowName("WJ_window");

    vtkSmartPointer<vtkRenderWindowInteractor> interactor = vtkSmartPointer<vtkRenderWindowInteractor>::New();

    interactor->SetRenderWindow(renwin);
    ren->ResetCamera();

    renwin->Render();
    interactor->Start();


    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值