使用 ITK 和 VTK 进行 CT 脑血管分割
CT Brain vessel segmentation using ITK and VTK
我正在做我自己的项目,其中我需要分割 脑血管 CT dicom 图像。我有 2 套 DICOM 图像。
1)CT dicom images of head with DSA (888 slices)
2)CT dicom images of head without DSA(same 888 slices),
所以我使用 vtkDICOMImageReader
分别阅读了这两个系列,并使用 vtkImageMathematics
减去这两个系列,并将结果存储在变量 mat
中,然后将其复制到 vtkImageReslice * reslice;
然后我使用 VKImageToImageFilter *filter_toitkimage
将此 reslice
导入 ITK 并使用此代码:
using HessianFilterType = itk::HessianRecursiveGaussianImageFilter<ImageType>;
HessianFilterType::Pointer hessianFilter = HessianFilterType::New();
hessianFilter->SetInput(filter_toitkimage->GetOutput());
hessianFilter->SetSigma(.6);
using VesselnessMeasureFilterType = itk::Hessian3DToVesselnessMeasureImageFilter<PixelType>;
VesselnessMeasureFilterType::Pointer vesselnessFilter = VesselnessMeasureFilterType::New();
vesselnessFilter->SetInput(hessianFilter->GetOutput());
vesselnessFilter->SetAlpha1(1);
vesselnessFilter->SetAlpha2(2);
然后我使用 ImageToVTKImageFilter
将其转换回 VTK 并使用了这个:
vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
volumeMapper->CroppingOff();
volumeMapper->RemoveAllInputs();
volumeMapper->SetInputData(conv->GetOutput()); //conv is the converted output
volumeMapper->SetBlendModeToMaximumIntensity();
volumeMapper->AutoAdjustSampleDistancesOff();
volumeMapper->SetSampleDistance(.1);
volumeMapper->Update();
//-----volume color
vtkSmartPointer<vtkColorTransferFunction> volumeColor = vtkSmartPointer<vtkColorTransferFunction>::New();
volumeColor->RemoveAllPoints();
////-----volume color
//---air
volumeColor->AddRGBPoint(0, 0.0, 0.0, 0.0);
volumeColor->AddRGBPoint(220, 1, 1, 1);
//---skin
volumeColor->AddRGBPoint(250, 0, 0, 0);
volumeColor->AddRGBPoint(300, 0, 0, 0);
//---muscle
volumeColor->AddRGBPoint(800, 1, 1, 1);
volumeColor->AddRGBPoint(1000, 1, 1, 1);
volumeColor->AddRGBPoint(1320, 1, 1, 1);
//---soft bone
volumeColor->AddRGBPoint(1350, 0, 0, 0);
volumeColor->AddRGBPoint(1500, 0, 0, 0);
//---hard bone
volumeColor->AddRGBPoint(1550, 0, 0, 0);
volumeColor->AddRGBPoint(2000, 0, 0, 0);
//---hardest bone
volumeColor->AddRGBPoint(2050, 0, 0, 0);
volumeColor->AddRGBPoint(4096, 0, 0, 0);
vtkSmartPointer<vtkPiecewiseFunction> volumeScalarOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
volumeScalarOpacity->AddPoint(0, 0.00);
volumeScalarOpacity->AddPoint(500, 0.15);
volumeScalarOpacity->AddPoint(1000, 0.15);
volumeScalarOpacity->AddPoint(1150, 0.85);
vtkSmartPointer<vtkPiecewiseFunction> volumeGradientOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
volumeGradientOpacity->AddPoint(0, 0.0);
volumeGradientOpacity->AddPoint(90, 0.5);
volumeGradientOpacity->AddPoint(100, 1.0);
vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
volumeProperty->SetColor(volumeColor);
volumeProperty->SetScalarOpacity(volumeScalarOpacity);
volumeProperty->SetGradientOpacity(volumeGradientOpacity);
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->ShadeOn();
volumeProperty->SetAmbient(0.5);
volumeProperty->SetDiffuse(0.3);
volumeProperty->SetSpecular(0.3);
vtkSmartPointer<vtkVolume> volume =vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
renderer->AddVolume(volume);
我得到了肺部的血管但是我没有得到脑血管的清晰图像。有人可以给点建议吗?
您的传递函数采用 CT 强度,但血管滤波器的输出与它完全不同。它可能被标准化为 0.0-1.0 范围,或 0-255 范围,或其他范围。你应该检查一下。
DSA 已经意味着 "Digital subtraction angiography"。因此您不应该再次执行差异,它已经由扫描仪的软件完成。您正在查看的可能是差异的一些中间步骤,但除非您想进行新的 CT 重建,否则我建议直接使用 DSA 而不要再次进行差异。请注意,在 PACS 中,它可能被称为模态 "XA" 用于血管造影(您不应该寻找 "CT" 模态)。
每个系统都不同,这可能很复杂,但我也在处理大脑的血管造影数据,一开始这让我感到困惑,所以我认为值得一提。
对于血管检测的原型设计,我建议首先使用 3D Slicer。有一个名为 VMTK 的库的插件实现了 vesselness 过滤器,但您也可以添加其他插件,尤其是用于获取所有 ITK 过滤器的插件。我认为使用它作为起点更容易,在实施之前尝试一些东西。
如果你真的想自己计算 DSA,在这种情况下你需要有 2 个 CTs 有和没有造影剂(但不是 DSAs),你必须确保在做差异之前两个体积都被完美地配准。如果您发现未对齐,我建议您使用简单的 elastix 框架来注册您的图像。
最后,vesselness 过滤器的临界点实际上是您 select 与 sigma 的频率。这基本上定义了容器的大小。在 VTMK 实现中,您可以有不同的频率,因此您可以设置开始和停止 sigma。在 Slicer 中,如果您在容器周围输入一些基准点,您甚至可以使用一个插件来找到正确的 sigma。所以如果你能看到一些血管但看不到其他血管,我建议将这个 sigma=0.6 降低到更低的值(假设血管显示比肺血管小)
希望对您有所帮助!
我正在做我自己的项目,其中我需要分割 脑血管 CT dicom 图像。我有 2 套 DICOM 图像。
1)CT dicom images of head with DSA (888 slices)
2)CT dicom images of head without DSA(same 888 slices),
所以我使用 vtkDICOMImageReader
分别阅读了这两个系列,并使用 vtkImageMathematics
减去这两个系列,并将结果存储在变量 mat
中,然后将其复制到 vtkImageReslice * reslice;
然后我使用 VKImageToImageFilter *filter_toitkimage
将此 reslice
导入 ITK 并使用此代码:
using HessianFilterType = itk::HessianRecursiveGaussianImageFilter<ImageType>;
HessianFilterType::Pointer hessianFilter = HessianFilterType::New();
hessianFilter->SetInput(filter_toitkimage->GetOutput());
hessianFilter->SetSigma(.6);
using VesselnessMeasureFilterType = itk::Hessian3DToVesselnessMeasureImageFilter<PixelType>;
VesselnessMeasureFilterType::Pointer vesselnessFilter = VesselnessMeasureFilterType::New();
vesselnessFilter->SetInput(hessianFilter->GetOutput());
vesselnessFilter->SetAlpha1(1);
vesselnessFilter->SetAlpha2(2);
然后我使用 ImageToVTKImageFilter
将其转换回 VTK 并使用了这个:
vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper = vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
volumeMapper->CroppingOff();
volumeMapper->RemoveAllInputs();
volumeMapper->SetInputData(conv->GetOutput()); //conv is the converted output
volumeMapper->SetBlendModeToMaximumIntensity();
volumeMapper->AutoAdjustSampleDistancesOff();
volumeMapper->SetSampleDistance(.1);
volumeMapper->Update();
//-----volume color
vtkSmartPointer<vtkColorTransferFunction> volumeColor = vtkSmartPointer<vtkColorTransferFunction>::New();
volumeColor->RemoveAllPoints();
////-----volume color
//---air
volumeColor->AddRGBPoint(0, 0.0, 0.0, 0.0);
volumeColor->AddRGBPoint(220, 1, 1, 1);
//---skin
volumeColor->AddRGBPoint(250, 0, 0, 0);
volumeColor->AddRGBPoint(300, 0, 0, 0);
//---muscle
volumeColor->AddRGBPoint(800, 1, 1, 1);
volumeColor->AddRGBPoint(1000, 1, 1, 1);
volumeColor->AddRGBPoint(1320, 1, 1, 1);
//---soft bone
volumeColor->AddRGBPoint(1350, 0, 0, 0);
volumeColor->AddRGBPoint(1500, 0, 0, 0);
//---hard bone
volumeColor->AddRGBPoint(1550, 0, 0, 0);
volumeColor->AddRGBPoint(2000, 0, 0, 0);
//---hardest bone
volumeColor->AddRGBPoint(2050, 0, 0, 0);
volumeColor->AddRGBPoint(4096, 0, 0, 0);
vtkSmartPointer<vtkPiecewiseFunction> volumeScalarOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
volumeScalarOpacity->AddPoint(0, 0.00);
volumeScalarOpacity->AddPoint(500, 0.15);
volumeScalarOpacity->AddPoint(1000, 0.15);
volumeScalarOpacity->AddPoint(1150, 0.85);
vtkSmartPointer<vtkPiecewiseFunction> volumeGradientOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
volumeGradientOpacity->AddPoint(0, 0.0);
volumeGradientOpacity->AddPoint(90, 0.5);
volumeGradientOpacity->AddPoint(100, 1.0);
vtkSmartPointer<vtkVolumeProperty> volumeProperty = vtkSmartPointer<vtkVolumeProperty>::New();
volumeProperty->SetColor(volumeColor);
volumeProperty->SetScalarOpacity(volumeScalarOpacity);
volumeProperty->SetGradientOpacity(volumeGradientOpacity);
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->ShadeOn();
volumeProperty->SetAmbient(0.5);
volumeProperty->SetDiffuse(0.3);
volumeProperty->SetSpecular(0.3);
vtkSmartPointer<vtkVolume> volume =vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
renderer->AddVolume(volume);
我得到了肺部的血管但是我没有得到脑血管的清晰图像。有人可以给点建议吗?
您的传递函数采用 CT 强度,但血管滤波器的输出与它完全不同。它可能被标准化为 0.0-1.0 范围,或 0-255 范围,或其他范围。你应该检查一下。
DSA 已经意味着 "Digital subtraction angiography"。因此您不应该再次执行差异,它已经由扫描仪的软件完成。您正在查看的可能是差异的一些中间步骤,但除非您想进行新的 CT 重建,否则我建议直接使用 DSA 而不要再次进行差异。请注意,在 PACS 中,它可能被称为模态 "XA" 用于血管造影(您不应该寻找 "CT" 模态)。
每个系统都不同,这可能很复杂,但我也在处理大脑的血管造影数据,一开始这让我感到困惑,所以我认为值得一提。
对于血管检测的原型设计,我建议首先使用 3D Slicer。有一个名为 VMTK 的库的插件实现了 vesselness 过滤器,但您也可以添加其他插件,尤其是用于获取所有 ITK 过滤器的插件。我认为使用它作为起点更容易,在实施之前尝试一些东西。
如果你真的想自己计算 DSA,在这种情况下你需要有 2 个 CTs 有和没有造影剂(但不是 DSAs),你必须确保在做差异之前两个体积都被完美地配准。如果您发现未对齐,我建议您使用简单的 elastix 框架来注册您的图像。
最后,vesselness 过滤器的临界点实际上是您 select 与 sigma 的频率。这基本上定义了容器的大小。在 VTMK 实现中,您可以有不同的频率,因此您可以设置开始和停止 sigma。在 Slicer 中,如果您在容器周围输入一些基准点,您甚至可以使用一个插件来找到正确的 sigma。所以如果你能看到一些血管但看不到其他血管,我建议将这个 sigma=0.6 降低到更低的值(假设血管显示比肺血管小)
希望对您有所帮助!