本文由Markdown语法编辑器编辑完成。
VTK中基于面绘制实现三维重建,使用的是经典的Marching Cubes(移动立方体法)算法。
面绘制是采用分割技术对一系列的二维图像进行轮廓识别、提取等操作,最终还原出被检测物体的三维模型,并以表面的方式显示出来。
面绘制的数据流管道pipeline结构为:
读取器->提取等值面->数据处理->映射器->实例化角色->绘制器->绘制窗口->交互器->交换方式。
Marching Cubes算法简介:
首先,假定原始数据是离散的三维空间规则数据场;
其次,给出所求等值面的值;
最后,找出等值面经过的体元位置,求出该体元内的等值面并计算出相关参数(以便由常用的图形软件包或图形硬件提供的面绘制功能绘制等值面)。
VTK提供了两种提取等值面的类:
(1) vtkContourFilter
(2) vtkMarchingCubes.
VTK通过vtkPolyDataNormals在等值面上产生法向量;通过vtkStripper在等值面上产生纹理或三角面片。
由于vtk 从6.0版本后将管道连接的代码进行了修改。因此,如果是运用vtk 6.0以上版本的代码运行该例程,管道的连接函数为:SetInputConnection()和GetOutputPort().
/////////////////////////////////////////////////////////////////////////////////////////
//该代码在vtk 6.3,windows7操作系统上运行。
// VTK headers
#include "vtkVolume16Reader.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"
#include "vtkMarchingCubes.h"
#include "vtkStripper.h"
#include "vtkActor.h"
#include "vtkPolyDataMapper.h"
#include "vtkProperty.h"
#include "vtkCamera.h"
//#include "vtkBoxWidget.h"
#include <iostream>
int main()
{
//读取二维切片数据序列
vtkVolume16Reader *reader = vtkVolume16Reader::New();
reader->SetDataDimensions(64, 64); //设置像素
reader->SetDataByteOrderToLittleEndian();
reader->SetFilePrefix("D:\\vtk\\vtkdata\\Data\\headsq\\quarter");//设置读取路径
reader->SetImageRange(1, 93);
reader->SetDataSpacing(3.2, 3.2, 1.5);
//抽取等值面为骨头的信息
vtkMarchingCubes *boneExtractor = vtkMarchingCubes::New();
boneExtractor->SetInputConnection(reader->GetOutputPort());
boneExtractor->SetValue(0,500); //设置提取的等值信息
//剔除旧的或废除的数据单元,提高绘制速度
vtkStripper *boneStripper = vtkStripper::New(); //三角带连接
//注意:vtk6.0以后的版本,管道的连接函数修改为了SetInputConnection()和GetOutputPort().
boneStripper->SetInputConnection(boneExtractor->GetOutputPort());
//建立映射
vtkPolyDataMapper *boneMapper = vtkPolyDataMapper::New();
//注意:vtk6.0以后的版本,管道的连接函数修改为了SetInputConnection()和GetOutputPort().
boneMapper->SetInputConnection(boneStripper->GetOutputPort());
//建立角色
vtkActor *bone = vtkActor::New();
bone->SetMapper(boneMapper);
bone->GetProperty()->SetDiffuseColor(.1,.94,.52);
bone->GetProperty()->SetSpecular(.3);
bone->GetProperty()->SetSpecularPower(20);
//标准句子
//定义绘制器
vtkRenderer *aRenderer = vtkRenderer::New();
//定义绘制窗口
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer(aRenderer);
//定义窗口交互器
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
//创建一个camera
vtkCamera *aCamera = vtkCamera::New();
aCamera->SetViewUp(0,0,-1);
aCamera->SetPosition(0,1,0);
aCamera->SetFocalPoint(0,0,0);
aRenderer->AddActor(bone);
aRenderer->SetActiveCamera(aCamera);
aRenderer->ResetCamera();
aCamera->Dolly(1.5);
aRenderer->SetBackground(0,0,0);
aRenderer->ResetCameraClippingRange();
/*
vtkBoxWidget *boxWidget = vtkBoxWidget::New();
boxWidget->SetInteractor(iren);
boxWidget->SetPlaceFactor(1.25);
boxWidget->SetProp3D(bone);
boxWidget->PlaceWidget();
*/
iren->Initialize();
iren->Start();
reader->Delete();
iren->Delete();
return 0;
}
2.2 体绘制(Volume Rendering)
VTK中基于体绘制实现三维重建,使用的是光线投射法(Ray-casting)。
体绘制的原理和面绘制完全不相同。面绘制需要生成中间图元,而体绘制则是直接在原图上进行绘制,内容需求较面绘制小。每切换一个视角需要重新对所有的像素点进行颜色和透明度计算,需要时间比面绘制长。
VTK的管道结构实现体绘制需要的类有:
vtkRenderWindow, vtkRenderer, vtkLight, vtkCamera, vtkActor, vtkProperty, vtkTransform.
dataset->filter->mapper.
#include "vtkRenderWindowInteractor.h"
#include "vtkDICOMImageReader.h"
#include "vtkRenderWindow.h"
#include "vtkCamera.h"
#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkProperty.h"
#include "vtkPolyDataNormals.h"
#include "vtkImageShiftScale.h"
#include "vtkVolumeRayCastMapper.h"
#include "vtkPiecewiseFunction.h"
#include "vtkColorTransferFunction.h"
#include "vtkVolumeProperty.h"
#include "vtkVolumeRayCastCompositeFunction.h"
#include <iostream>
int main()
{
//标准句子
//定义绘制器
vtkRenderer *aRenderer = vtkRenderer::New();
//定义绘制窗口
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer(aRenderer);
//定义窗口交互器
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
//CT格式数据读取类
vtkDICOMImageReader *reader = vtkDICOMImageReader::New();
//这里输入Dicom数据的文件夹的路径,读者需要根据数据在本机上的位置进行修改。
reader->SetDirectoryName("D:\\TestData\\Brain");
//图像数据预处理。常见两种操作。一种是类型转换,通过 vtkImageShiftScale 将不同类型的数据集转换为 VTK 可以处理的数据;
//另一种是剔除冗余数据,通过 vtkStripper 放置无效的旧单元的存在,提高绘制速度。
vtkImageShiftScale *shiftScale = vtkImageShiftScale::New();
shiftScale->SetInputConnection(reader->GetOutputPort());
shiftScale->SetOutputScalarTypeToUnsignedChar();
//数据分类,找出数据与不同物质之间的对应关系,同时也为了在最终图像中以不同颜色表示单一物质的不同属性。
//此处省略
//………………
//透明度映射函数定义
//给数据点赋不透明值。体绘制中,需要显示三维数据场的内部结构,因而需要生成具有透明度的图像。
vtkPiecewiseFunction *opacityTransferFunction = vtkPiecewiseFunction::New();
opacityTransferFunction->AddPoint(20, 0.0);
opacityTransferFunction->AddPoint(255, 0.2);
//颜色映射函数定义
//给数据点赋颜色值,将分类后的组织信息分别予以不同的颜色,便于图像分析。
vtkColorTransferFunction *colorTransferFunction = vtkColorTransferFunction::New();
colorTransferFunction->AddRGBPoint(0.0, 0.0, 0.0, 0.0);
colorTransferFunction->AddRGBPoint(64.0, 1.0, 0.0, 0.0);
colorTransferFunction->AddRGBPoint(128.0, 0.0, 0.0, 1.0);
colorTransferFunction->AddRGBPoint(192.0, 0.0, 1.0, 0.0);
colorTransferFunction->AddRGBPoint(255.0, 0.0, 0.2, 0.0);
//体数据属性
vtkVolumeProperty *volumeProperty = vtkVolumeProperty::New();
volumeProperty->SetColor(colorTransferFunction);
volumeProperty->SetScalarOpacity(opacityTransferFunction);
volumeProperty->ShadeOn();
volumeProperty->SetInterpolationTypeToLinear();
//体绘制惯用语句:
//计算光照效应。采用光线类 vtkVolumeRayCastCompositeFunction 进行投射,
//最终用 vtkVolumeRayCastMapper类进行光效应计算。
vtkVolumeRayCastCompositeFunction *compositeFunction = vtkVolumeRayCastCompositeFunction::New();
vtkVolumeRayCastMapper *volumeMapper = vtkVolumeRayCastMapper::New();
volumeMapper->SetVolumeRayCastFunction(compositeFunction);
volumeMapper->SetInput(shiftScale->GetOutput());
vtkVolume *volume = vtkVolume::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
aRenderer->AddVolume(volume);
aRenderer->SetBackground(1,1,1);
renWin->SetSize(600, 600);
renWin->Render();
iren->Initialize();
iren->Start();
return 0;
}