等值面
等值面(线)提取是一种常用的可视化技术,常应用于医学、地质、气象等领域。例如,在医学图像处理中,由于CT、MRI等图像分辨率越来越高,虽然体绘制技术可以清晰地对数据内部结构进行可视化,但是其计算量和效率却制约了其使用。此时可通过等值面提取技术,仅提取感兴趣的一个或者几个组织轮廓,并生成网格模型以供后续的处理和研究。
根据数据类型的不同,VTK中提供了多个等值面提取类,其类图如图所示
VTK中的等值面提取算法多基于MarchingCube算法来实现。MarchingCube是经典的移动立方体等值面提取算法。该算法是由W.E.Lorenson和H.E.Cline在1987年提出的。由于这一方法原理简单,易于实现,目前已经得到了较为广泛的应用,称为三维数据等值面生成的经典算法。等值面提取类根据数据类型的不同而有所侧重。
- vtkImageMarchingCubes:主要处理三维图像数据
- vtkMarchingCubes:主要针对规则体数据生成等值面
- vtkMarchingSquares:则是针对二维规则网格数据生成等值线
- vtkMarchingContourFilter:可以接受任何类型的数据,其内部根据数据不同生成不同的算法对象实现等值面/线的提取,具有较高的效率
- vtkContourFilter:则是一个更加通用的等值面提取类,其可以接受任意的数据类型生成等值线或等值面。
- vtkDiscreteMarchingCubes 继承自vtkMarchingCubes,主要针对Label图像,比如利用图像分割算法对医学图像进行分割后得到含有不同Label值的数据,每个Label对应一个组织,通过想要得到其中一个或者几个组织的轮廓模型,则可以考虑使用该类。
- vtkDiscreteFlyingEdges3D
和vtkDiscreteMarchingCubes 功能类似。但产生的结果不同。此过滤器可以生成输出法线,并且每个标记区域与相邻区域完全断开连接(重合点不会合并)。这两种算法都会在具有不同分割标签的顶点之间的中间点处插入边。 此类已使用vtkSMPTools 进行线程化。使用 TBB 或其他非顺序类型(在 CMake 变量VTK_SMP_IMPLEMENTATION_TYPE中设置)可以显著提高性能。- 类图如下
- 类图如下
如何使用vtkDiscreteFlyingEdges3D
// Run marching cubes
#if VTK_MAJOR_VERSION >= 9 || (VTK_MAJOR_VERSION >= 8 && VTK_MINOR_VERSION >= 2)
// Normals computation in vtkDiscreteFlyingEdges3D is faster than computing normals in a subsequent
// vtkPolyDataNormals filter. However, if smoothing step is applied after vtkDiscreteFlyingEdges3D then
// computing normals after smoothing provides smoother surfaces.
bool marchingCubesComputesSurfaceNormals = (computeSurfaceNormals > 0) && (smoothingFactor <= 0);
vtkSmartPointer<vtkDiscreteFlyingEdges3D> marchingCubes = vtkSmartPointer<vtkDiscreteFlyingEdges3D>::New();
#else
bool marchingCubesComputesSurfaceNormals = false;
vtkSmartPointer<vtkDiscreteMarchingCubes> marchingCubes = vtkSmartPointer<vtkDiscreteMarchingCubes>::New();
#endif
marchingCubes->SetInputData(binaryLabelmapWithIdentityGeometry);
const int labelmapFillValue = binaryLabelmapWithIdentityGeometry->GetScalarRange()[1]; // max value
marchingCubes->GenerateValues(1, labelmapFillValue, labelmapFillValue);
marchingCubes->ComputeGradientsOff();
marchingCubes->ComputeNormalsOff();
marchingCubes->ComputeScalarsOff();
marchingCubes->Update();
设置等值面的值
提取等值面时,最重要的是要设置等值面的数值,SetValue()函数用于设置等值面的值,其第一个参数表示等值面的序号,因此可以通过这个函数设置多个等值面值来提取多个等值面。另外我们也可以通过GenerateValues提取多个等值面。
- SetValue
/**
* Set a particular contour value at contour number i. The index i ranges
* between 0<=i<NumberOfContours.
*/
void SetValue(int i, double value) {
this->ContourValues->SetValue(i,value);}
//设置多个值
int valueIndex = 0;
for (vtkIdType labelValue : labelValues)
{
marchingCubes->SetValue(valueIndex, labelValue);
++valueIndex;
}
- GenerateValues
/* Generate numContours equally spaced contour values between specified
* range. Contour values will include min/max range values.
*/
void GenerateValues(int numContours, double range[2]) {
this->ContourValues->GenerateValues(numContours, range);}
/**
* Generate numContours equally spaced contour values between specified
* range. Contour values will include min/max range values.
*/
void GenerateValues(int numContours, double rangeStart, double rangeEnd)
{
this->ContourValues->GenerateValues(numContours, rangeStart, rangeEnd);}
使用中遇到的问题
- 提取的等值面渲染是黑色的
- 关闭Scalars计算得以解决,如果计算Scalars 会导致mesh法线错误
marchingCubes->ComputeScalarsOff();