VTK -更新vtkPolyData在renderWindow没有阻塞交互

VTK - update vtkPolyData in renderWindow without blocking interaction

本文关键字:交互 renderWindow 更新 vtkPolyData VTK      更新时间:2023-10-16

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

下面是我重新创建问题的最小代码。我有一个可视化类来处理这个,它的初始化列表:

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())
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();
}
下面是display函数:
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();
}
}

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

void Visualization::run()
{
    while (1)   // infinite while loop
    {
            // Update m_clouds and display
            display(m_clouds);
    }
}

更新:正如mirni提醒我,"q"键基本上退出当前的renderWindow,我后来看到的实际上是来自display函数,而不是init。在display中,我没有调用renderWindowInteractor->Start(),因此我不能与窗口交互。然而,renderWindowInteractor->Start()卡住了我当前的线程,因此我不能继续我的程序并更新我的vtkPolyData。

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

谢谢!

您的问题的答案是:您只需更新数据并调用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,米罗