VTK - 在renderWindow中更新vtkPolyData而不阻止交互

lin*_*bot 3 c++ vtk

我使用VTK显示点云并在循环中更新它.第一次显示云时,窗口可以通过鼠标进行交互,如果我想更新云,我必须按'q',窗口将显示更新的云.但是,虽然云更新并在窗口中正确显示,但我失去了对窗口的控制(即不能使用鼠标移动或旋转窗口中的点云).

以下是重新创建问题的最小代码.我有一个Visualization类来处理它,它的初始化列表:

points(vtkSmartPointer<vtkPoints>::New())
, vertices(vtkSmartPointer<vtkCellArray>::New())
, pointsPolyData(vtkSmartPointer<vtkPolyData>::New())
, mapper(vtkSmartPointer<vtkPolyDataMapper>::New())
, actor(vtkSmartPointer<vtkActor>::New())
, renderer(vtkSmartPointer<vtkRenderer>::New())
, renderWindow(vtkSmartPointer<vtkRenderWindow>::New())
, renderWindowInteractor(vtkSmartPointer<vtkRenderWindowInteractor>::New())
Run Code Online (Sandbox Code Playgroud)

这是init函数:

void Visualization::init(const cv::Mat &point_cloud){
noPoints = point_cloud.cols * point_cloud.rows;

// Preallocate memory
points->SetNumberOfPoints(noPoints);

// Copy
int element_stripe = sizeof(float) * point_cloud.channels();
for (unsigned i = 0; i < noPoints; i++)
{

    float x = point_cloud.at<cv::Vec3f>(i)[0];
    float y = point_cloud.at<cv::Vec3f>(i)[1];
    float z = point_cloud.at<cv::Vec3f>(i)[2];

    vtkIdType pid[1] = {i};
    points->SetPoint(i, x, y, z);
    vertices->InsertNextCell(1, pid);
}

// Push data to polydata
pointsPolyData->SetPoints(points);
pointsPolyData->SetVerts(vertices);


// Set visualization pipeline
mapper->SetInputData(pointsPolyData);
actor->SetMapper(mapper);
actor->GetProperty()->SetPointSize(2);
renderWindow->AddRenderer(renderer);
renderer->SetBackground(.3,.6,.3);
renderWindowInteractor->SetRenderWindow(renderWindow);

renderer->AddActor(actor);
isPipelineInit = true;

renderWindow->Render();
renderWindowInteractor->Start();
}
Run Code Online (Sandbox Code Playgroud)

这是显示功能:

void Visualization::display(const cv::Mat &point_cloud){
if(!isPipelineInit)
    init(point_cloud);
else
{
    // Copy
    int element_stripe = sizeof(float) * point_cloud.channels();
    for (unsigned i = 0; i < noPoints; i++)
    {
        points->SetPoint(i, (float*)(point_cloud.data + i*element_stripe));
    }
    pointsPolyData->Modified();
    mapper->Update();

    renderWindowInteractor->GetRenderWindow()->Render();
}
}
Run Code Online (Sandbox Code Playgroud)

我还有一个在线程中运行无限循环的函数:

void Visualization::run()
{
    while (1)   // infinite while loop
    {
            // Update m_clouds and display
            display(m_clouds);
    }
}
Run Code Online (Sandbox Code Playgroud)

更新: 由于mirni提醒我'q'键基本上退出当前的renderWindow,我后面看到的实际上是来自display函数而不是init.在display我没有打电话renderWindowInteractor->Start(),因此我无法与窗口互动.但是,renderWindowInteractor->Start()卡住了我当前的线程,因此我无法继续我的程序并更新我的vtkPolyData.

我想问题就变成了:我应该如何同时显示和更新?我应该在不同的线程中做,所以一个用于显示而另一个用于更新?

谢谢!

小智 5

您的问题的答案是:您只需更新数据和调用vtkRenderWindow::Render()方法.VTK渲染管道自己发现数据已经改变并且需要更新.

您的代码确实需要重新设计 - 在数据更改时(仅一次)更新可视化更有意义,而不是继续探测数据"有什么改变吗?" (每毫秒).

此外,通常您不需要用于VTK可视化管道的单独线程.把事情简单化:

  • 不要将可视化对象设为线程.(如果你有100个对象怎么办?你会为每个对象创建100个单独的线程吗?).
  • 摆脱无限循环.
  • display(...)方法重命名为
void Visualization::update(const cv::Mat &point_cloud);

通过适合您的场景的任何方式更改数据(回调?Qt信号?消息?...),使其公开并从外部调用它.确保最后保持vtkRenderWindow :: Render()调用.

  • 您可能需要考虑直接从cv :: Mat结构中复制数据,使用指向公开的点数据的原始指针vtkPoints::GetVoidPointer(int)并执行memcopy而不是for循环,但是在您有适当的事情之前不要这样做测量显示需要优化.(过早优化是根...)

  • vtkRenderWindowInteractor::Start()启动一个事件循环并在你发现时劫持线程.而不是Start()只是调用Initialize()启用交互器,但让控制流继续.

HTH,Miro