先上效果:
左边是这份代码体绘制的,右边是使用软件重建的。
需要注意的是 vtk 默认读取 DICOM 的类并不支持所有 DICOM 文件,只支持未经压缩处理的。
这份代码缺点是渲染速度比较慢,改用 vtkGPUVolumeRayCastMapper 的话速度会提升,骨骼效果也更好,但是外面有层类似云雾的东西,还需要调参优化。
#include <vtkSmartPointer.h> #include <vtkCamera.h> #include <vtkFiniteDifferenceGradientEstimator.h> #include <vtkImageClip.h> #include <vtkPiecewiseFunction.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRenderer.h> #include <vtkStructuredPoints.h> #include <vtkStructuredPointsReader.h> #include <vtkVolume.h> #include <vtkVolumeProperty.h> #include <vtkFixedPointVolumeRayCastMapper.h> #include <vtkColorTransferFunction.h> #include <vtkImageCast.h> #include <vtkDICOMImageReader.h> #include <vtkGPUVolumeRayCastMapper.h> #include <vtkSmartVolumeMapper.h> int main() { // Create the renderers, render window, and interactor vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New(); vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New(); iren->SetRenderWindow(renWin); vtkSmartPointer<vtkRenderer> ren = vtkSmartPointer<vtkRenderer>::New(); renWin->AddRenderer(ren); // Read data vtkSmartPointer<vtkDICOMImageReader> reader = vtkSmartPointer<vtkDICOMImageReader>::New(); reader->SetDirectoryName("C:\\Examples\\sample_data\\3Dircadb2.2\\PATIENT_DICOM"); reader->Update(); vtkSmartPointer<vtkImageCast> cast = vtkSmartPointer<vtkImageCast>::New(); cast->SetInputConnection(reader->GetOutputPort()); cast->SetOutputScalarTypeToUnsignedShort(); cast->Update(); vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New(); volumeProperty->SetInterpolationTypeToLinear(); volumeProperty->ShadeOn(); volumeProperty->SetAmbient(.5); volumeProperty->SetDiffuse(1.0); volumeProperty->SetSpecular(.5); volumeProperty->SetSpecularPower(25); volumeProperty->SetInterpolationTypeToLinear(); vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New(); compositeOpacity->AddPoint(-3024, 0, 0.5, 0.0); compositeOpacity->AddPoint(-220, 0, .49, .61); compositeOpacity->AddPoint(625, .71, .5, 0.0); compositeOpacity->AddPoint(3071, 0.0, 0.5, 0.0); volumeProperty->SetScalarOpacity(compositeOpacity); vtkSmartPointer<vtkColorTransferFunction> color = vtkSmartPointer<vtkColorTransferFunction>::New(); color->AddRGBPoint(-3024, 0, 0, 0, 0.5, 0.0); color->AddRGBPoint(-200, 0.73, 0.25, 0.30, 0.49, .61); color->AddRGBPoint(641, .90, .82, .56, .5, 0.0); color->AddRGBPoint(3071, 1, 1, 1, .5, 0.0); volumeProperty->SetColor(color); vtkSmartPointer<vtkPiecewiseFunction> volumeGradientOpacity = vtkSmartPointer<vtkPiecewiseFunction>::New(); volumeGradientOpacity->AddPoint(0, 2.0); volumeGradientOpacity->AddPoint(500, 2.0); volumeGradientOpacity->AddSegment(600, 0.73, 900, 0.9); volumeGradientOpacity->AddPoint(1300, 0.1); volumeProperty->SetGradientOpacity(volumeGradientOpacity); vtkSmartPointer<vtkFixedPointVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkFixedPointVolumeRayCastMapper>::New(); volumeMapper->SetInputConnection(cast->GetOutputPort()); volumeMapper->SetSampleDistance(0.5f); vtkSmartPointer<vtkVolume>volume = vtkSmartPointer<vtkVolume>::New(); volume->SetMapper(volumeMapper); volume->SetProperty(volumeProperty); ren->AddViewProp(volume); renWin->Render(); iren->Start(); return EXIT_SUCCESS; }