在使用VMTK血管中心线提取之后,实现内窥镜的漫游: VTK(四)—VMTK血管中心线提取
本文测试模型: lumen.stl: https://github.com/jackyko1991/Vessel-Centerline-Extraction/tree/master/test_data/right
前言
对提取的中心线进行曲线插值,使得路径平滑,并跟随中心线完成内窥镜的漫游。
实现效果:
代码
CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(EndoRoaming LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package( Eigen3 REQUIRED )
find_package( VMTK REQUIRED)
include(${VMTK_USE_FILE})
find_package( ITK REQUIRED)
include(${ITK_USE_FILE})
find_package( VTK 8.1.2 EXACT REQUIRED)
include(${VTK_USE_FILE})
include_directories(${EIGEN3_INCLUDE_DIR})
add_executable(EndoRoaming endoroaming.cpp)
target_link_libraries(EndoRoaming ${VTK_LIBRARIES})
endoroaming.cpp:
#include <vtkSmartPointer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkProperty.h>
#include <vtkAxesActor.h>
#include <vtkSTLReader.h>
#include <vtkDiscreteMarchingCubes.h>
#include <vtkWindowedSincPolyDataFilter.h>
#include <vtkCleanPolyData.h>
#include <vtkTriangleFilter.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkDataArray.h>
#include <vtkIdList.h>
#include <vtkDecimatePro.h>
#include <vtkDoubleArray.h>
#include <vtkParametricSpline.h>
#include <vtkParametricFunctionSource.h>
#include <vtkLODActor.h>
#include <vtkKochanekSpline.h>
#include <vtkvmtkCapPolyData.h>
#include <vtkvmtkPolyDataCenterlines.h>
#include <Eigen/Core>
#include <Eigen/Eigen>
#include <unistd.h>
#include <iostream>
vtkSmartPointer<vtkPolyData> ExtractCenterline(vtkSmartPointer<vtkPolyData> inputSurface) {
vtkSmartPointer<vtkPolyData> cappedSurface = vtkSmartPointer<vtkPolyData>::New();
vtkSmartPointer<vtkCleanPolyData>surfaceCleaner = vtkSmartPointer<vtkCleanPolyData>::New();
surfaceCleaner->SetInputData(inputSurface);
surfaceCleaner->Update();
vtkSmartPointer < vtkTriangleFilter> surfaceTriangulator = vtkSmartPointer<vtkTriangleFilter>::New();
surfaceTriangulator->SetInputConnection(surfaceCleaner->GetOutputPort());
surfaceTriangulator->PassLinesOff();
surfaceTriangulator->PassVertsOff();
surfaceTriangulator->Update();
cappedSurface->DeepCopy(surfaceTriangulator->GetOutput());
vtkSmartPointer<vtkvmtkCapPolyData> capper = vtkSmartPointer<vtkvmtkCapPolyData>::New();
capper->SetInputData(cappedSurface);
capper->Update();
vtkSmartPointer<vtkIdList> CapCenterIds = vtkSmartPointer<vtkIdList>::New();
cappedSurface->DeepCopy(capper->GetOutput());
CapCenterIds->DeepCopy(capper->GetCapCenterIds());
cout<<"The number of the lumen is:" <<capper->GetCapCenterIds()->GetNumberOfIds()<<endl;
vtkSmartPointer<vtkIdList> sourceIds = vtkSmartPointer<vtkIdList>::New();
sourceIds->SetNumberOfIds(1);
sourceIds->SetId(0, CapCenterIds->GetId(0));
vtkSmartPointer<vtkIdList> targetIds = vtkSmartPointer<vtkIdList>::New();
targetIds->SetNumberOfIds(1);
targetIds->SetId(0, CapCenterIds->GetId(2));
vtkSmartPointer<vtkvmtkPolyDataCenterlines> centerlinesFilter = vtkSmartPointer<vtkvmtkPolyDataCenterlines>::New();
centerlinesFilter->SetInputData(cappedSurface);
centerlinesFilter->SetSourceSeedIds(sourceIds);
centerlinesFilter->SetTargetSeedIds(targetIds);
centerlinesFilter->SetAppendEndPointsToCenterlines(true);
centerlinesFilter->SetCenterlineResampling(true);
centerlinesFilter->SetResamplingStepLength(1);
centerlinesFilter->SetRadiusArrayName("Radius");
centerlinesFilter->SetEdgeArrayName("Edge");
centerlinesFilter->SetEdgePCoordArrayName("PCoord");
centerlinesFilter->Update();
vtkSmartPointer<vtkPolyData> output = centerlinesFilter->GetOutput();
return output;
}
int main(int argc,char**argv)
{
if(argc<2)
{
std::cout<<"please input a model\n";
return -1;
}
std::string source = argv[1];
vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName(source.c_str());
reader->Update();
vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(reader->GetOutputPort());
mapper->Update();
vtkSmartPointer<vtkPolyData> data = vtkSmartPointer<vtkPolyData>::New();
data->DeepCopy(reader->GetOutput());
vtkSmartPointer<vtkPoints> pathpoints = vtkSmartPointer<vtkPoints>::New();
pathpoints->DeepCopy(ExtractCenterline(data)->GetPoints());
cout<<"The number of points:"<<pathpoints->GetNumberOfPoints()<<endl;
vtkNew<vtkKochanekSpline> xSpline;
vtkNew<vtkKochanekSpline> ySpline;
vtkNew<vtkKochanekSpline> zSpline;
vtkSmartPointer<vtkParametricSpline> spline = vtkSmartPointer<vtkParametricSpline>::New();
spline->SetXSpline(xSpline);
spline->SetYSpline(ySpline);
spline->SetZSpline(zSpline);
spline->SetPoints(pathpoints);
vtkSmartPointer<vtkParametricFunctionSource> functionSource = vtkSmartPointer<vtkParametricFunctionSource>::New();
functionSource->SetParametricFunction(spline);
functionSource->SetUResolution(10 * pathpoints->GetNumberOfPoints());
functionSource->SetVResolution(10 * pathpoints->GetNumberOfPoints());
functionSource->SetWResolution(10 * pathpoints->GetNumberOfPoints());
functionSource->Update();
vtkSmartPointer<vtkPoints> newPoints = vtkSmartPointer<vtkPoints>::New();
int NumberInsertPoints = 10 * pathpoints->GetNumberOfPoints();
double ratioSpeed = 1.0/(NumberInsertPoints-1);
for(int i = 0; i < NumberInsertPoints; i++)
{
double u[] = {i*ratioSpeed, 0, 0};
double p[3];
spline->Evaluate(u, p, nullptr);
newPoints->InsertNextPoint(p);
}
cout<<"The number of new points:"<<newPoints->GetNumberOfPoints()<<endl;
vtkSmartPointer<vtkPolyDataMapper> pointMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
pointMapper->SetInputConnection(functionSource->GetOutputPort());
vtkSmartPointer<vtkLODActor> actorPoints = vtkSmartPointer<vtkLODActor>::New();
actorPoints->SetMapper(pointMapper);
actorPoints->GetProperty()->SetColor(0,1,0);
actorPoints->GetProperty()->SetLineWidth(2);
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkProperty> property = vtkSmartPointer<vtkProperty>::New();
property->SetDiffuseColor(1, 0.49, 0.25);
property->SetDiffuse(0.7);
property->SetSpecular(0.3);
property->SetSpecularPower(20);
property->SetOpacity(0.9);
actor->SetProperty(property);
vtkSmartPointer<vtkAxesActor> actor2 = vtkSmartPointer<vtkAxesActor>::New();
actor2->SetPosition(0, 0, 0);
actor2->SetTotalLength(100, 100, 100);
actor2->SetShaftType(0);
actor2->SetAxisLabels(0);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->AddActor(actor2);
renderer->AddActor(actorPoints);
renderer->SetBackground(0.1,0.2,0.4);;
vtkSmartPointer<vtkRenderWindow> renderWindow =vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(1920,1080);
vtkSmartPointer<vtkCamera> aCamera = vtkSmartPointer<vtkCamera>::New();
while(true)
{
for(int i=0;i<newPoints->GetNumberOfPoints()-1;i++)
{
double* point = new double[3];
double* NextPoint = new double[3];
newPoints->GetPoint(i,point);
newPoints->GetPoint(i+1,NextPoint);
Eigen::Vector3d lastPosition(point[0],point[1],point[2] );
Eigen::Vector3d NextPosition(NextPoint[0],NextPoint[1],NextPoint[2] );
Eigen::Vector3d focalPoint = NextPosition + (NextPosition - lastPosition)*1.0;
aCamera->SetPosition ( lastPosition[0], lastPosition[1], lastPosition[2] );
aCamera->SetFocalPoint( focalPoint[0], focalPoint[1], focalPoint[2] );
aCamera->SetViewUp ( 0, -1, 0);
aCamera->ComputeViewPlaneNormal();
renderer->SetActiveCamera(aCamera);
renderWindow->Render();
usleep(30*1000);
}
return 0;
}
}
|