vtkTubeFilter类
vtkTubeFilter是一种在每条输入线周围生成一个管的过滤器。管由三角形条带组成,并随着线法线的旋转围绕管旋转。(如果不存在法线,则会自动计算法线。)可以将管的半径设置为随标量或矢量值而变化。如果半径随标量值变化,则将线性调整半径。如果半径随矢量变化,则使用质量流量保持变化。如果半径按向量范数变化,则半径将线性调整为其范数。还可以指定管的边数。还可以指定哪些边是可见的。这对于生成有趣的条带效果非常有用。其他选项包括为管状体加盖和生成纹理坐标的功能。纹理坐标可以与关联的纹理贴图一起使用,以创建有趣的效果,例如使用与长度或时间对应的条纹标记管。
相邻一组圆上的点,一一对应连接成一条三角带,就形成了管腔的侧面片元;
此过滤器通常用于创建粗线条或戏剧性线条。另一个常见的用途是将此过滤器与vtkStreamTracer组合以生成流管。
警告
管侧的数量必须大于3。如果希望使用较少的边(即功能区),请使用vtkRibbonFilter。
输入线不得有重复点,也不得在平行于输入/输出线段的点上有法线。(可以使用vtkCleanPolyData删除重复的点。)如果某条线不符合此标准,则该线不会被管化。
在医学处理中的应用,可以根据医生绘制的曲线生成闭合的管子,进一步统计管子内的体素的CT值或者灰度值。
示例
下面假设我们要跟据一条曲线生成管腔,然后统计管腔内的数值;
vtkNew<vtkNamedColors> colors;
double origin[3] = { 0.0, 0.0, 0.0 };
double p0[3] = { 1,0,0 };
double p1[3] = { 1,1,0 };
double p2[3] = { 1,1,1 };
double p3[3] = { 0,-1,0 };
// Create a vtkPoints object and store the points in it
vtkNew<vtkPoints> points;
points->InsertNextPoint(origin);
points->InsertNextPoint(p0);
points->InsertNextPoint(p1);
points->InsertNextPoint(p2);
points->InsertNextPoint(p3);
vtkNew<vtkParametricSpline> spline;
spline->SetPoints(points);
vtkNew<vtkParametricFunctionSource> functionSource;
functionSource->SetParametricFunction(spline);
functionSource->Update();
vtkNew<vtkTubeFilter> Tube;
Tube->SetInputConnection(functionSource->GetOutputPort());
Tube->SetRadius(0.5);
Tube->SetNumberOfSides(20);
Tube->CappingOn();
Tube->SidesShareVerticesOn();
Tube->Update();
// Setup actor and mapper
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(Tube->GetOutputPort());
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0, 1, 0);
// Setup render window, renderer, and interactor
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->SetBackground(colors->GetColor3d("Silver").GetData());
renderWindow->Render();
renderWindowInteractor->Start();
代码内生成的管子有交叠时:
使用CappingOn
将管子两头闭合:
将SetRadius
设置为0.01
时:
将SetRadius
设置为0.5
时:
之前使用的坐标,管子没有交叠:
double origin[3] = { 0.0, 0.0, 0.0 };
double p0[3] = { 0,3,2 };
double p1[3] = { 5,4.4,3.6 };
double p2[3] = { 10,4.4,4.2 };
double p3[3] = { 15,4.4,4.8 };
根据之前的笔记VTK笔记-图形相关-多边形数据转换图像数据-vtkPolyData转换为vtkImageData将管腔转换为vtkImageData
的Mask数据;
vtkNew<vtkNamedColors> colors;
double p0[3] = { 0.0, 0.0, 0.0 };
double p1[3] = { 1,0,0 };
double p2[3] = { 1,1,0 };
double p3[3] = { 1,1,1 };
double p4[3] = { 0,-1,0 };
// Create a vtkPoints object and store the points in it
vtkNew<vtkPoints> points;
points->InsertNextPoint(p0);
points->InsertNextPoint(p1);
points->InsertNextPoint(p2);
points->InsertNextPoint(p3);
points->InsertNextPoint(p4);
vtkNew<vtkParametricSpline> spline;
spline->SetPoints(points);
vtkNew<vtkParametricFunctionSource> functionSource;
functionSource->SetParametricFunction(spline);
functionSource->Update();
vtkNew<vtkTubeFilter> Tube;
Tube->SetInputConnection(functionSource->GetOutputPort());
Tube->SetRadius(0.5);
Tube->SetNumberOfSides(20);
Tube->CappingOn();
Tube->SidesShareVerticesOn();
Tube->Update();
// Setup actor and mapper
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputConnection(Tube->GetOutputPort());
auto pd = Tube->GetOutput();
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0, 1, 0);
vtkNew<vtkImageData> whiteImage;
double bounds[6];
pd->GetBounds(bounds);
double spacing[3]; // desired volume spacing
spacing[0] = 0.1;
spacing[1] = 0.1;
spacing[2] = 0.1;
whiteImage->SetSpacing(spacing);
// compute dimensions
int dim[3];
for (int i = 0; i < 3; i++) {
dim[i] = static_cast<int>(ceil((bounds[i * 2 + 1] - bounds[i * 2]) / spacing[i]));
}
whiteImage->SetDimensions(dim);
whiteImage->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);
double origin[3];
origin[0] = bounds[0] + spacing[0] / 2;
origin[1] = bounds[2] + spacing[1] / 2;
origin[2] = bounds[4] + spacing[2] / 2;
whiteImage->SetOrigin(origin);
whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
unsigned char inval = 255;
unsigned char outval = 0;
vtkIdType count = whiteImage->GetNumberOfPoints();
for (vtkIdType i = 0; i < count; ++i) {
whiteImage->GetPointData()->GetScalars()->SetTuple1(i, i);
}
// polygonal data --> image stencil:
vtkNew<vtkPolyDataToImageStencil> pol2stenc;
pol2stenc->SetInputData(pd);
pol2stenc->SetOutputOrigin(origin);
pol2stenc->SetOutputSpacing(spacing);
pol2stenc->SetOutputWholeExtent(whiteImage->GetExtent());
pol2stenc->Update();
// cut the corresponding white image and set the background:
vtkNew<vtkImageStencil> imgstenc;
imgstenc->SetInputData(whiteImage);
imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
imgstenc->ReverseStencilOff();
imgstenc->SetBackgroundValue(outval);
imgstenc->Update();
vtkNew<vtkGPUVolumeRayCastMapper> gpuMapper;
gpuMapper->SetInputData(imgstenc->GetOutput());
gpuMapper->SetMaskTypeToBinary();
gpuMapper->SetMaskInput(NULL);
vtkPiecewiseFunction * psfunction = vtkPiecewiseFunction::New();
//透明度传递函数
psfunction->AddPoint(0.0, 0.0);
psfunction->AddPoint(40.0, 0.0);
psfunction->AddPoint(50.0, 0.3);
psfunction->AddPoint(110.0, 0.4);
psfunction->AddPoint(120, 0.5);
psfunction->AddPoint(130, 0.6);
psfunction->AddPoint(190, 0.8);
psfunction->AddPoint(255, 1.0);
vtkColorTransferFunction * colfunction = vtkColorTransferFunction::New();
//颜色传递函数
colfunction->AddRGBPoint(0.0, 0.5, 0.3, 0.2);
colfunction->AddRGBPoint(50.0, 0.8, 0.5, 0.5);
colfunction->AddRGBPoint(110.0, 0.6, 0.2, 0.3);
colfunction->AddRGBPoint(190.0, 0.81, 0.27, 0.1);
colfunction->AddRGBPoint(255.0, 0.5, 0.9, 0.9);
vtkVolumeProperty * volpro = vtkVolumeProperty::New();
//体数据属性
volpro->SetColor(colfunction);
volpro->SetScalarOpacity(psfunction);
volpro->ShadeOn();
volpro->SetInterpolationTypeToLinear();
vtkVolume * data = vtkVolume::New();
//体数据映射器和属性
data->SetMapper(gpuMapper);
data->SetProperty(volpro);
// Setup render window, renderer, and interactor
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renderWindow;
renderWindow->AddRenderer(renderer);
vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
renderWindowInteractor->SetRenderWindow(renderWindow);
//renderer->AddActor(actor);
renderer->AddVolume(data);
renderer->SetBackground(0, 0, 0);
renderer->ResetCameraClippingRange();
renderer->SetBackground(colors->GetColor3d("Silver").GetData());
renderWindow->Render();
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
生成vtkImageData
后,线内部交叉部分会设置为非多边形内,这个问题还没有找到为什么;