VTK笔记-使用vtkTubeFilter类把一条线扩展成一个管腔

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后,线内部交叉部分会设置为非多边形内,这个问题还没有找到为什么;
在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

黑山老妖的笔记本

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值