前言:本博文主要研究mimics中Calculate Parts所采用的方法以及VTK中三维重建的方法,希望对各位小伙伴有所帮助,谢谢!
mimics-Calculate parts - Interpolation
Gray Interpolation
灰度值插值是一种真正的3D插值,它考虑了部分体积效应,因此更准确。使用灰度值插值方法,我们假设骨密度给出了一个像素内骨骼数量的指示。根据灰度值确定表面的所有边缘。另外,这两个像素之间的位置是基于这两个像素的灰度值。
灰度值插值的优点是它提供了大量的细节和尺寸是正确的。缺点是,你得到不必要的细节,由于在图像中的噪声。以大腿骨为例,当使用这个灰度值插值时,你会得到更好的结果(意思是:一个很好的圆润边缘)。当然,你也需要做一些平滑来减少噪音。
然而,重要的是要认识到,灰度值插值并不总是产生良好的结果。当扫描的切片距离明显偏离切片厚度时,得到的网格表面会产生噪声。只有当切片厚度和切片距离相同时,灰度值插值才能很好地工作。在扫描(采集)过程中应满足此条件。因此,Z分辨率的变化(参见关于矩阵缩减的段落)不应与灰度值插值结合使用。降低XY分辨率并不违反该条件。
灰度值插值建议用于CT技术应用。
Contour Interpolation
轮廓插值是在图像平面上平滑扩展到三维空间的二维插值。该插值算法在切片内使用灰度值插值,但在Z方向上使用轮廓之间的线性插值(如下图所示)。这种插值方法为医疗目的提供了最好的结果。
vtkContourFilter
描述:vtkContourFilter是一个过滤器,接受任何数据集的输入并输出等值面或等值线。输出的形式取决于输入数据的维数。若输入数据包含3D单元,则输出等值面。若输入数据包含2D单元,则输出等值线。同样的,若输入数据包含1D或0D,则输出等指点。如果输入维度为混合的,则可以输出混合类型。
ComputeNormal():Set/Get法线的计算。计算法线相当耗费时间和内存。如果输出数据将由修改拓扑或几何的过滤器处理,那么关闭法线和梯度可能是明智的。对于vtkImageData, vtklineargrid, vtkStructuredGrid和vtkUnstructuredGrid输入,此设置默认为On,而对于所有其他输入则为Off。
vtkSynchronizedTemplates3D
描述:用于从结构数据生成等值面。vtkSynchronizedTemplates3D是同步模板算法的3D实现。注意,vtkContourFilter将在适当的时候自动使用这个类。该接口只针对3D图像。
核心函数为ContourImage
根据Image以及设定的Contour值,寻找Contour的边界;
根据添加的点以及所在的位置,建立拓扑关系(拓扑关系基于两个Table进行);
若输入图像为多值图像,即不是二值图像,添加的点会进行插值;
测试代码
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkRenderingVolumeOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include "vtkSmartPointer.h"
#include "vtkCamera.h"
#include "vtkDoubleArray.h"
#include "vtkImageData.h"
#include "vtkImageProperty.h"
#include "vtkImageReslice.h"
#include "vtkImageSincInterpolator.h"
#include "vtkImageSlice.h"
#include "vtkImageSliceMapper.h"
#include "vtkInteractorStyleImage.h"
#include "vtkPNGReader.h"
#include "vtkPointData.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkTestUtilities.h"
#include <vtkImageData.h>
#include <vtkMetaImageReader.h>
#include <vtkContourFilter.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkSTLWriter.h>
#include <vtkSTLReader.h>
#include <vtkPolyDataNormals.h>
#include <vtkStripper.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkImageResliceMapper.h>
#include "zxContourFilter.h"
void CreateColorImage(vtkImageData* image);
int main()
{
vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();
CreateColorImage(image);
zxContourFilter* filter = zxContourFilter::New();
filter->SetInputData(image);
filter->SetValue(0, 4);
//filter->GenerateValues(3, -10., 10.);
filter->Update();
vtkSTLWriter* writer = vtkSTLWriter::New();
writer->SetFileName("F:\\contourPolyData.stl");
writer->SetInputData(filter->GetOutput());
writer->Write();
/*vtkPolyDataNormals* normals = vtkPolyDataNormals::New();
normals->SetInputData(filter->GetOutput());
normals->SetFeatureAngle(60);
normals->SetComputePointNormals(true);
normals->Update();
vtkSTLWriter* writer2 = vtkSTLWriter::New();
writer2->SetFileName("F:\\contourNormals.stl");
writer2->SetInputData(normals->GetOutput());
writer2->Write();
vtkStripper* stripper = vtkStripper::New();
stripper->SetInputData(normals->GetOutput());
stripper->Update();*/
/*vtkSTLWriter* writer3 = vtkSTLWriter::New();
writer3->SetFileName("F:\\contourStripper.stl");
writer3->SetInputData(stripper->GetOutput());
writer3->Write();*/
vtkPolyDataMapper* contourMapper = vtkPolyDataMapper::New();
contourMapper->SetInputData(filter->GetOutput());
vtkActor* contourActor = vtkActor::New();
contourActor->SetMapper(contourMapper);
// Setup renderers
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
//renderer->AddViewProp(imageSlice);
renderer->AddActor(contourActor);
renderer->ResetCamera();
// Setup render window
vtkSmartPointer<vtkRenderWindow> renderWindow = vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(300, 300);
renderWindow->AddRenderer(renderer);
// Setup render window interactor
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
vtkSmartPointer<vtkInteractorStyleTrackballCamera> style =
vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New();
renderWindowInteractor->SetInteractorStyle(style);
// Render and start interaction
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->Render();
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
void CreateColorImage(vtkImageData* image)
{
int directSize = 7;
int zSize = 5;
image->SetDimensions(directSize, directSize, zSize);
image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
for (unsigned int z = 0; z < zSize; z++)
{
for (unsigned int y = 0; y < directSize; y++)
{
for (unsigned int x = 0; x < directSize; x++)
{
unsigned char* pixel = static_cast<unsigned char*>(image->GetScalarPointer(x, y, z));
pixel[0] = 0;
}
}
}
for (unsigned int z = 1; z < 5; z++)
{
for (unsigned int y = z; y < directSize -z; y++)
{
for (unsigned int x = z; x < directSize - z; x++)
{
unsigned char* pixel = static_cast<unsigned char*>(image->GetScalarPointer(x, y, z));
pixel[0] = 4;
}
}
}
}