本文由Markdown语法编辑器编辑完成。
1. 问题提出
在传统的医学软件中,标记测量一般包括距离(distance), 角度(angle), 椭圆或矩形ROI的面积、灰度均值和标准差等。这些测量一般是在MPR的三个切割面上进行的。而在项目进行的过程中,医生提出“想在曲面上测量两个点之间的最短距离”的需求。
这个需求也是临床骨科医生在他们日常使用Mimics软件时经常会使用到的一个测量功能。因此,他们希望我们能够实现一个类似于Mimics的在曲面上寻找最短距离的功能。如图所示:
空间中两点之间当然是直线最短。但是,如果这两个点必须在同一个曲面上,而且它们之间的连线要在曲线表面上时,这时就无法用直线连接了。因为,曲面其实是由很多个三角面片构成的,如三维模型通用的数据存储格式STL文件,里面就是存储中构成这个三维模型的所有的三角面片的顶点值和该三角面片的法向量。
这个问题,归根结底,还是一个数学问题。那就是在一个由很多个点构成的网络图模型中,如何在给定起始点和终止点的条件下,找到这两个点之间的最短路径。
2. 解决方案
之前,由于对数据结构不是特别熟悉,没有想到数据结构中其实已经有非常成熟的寻找最短路径的算法——Dijkstra算法。而且这个算法在VTK中已经有实现。
以下是应用VTK中的vtkDijkstraGraphGeodesicPath类来实现在曲面上任意两点之间寻找最短路径的例子代码。
#include <vtkSphereSource.h>
#include <vtkProperty.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkDijkstraGraphGeodesicPath.h>
#include <vtkSTLReader.h>
int main(int , char *[])
{
// Read a stl file.
vtkSmartPointer<vtkPolyData> input1 =vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkSTLReader> reader1 = vtkSmartPointer<vtkSTLReader>::New();
reader1->SetFileName("E:\\STL\\left_femur.stl");
reader1->Update();
input1->DeepCopy(reader1->GetOutput());
vtkSmartPointer<vtkDijkstraGraphGeodesicPath> dijkstra =
vtkSmartPointer<vtkDijkstraGraphGeodesicPath>::New();
dijkstra->SetInputData(input1);
dijkstra->SetStartVertex(0);
dijkstra->SetEndVertex(250);
dijkstra->Update();
// Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> pathMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
pathMapper->SetInputConnection(dijkstra->GetOutputPort());
vtkSmartPointer<vtkActor> pathActor =
vtkSmartPointer<vtkActor>::New();
pathActor->SetMapper(pathMapper);
pathActor->GetProperty()->SetColor(1,0,0); // 路径用红色的线表示.
pathActor->GetProperty()->SetLineWidth(4);
// Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(input1);
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
//Create a renderer, render window, and interactor
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//Add the actor to the scene
renderer->AddActor(actor);
renderer->AddActor(pathActor);
renderer->SetBackground(.3, .6, .3); // Background color green
//Render and interact
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
以下是在起始点索引为0,结束点在不同的情况下,得到的寻找的最短路径的截图:
EndVertex = 250时的截图:
EndVertex = 3650时的截图:
在将STL模型通过vtkExtractEdges抽取出三维模型的边缘线后,可以看到之前的规划出的最短路径在线框上的走势。
EndVertex = 10000时的截图: