MarchingCubes建模是三维可视化库VTK建模算法之一。该建模方法采用空间分解的方法,对空间体元进行不断的切割处理,最后得到一个由规则体构成的非规则复杂物体的近似。这种方法包括有物体的内在信息,从而实现体数据的表达。
MC方法求等值面的算法流程:
① 将三维离散规则数据场分层读入内存;
② 扫描两层数据,逐个构造体元,每个体元中的8个角点取自相邻的两层;
③ 将体元每个角点的函数值与给定的等值面C作比较,根据比较结果,构造该体元的状态表;
④ 根据状态表,得到将与等值面有角点的体元边界;
⑤ 通过线性插值方法,计算出体元边界与等值面的交点;
⑥ 利用中心差分方法,求出体元各角点处的法向量,再通过线性插值方法,求出三角形各顶点处的法向量;
<7> 根据各三角面片各顶点的坐标值及法向量绘制等值面图像。
#include "stdafx.h"
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkImageData.h>
#include <vtkSphereSource.h>
#include <vtkVoxelModeller.h>
#include <vtkRenderWindow.h>
#include <vtkSmartPointer.h>
#include <vtkMarchingCubes.h>
#include <vtkPolyDataMapper.h>
#include <vtkDICOMImageReader.h>
#include <vtkRenderWindowInteractor.h>
int _tmain(int argc, _TCHAR* argv[])
{
// std::string folder = "C:\\Users\\yorktal03\\Desktop\\ZYH\\data\\MarchingMan";
vtkSmartPointer<vtkSphereSource> sphere = vtkSphereSource::New();
sphere->SetPhiResolution(20);
sphere->SetThetaResolution(20);
sphere->Update();
double bounds[6];
// GetBounds()
// Return a pointer to the geometry bounding box in the form (xmin,xmax, ymin,ymax, zmin,zmax).
// THIS METHOD IS NOT THREAD SAFE.
sphere->GetOutput()->GetBounds(bounds);
/*for (unsigned int i = 0; i < 6; i += 2)
{
double range = bounds[i + 1] - bounds[i];
bounds[i] = bounds[i] - .1 * range;
bounds[i + 1] = bounds[i + 1] + .1 * range;
}*/
vtkSmartPointer<vtkVoxelModeller> voxelModeller = vtkVoxelModeller::New();
voxelModeller->SetSampleDimensions(50, 50, 20);
voxelModeller->SetModelBounds(bounds);
voxelModeller->SetScalarTypeToFloat();
voxelModeller->SetMaximumDistance(.1);
voxelModeller->SetInputConnection(sphere->GetOutputPort());
voxelModeller->Update();
vtkSmartPointer<vtkImageData> volume = vtkSmartPointer<vtkImageData>::New();
volume->DeepCopy(voxelModeller->GetOutput());
/*vtkSmartPointer<vtkDICOMImageReader> imgs = vtkDICOMImageReader::New();
imgs->SetDirectoryName(folder.c_str());
imgs->Update();
volume->DeepCopy(imgs->GetOutput());*/
vtkSmartPointer<vtkMarchingCubes> surface = vtkMarchingCubes::New();
surface->SetInputData(volume);
surface->ComputeNormalsOn();
surface->SetValue(0, 0.5);
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::New();
mapper->SetInputConnection(surface->GetOutputPort());
mapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> actor = vtkActor::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkRenderer> ren = vtkRenderer::New();
ren->AddActor(actor);
ren->SetBackground(0.1, .2, .3);
vtkSmartPointer<vtkRenderWindow> renWin = vtkRenderWindow::New();
renWin->AddRenderer(ren);
renWin->Render();
vtkSmartPointer<vtkRenderWindowInteractor> irenwin = vtkRenderWindowInteractor::New();
irenwin->SetRenderWindow(renWin);
irenwin->Start();
return 0;
}
两种不同的输入数据,一种是绘制一个球体:
一种是从DICOM图像列;
读取图像然后显示图像好像没有什么麻烦,只是绘制立体图以及参数的设置还是需要学习的。
voxelModeller :将无规则的数据集转化为体素表示。
体素(voxel),是体积元素(volumepixel)的简称。
vtkVoxelModeller默认输出的图像是 VTK_BIT 图像,但是MC不支持这个类型的图像,所以 SetScalarTypeToFloat() 得到一个Float的图像。
当然这边也有其他比较复杂的例子