将第三讲的工程备份一份,后续的教程都会基于该教程讲解。由于篇幅问题,我不会贴上所有的代码,但是会给出pipeline流程图和关键代码,如果你对前面的教程掌握较好,那么通过pipeline流程图自己也能实现体绘制。
一般来说,体绘制的数据来源于扫描仪器的产生,比如MRI,CT,超声等等,但是各种仪器,或者说同类仪器由不同厂家生产,其扫描得到的原始数据有或多或少的差别,所以定义了一些标准格式,比如dicom。有人觉得拿到dicom格式的图像就万事大吉,体绘制就会极其顺利。其实不是的,本人在初次通过vtk进行体绘制的时候,死活读取不到数据,国内外的网站搜寻了一大堆,各种在论坛和前辈请教。甚至把数据传给别人依旧不能重建出来,其中的一种情况就是你拿到的数据已经经过了处理,比如压缩。
那么,对于不同格式的数据,我们有没有一个统一的办法解决问题呢?答案是肯定的,在vtk中有一个功能强大的类叫作vtkImageData,其实你通过vtk提供的各种reader去读取三维切片序列,或者直接读取一个三维图像,最终也要转换为vtkImageData格式。所以,当vtk中没有提供直接读取的reader,或者说直接读取的reader读取不到图像,我们依旧可以通过填写vtkImageData中的数据来实现体绘制。好了,扯得有点多了,直接上pipeline流程图:
先总体讲一下,本质上还是和cone例子中的流程一直,该有的data,mapper,actor(这里是vtkVolum),renderer都有,将他们串联起来就实现了体绘制。在途中的vtkxxxReader代表的是vtk中原生自带的所有reader,比如读取dicom、bmp、jpg这些格式的reader,如果你的图像格式可以通过原生reader读取到,那么调用GetOutputData也就能够得到vtkImagedata。如果你拿到的格式没有原生reader,那么你可以通过C++的fstream来读取,只需要把vtkImagedata填好就可以了。另外,说一下vtkVolumeProperty类,顾名思义是控制体绘制的参数的,比如光照,颜色等等。另外两个类vtkColorTransferFunction和vtkPiecewiseFunction分别控制体绘制的颜色和透明度,设置好后再传给vtkVolumeProperty。例如可以通过vtkColorTransferFunction可以改变骨骼的颜色,通过vtkPiecewiseFunction来讲人体的其他组织设置成透明,那么最后就只剩下骨骼。下面贴出填写vtkImagedata的代码:
this->pvtkImageData = vtkImageData::New();
this->pvtkImageData->SetDimensions(x, y, z); // 设置渲染数据的长宽高,俗称三维
this->pvtkImageData->SetSpacing(dx, dy, dz); // 设置三维的间隔,也就是两个像素点之间的间隔
this->pvtkImageData->SetOrigin(0.0, 0.0, 0.0); // 设置原点
this->pvtkImageData->AllocateScalars(VTK_UNSIGNED_SHORT, 1); // 该函数分配内存,具体的分配大小由两个函数参数共同决定
// 在这里代表的意思是,分配了x * y * z * sizeof(unsigned short * 1)这么大的内存
unsigned short *ptr = (unsigned short *)this->pvtkImageData->GetScalarPointer(); // 获取存储data数据的地址
memcpy(ptr, targetdata, x * y * z * sizeof(unsigned short * 1); // 将目标数据拷贝到vtkImageData中
接下里给出一些颜色和透明度的参考值,透明度映射:
this->popacityTransferFunction = vtkPiecewiseFunction::New();
this->popacityTransferFunction->AddPoint(1000, 0.0);
this->popacityTransferFunction->AddPoint(4000, 0.68);
this->popacityTransferFunction->AddPoint(7000, 0.83);
颜色映射:
this->pvtkColorTransferFunction = vtkColorTransferFunction::New();
this->pvtkColorTransferFunction->AddHSVPoint(1000, 0.042, 0.73, 0.55);
this->pvtkColorTransferFunction->AddHSVPoint(2500, 0.042, 0.73, 0.55, 0.5, 0.92);
this->pvtkColorTransferFunction->AddHSVPoint(4000, 0.088, 0.67, 0.88);
this->pvtkColorTransferFunction->AddHSVPoint(5500, 0.088, 0.67, 0.88, 0.33, 0.45);
this->pvtkColorTransferFunction->AddHSVPoint(7000, 0.95, 0.063, 1.0);
vtkVolumeProperty的设置:
this->pvtkVolumeProperty->SetColor(pvtkColorTransferFunction);
this->pvtkVolumeProperty->SetScalarOpacity(popacityTransferFunction);
this->pvtkVolumeProperty->SetInterpolationTypeToLinear();
this->pvtkVolumeProperty->ShadeOn();
this->pvtkVolumeProperty->SetShade(0, 1);
this->pvtkVolumeProperty->SetDiffuse(0.9);
this->pvtkVolumeProperty->SetAmbient(0.1);
this->pvtkVolumeProperty->SetSpecular(0.2);
this->pvtkVolumeProperty->SetSpecularPower(10.0);
this->pvtkVolumeProperty->SetComponentWeight(0, 1);
this->pvtkVolumeProperty->SetDisableGradientOpacity(1);
this->pvtkVolumeProperty->DisableGradientOpacityOn();
this->pvtkVolumeProperty->SetScalarOpacityUnitDistance(0.891927);
最终,渲染本文末尾共享的数据,可以得到如下效果:
图中渲染的是一个头部MRI图像。
如果对颜色按照如下代码进行修改:
this->popacityTransferFunction->AddPoint(1000, 0.0);
this->popacityTransferFunction->AddPoint(1150, 0.68);
this->popacityTransferFunction->AddPoint(1300, 0.83);
this->popacityTransferFunction->AddPoint(1301, 0);
将得到这样一幅图
大部分人体组织都看不见了,只剩下一个轮廓。
大脑图像下载
更多VTK教程,请VX搜索CodeKit。