【问题标题】:Poor performance of large number of viz::Widget3D in OpenCVOpenCV 中大量 viz::Widget3D 的性能不佳
【发布时间】:2019-02-26 17:43:28
【问题描述】:

在 OpenCV 中使用数千个 viz::Widget3D 非常慢。我在带有 Visual Studio 2017 的 Windows 上尝试了 v3.4.3 和 v4.0.0。这段代码 sn-p 需要 5 秒来执行定时部分(t0t1),之后查看非常不稳定:

using namespace std;
using namespace cv;

int main()
{
  constexpr double n = 100;

  viz::Viz3d window("Viz3d");

  window.setFullScreen();
  window.showWidget("Coordinate Widget", viz::WCoordinateSystem());
  window.spinOnce();

  auto t0 = chrono::high_resolution_clock::now(); 

  for (double x = 0; x < n; x += 1)
    for (double y = 0; y < n; y += 1) 
      window.showWidget(to_string(x+y*n), viz::WArrow({x, y, 0}, {x+1, y+1, 0}, 0.02, viz::Color::bluberry()));

  auto t1 = chrono::high_resolution_clock::now(); 

  window.spin();

  fmt::print("\nTime: {}ms", chrono::duration_cast<chrono::milliseconds>(t1-t0).count());
  fmt::print("\nVersion {}.{}.{}{}\n", CV_VERSION_MAJOR, CV_VERSION_MINOR, CV_VERSION_REVISION, CV_VERSION_STATUS);
  return 0;
}

小部件管理似乎带来了巨大的开销。有没有其他方法可以以低延迟显示数千个小部件(文本、线条、箭头)?我试过viz::WWidgetMerger,速度更慢。

编辑

顺便说一句,我只需要“立即”模式渲染。我不会在显示小部件后对其进行修改。

【问题讨论】:

  • 成千上万的小部件,我一般认为是性能问题。 viz::Widget3D 听起来有点像 OpenGL。如果每个小部件都管理它自己的 GL 上下文——1000 次上下文切换用于一次更新,那会怎样。恕我直言,这绝对是一个性能问题。你怎么需要这么大的数字?
  • @Scheff 我需要用文本和矢量注释 2D 和 3D 图像的每个像素(体素)。这通常在 VTK 中完成,由 OpenCV 包装以提供viz::Widget3D
  • 可能是,我把Widget 看得太字面意思了。我不确定它是一个小部件(一个小部件集,例如 Qt 中的 QWidget)。出于好奇,我查看了源代码cv::viz::Widget::Impl 并找到了对vtk 的引用。类库,建立在类库之上,建立在类库之上。一切都已经在某个地方完成了-只需将其组合起来即可获得新的东西。缺点:如果遇到性能问题(或无法正常工作),从哪里开始搜索?
  • @DanMašek 我的猜测是一样的:开销在于映射字符串,我不需要。直接使用 VTK 可以解决问题 - 我已经看到了带有数千个箭头的 VTK 可视化,但我目前对攀登 VTK 学习曲线不感兴趣。我问了这个问题是为了确保我不会错过一个简单的cv::viz 解决方案。
  • @DanMašek 我试过viz::WWidgetMerger,性能更差。

标签: c++ opencv visual-c++ visualization vtk


【解决方案1】:

如果您有数千个小部件,则在将所有小部件添加在一起时创建单个 WidgetMerger 将会非常缓慢(如果您要可视化每个单独添加的时间,您会看到指数级的减速)。

但是,如果您改为进行多个合并,则它应该是平滑的,在显示时绝对不会出现断断续续的情况,而在创建时只会有点慢一点。

你可以尝试做类似的事情:

std::vector<viz::WWidgetMerger> mergers(n);
for (double x = 0; x < n; x += 1) {
  viz::WWidgetMerger merger = mergers[x];
  for (double y = 0; y < n; y += 1) {
    merger.addWidget(viz::WArrow({x, y, 0}, {x+1, y+1, 0}, 0.02, viz::Color::bluberry()));
  }
  merger.finalize();
  window.showWidget("merger_" + std::to_string(x), merger);
}

性能差异:

您的代码原样:Time: 2522ms 非常不稳定,几乎无法使用。

使用多次合并:Time: 6097ms 黄油般顺滑,没有波折

使用单个合并:时间 > 5 分钟。我什至没有等它完成它花了这么长时间。

因此,虽然最初在创建小部件时使用多个合并会稍微降低速度,但对于显示性能,我认为这是值得的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    • 1970-01-01
    • 2019-07-25
    相关资源
    最近更新 更多