12. VTK上选取点(VTK7版本+VTK9版本)

这个专栏是用于记录我在学习VTK过程中的一些心得体会。参考的资料主要有以下三个:

1. 张晓东 罗火灵《VTK图形图像开发进阶》
2. https://examples.vtk.org/site/
3. 沈子恒 《VTK 三维数据渲染进阶》

遇到的一个大问题就是由于版本更新,这些资料中很多代码无法正常运行,需要进行一定的修改,所以这个专栏会记录下来我修改后的程序代码,以便于我之后温习。也希望能给和我有同样困扰的小伙伴们一些帮助。

我使用的版本:VTK9 + VS2022

VTK上选取点这个例子我主要是参考了官网的程序代码examples.vtk.org/site/Cxx/Picking/CellPicking/  。

这个在我正在做的医学图像项目VS2022联合Qt5开发学习8(QT5.12.3联合VTK7在VS2022上开发医学图像项目3——医学图像可视化)-CSDN博客的后续功能上有用到,所以在这里记录一下。

VTK9版本

#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkActor.h>
#include <vtkCellPicker.h>
#include <vtkDataSetMapper.h>
#include <vtkExtractSelection.h>
#include <vtkIdTypeArray.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlaneSource.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkSmartPointer.h>
#include <vtkTriangleFilter.h>
#include <vtkUnstructuredGrid.h>

namespace {

    // Catch mouse events.
    class MouseInteractorStyle : public vtkInteractorStyleTrackballCamera
    {
    public:
        static MouseInteractorStyle* New();

        MouseInteractorStyle()
        {
            selectedMapper = vtkSmartPointer<vtkDataSetMapper>::New();
            selectedActor = vtkSmartPointer<vtkActor>::New();
        }

        virtual void OnLeftButtonDown() override
        {
            vtkNew<vtkNamedColors> colors;

            // Get the location of the click (in window coordinates).
            int* pos = this->GetInteractor()->GetEventPosition();

            vtkNew<vtkCellPicker> picker;
            picker->SetTolerance(0.0005);

            // Pick from this location.
            picker->Pick(pos[0], pos[1], 0, this->GetDefaultRenderer());

            double* worldPosition = picker->GetPickPosition();
            std::cout << "Cell id is: " << picker->GetCellId() << std::endl;

            if (picker->GetCellId() != -1)
            {

                std::cout << "Pick position is: (" << worldPosition[0] << ", "
                    << worldPosition[1] << ", " << worldPosition[2] << ")" << endl;

                vtkNew<vtkIdTypeArray> ids;
                ids->SetNumberOfComponents(1);
                ids->InsertNextValue(picker->GetCellId());

                vtkNew<vtkSelectionNode> selectionNode;
                selectionNode->SetFieldType(vtkSelectionNode::CELL);
                selectionNode->SetContentType(vtkSelectionNode::INDICES);
                selectionNode->SetSelectionList(ids);

                vtkNew<vtkSelection> selection;
                selection->AddNode(selectionNode);

                vtkNew<vtkExtractSelection> extractSelection;
                extractSelection->SetInputData(0, this->Data);
                extractSelection->SetInputData(1, selection);
                extractSelection->Update();

                // In selection
                vtkNew<vtkUnstructuredGrid> selected;
                selected->ShallowCopy(extractSelection->GetOutput());

                std::cout << "Number of points in the selection: "
                    << selected->GetNumberOfPoints() << std::endl;
                std::cout << "Number of cells in the selection : "
                    << selected->GetNumberOfCells() << std::endl;
                selectedMapper->SetInputData(selected);
                selectedActor->SetMapper(selectedMapper);
                selectedActor->GetProperty()->EdgeVisibilityOn();
                selectedActor->GetProperty()->SetColor(
                    colors->GetColor3d("Tomato").GetData());

                selectedActor->GetProperty()->SetLineWidth(3);

                this->Interactor->GetRenderWindow()
                    ->GetRenderers()
                    ->GetFirstRenderer()
                    ->AddActor(selectedActor);
            }
            // Forward events.
            vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
        }

        vtkSmartPointer<vtkPolyData> Data;
        vtkSmartPointer<vtkDataSetMapper> selectedMapper;
        vtkSmartPointer<vtkActor> selectedActor;
    };

    vtkStandardNewMacro(MouseInteractorStyle);

} // namespace

int main(int, char* [])
{
    vtkNew<vtkNamedColors> colors;

    vtkNew<vtkPlaneSource> planeSource;
    planeSource->Update();

    vtkNew<vtkTriangleFilter> triangleFilter;
    triangleFilter->SetInputConnection(planeSource->GetOutputPort());
    triangleFilter->Update();

    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputConnection(triangleFilter->GetOutputPort());

    vtkNew<vtkActor> actor;
    actor->GetProperty()->SetColor(colors->GetColor3d("SeaGreen").GetData());
    actor->SetMapper(mapper);

    vtkNew<vtkRenderer> renderer;
    vtkNew<vtkRenderWindow> renderWindow;
    renderWindow->AddRenderer(renderer);
    renderWindow->SetWindowName("CellPicking");

    vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
    renderWindowInteractor->SetRenderWindow(renderWindow);
    renderWindowInteractor->Initialize();

    // Set the custom stype to use for interaction.
    vtkNew<MouseInteractorStyle> style;
    style->SetDefaultRenderer(renderer);
    style->Data = triangleFilter->GetOutput();

    renderWindowInteractor->SetInteractorStyle(style);

    renderer->AddActor(actor);
    renderer->ResetCamera();

    renderer->SetBackground(colors->GetColor3d("PaleTurquoise").GetData());

    renderWindow->Render();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

官网的代码,直接就可以用了。

运行结果

VTK上选取点

 

VTK7版本

因为我的医学图像项目用的是VTK7,上面的代码如果直接放在VTK7上大概会报十个错,主要问题是不存在从 XXX到 XXX的适当转换函数。


所以我又修改了一下代码,让它能在VTK7下正常运行。修改方法主要是用 .GetPointer() 方法获取指向对象的指针,并将其传递给需要原始指针的函数或方法。

#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkActor.h>
#include <vtkCellPicker.h>
#include <vtkDataSetMapper.h>
#include <vtkExtractSelection.h>
#include <vtkIdTypeArray.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPlaneSource.h>
#include <vtkPoints.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkRendererCollection.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkSmartPointer.h>
#include <vtkTriangleFilter.h>
#include <vtkUnstructuredGrid.h>

namespace {

    // Catch mouse events.
    class MouseInteractorStyle : public vtkInteractorStyleTrackballCamera
    {
    public:
        static MouseInteractorStyle* New();

        MouseInteractorStyle()
        {
            selectedMapper = vtkSmartPointer<vtkDataSetMapper>::New();
            selectedActor = vtkSmartPointer<vtkActor>::New();
        }

        virtual void OnLeftButtonDown() override
        {
            vtkNew<vtkNamedColors> colors;

            // Get the location of the click (in window coordinates).
            int* pos = this->GetInteractor()->GetEventPosition();

            vtkNew<vtkCellPicker> picker;
            picker->SetTolerance(0.0005);

            // Pick from this location.
            picker->Pick(pos[0], pos[1], 0, this->GetDefaultRenderer());

            double* worldPosition = picker->GetPickPosition();
            std::cout << "Cell id is: " << picker->GetCellId() << std::endl;

            if (picker->GetCellId() != -1)
            {

                std::cout << "Pick position is: (" << worldPosition[0] << ", "
                    << worldPosition[1] << ", " << worldPosition[2] << ")" << endl;

                vtkNew<vtkIdTypeArray> ids;
                ids->SetNumberOfComponents(1);
                ids->InsertNextValue(picker->GetCellId());

                vtkNew<vtkSelectionNode> selectionNode;
                selectionNode->SetFieldType(vtkSelectionNode::CELL);
                selectionNode->SetContentType(vtkSelectionNode::INDICES);
                selectionNode->SetSelectionList(ids.GetPointer()); // 使用 .GetPointer() 获取指针

                vtkNew<vtkSelection> selection;
                selection->AddNode(selectionNode.GetPointer());

                vtkNew<vtkExtractSelection> extractSelection;
                extractSelection->SetInputData(0, this->Data.GetPointer());
                extractSelection->SetInputData(1, selection.GetPointer());
                extractSelection->Update();

                // In selection
                vtkNew<vtkUnstructuredGrid> selected;
                selected->ShallowCopy(extractSelection->GetOutput());

                std::cout << "Number of points in the selection: "
                    << selected->GetNumberOfPoints() << std::endl;
                std::cout << "Number of cells in the selection : "
                    << selected->GetNumberOfCells() << std::endl;
                selectedMapper->SetInputData(selected.GetPointer());
                selectedActor->SetMapper(selectedMapper);
                selectedActor->GetProperty()->EdgeVisibilityOn();
                selectedActor->GetProperty()->SetColor(
                    colors->GetColor3d("Tomato").GetData());

                selectedActor->GetProperty()->SetLineWidth(3);

                this->Interactor->GetRenderWindow()
                    ->GetRenderers()
                    ->GetFirstRenderer()
                    ->AddActor(selectedActor);
            }
            // Forward events.
            vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
        }

        vtkSmartPointer<vtkPolyData> Data;
        vtkSmartPointer<vtkDataSetMapper> selectedMapper;
        vtkSmartPointer<vtkActor> selectedActor;
    };

    vtkStandardNewMacro(MouseInteractorStyle);

} // namespace

int main(int, char* [])
{
    vtkNew<vtkNamedColors> colors;

    vtkNew<vtkPlaneSource> planeSource;
    planeSource->Update();

    vtkNew<vtkTriangleFilter> triangleFilter;
    triangleFilter->SetInputConnection(planeSource->GetOutputPort());
    triangleFilter->Update();

    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputConnection(triangleFilter->GetOutputPort());
    vtkMapper* mapperRawPtr = mapper.GetPointer();  // 获取指针

    vtkNew<vtkActor> actor;
    vtkProp* actorRawPtr = actor.GetPointer();
    actor->GetProperty()->SetColor(colors->GetColor3d("SeaGreen").GetData());
    actor->SetMapper(mapperRawPtr);


    vtkNew<vtkRenderer> renderer;
    vtkRenderer* rendererRawPtr = renderer.GetPointer();  // 获取指针
    vtkNew<vtkRenderWindow> renderWindow;
    renderWindow->AddRenderer(rendererRawPtr);
    renderWindow->SetWindowName("CellPicking");

    vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
    vtkRenderWindow* renderWindowRawPtr = renderWindow.GetPointer();
    renderWindowInteractor->SetRenderWindow(renderWindowRawPtr);
    renderWindowInteractor->Initialize();

    // Set the custom stype to use for interaction.
    vtkNew<MouseInteractorStyle> style;
    vtkInteractorObserver* styleRawPtr = style.GetPointer();
    style->SetDefaultRenderer(rendererRawPtr);
    style->Data = triangleFilter->GetOutput();
    renderWindowInteractor->SetInteractorStyle(styleRawPtr);



    renderer->AddActor(actorRawPtr);
    renderer->ResetCamera();

    renderer->SetBackground(colors->GetColor3d("PaleTurquoise").GetData());

    renderWindow->Render();
    renderWindowInteractor->Start();

    return EXIT_SUCCESS;
}

不过我这么修改之后还是有个问题,运行之后是这个样子。

VTK7上选取点

 

感觉vtkCellPicker用起来还是没什么问题的,vtkTriangleFilter那里有点问题,再就是颜色那里可能VTK7里没有一些VTK9里设置的特殊颜色。颜色这里可以这么修改:

    vtkNew<vtkActor> actor;
    vtkProp* actorRawPtr = actor.GetPointer();
    //actor->GetProperty()->SetColor(colors->GetColor3d("SeaGreen").GetData());

    vtkColor3d myColor;
    myColor.Set(0.5, 0.8, 0.2); // 设置 RGB 值,范围在 [0, 1]

    actor->GetProperty()->SetColor(myColor.GetData());

这里注释掉的是原代码,下面三行是我自己设的颜色,后面涉及到颜色的地方也可以按照这个修改。

 

还有一个问题是,不管是VTK9还是VTK7版本的代码,运行时取点都不是很灵便,原因可能是这里

            vtkNew<vtkCellPicker> picker;
            picker->SetTolerance(0.0005);

vtkCellPicker 是 VTK 提供的一个类,用于执行这种拾取操作。SetTolerance 方法用于设置 vtkCellPicker 对象的拾取容差。拾取容差是一个浮点数,用于控制拾取操作的精度。SetTolerance 方法的参数是一个介于 0 和 1 之间的浮点数,表示拾取容差的大小。默认值是 0.025,这通常对于大多数应用来说已经足够了。在这个代码拾取容差设置为了 0.0005,拾取操作是非常精确了,但可能会更难拾取到对象。这个就看后期个人需求自己改值吧。

 版本问题真的是很闹心哇。联想到最近一段时间都在头秃地改怎么在.stl图像上取点做切面然后实时更新,总是出问题,很难不怀疑是版本的锅。可是我现在一定得用VTK7,不然就得大改代码 ORZ。如果有朋友有比较好的用VTK7在qvtkWidget显示的.stl三维图像上取点做切面解决方案,欢迎在这个博客下留言(TAT帮帮我,琢磨了好几天了,头发要被我自己揪秃了)。

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值