先上效果:
左边是这份代码体绘制的,右边是使用软件重建的。
需要注意的是 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;
}
