使用OpenCV如何获得更好的性能?

4
我需要实时处理,但OpenCV的内部功能无法提供此功能。我正在进行手势识别,它几乎完美地工作,但输出结果非常滞后和缓慢。我知道这不是因为我的算法,而是因为OpenCV的处理时间。有什么方法可以加速它吗?
注:我不想使用IPP库,请不要建议。我需要从OpenCV本身获得更高的性能。

1
分析OpenCV代码并亲自试试... - vijiboy
我没有足够的熟练度或时间去做那件事情。 这正是你提问的原因。 - fdh
2
抱歉如果我错过了,但通常情况下,除非是新功能/错误,否则OpenCV代码可能不是问题所在。如果你在另一边,那么你可以具体指出你正在使用的OpenCV代码。 - vijiboy
3个回答

10

提高图像分析的传统技术:

  1. 将图像转换为单色样本。
  2. 减小样本范围,例如从8位单色到4位单色。
  3. 缩小图像尺寸,例如从1024x1924到64x64。
  4. 降低帧率,例如从60fps到5fps。
  5. 使用更高级函数猜测目标区域的位置,并在输出裁剪后对其进行常规分析,例如执行图像识别以定位手部,然后再确定手势。

  1. 我不能将图像变成单色的,因为颜色对于重要性和必要性非常高。
  2. 我不能减少深度,因为我的算法依赖于精度。
  3. 我不能减小尺寸,因为我的程序依赖于清晰度。
  4. 我需要一个更大的图像才能使程序正常运行。
  5. 请问您能否澄清/详细说明一下?因为我不太理解您的建议。
- fdh
2
Steve-o说了一句智慧的话。获得良好性能的关键是尽量减少昂贵的操作,而不是加快昂贵操作的速度。实践建议#5的一个例子是:当我跟踪我的机器人车时,我只对上一帧中发现车辆附近的区域进行图像处理,而不是整个帧。 - Chris Bennet
@fdh 这些都是每个处理计算机视觉问题的人都会遇到的相同问题,解决方案通常是违反直觉的。你可以用更少的数据获得更好的性能。 - Cameron Lowell Palmer

1

Steve-o的回答对于优化代码效率很好。我建议添加一些逻辑来监视执行时间,以帮助您确定在哪里花费优化的努力。

OpenCV时间监控逻辑(Python):

startTime = cv.getTickCount()
# your code execution
time = (cv.getTickCount() - startTime)/ cv.getTickFrequency()

时间监控的增强逻辑:

boost::posix_time::ptime start = boost::posix_time::microsec_clock::local_time();
// do something time-consuming
boost::posix_time::ptime end = boost::posix_time::microsec_clock::local_time();

boost::posix_time::time_duration timeTaken = end - start;
std::cout << timeTaken << std::endl;

根据我的经验,配置OpenCV构建的方式非常重要。 IPP并不是提供更好性能的唯一选择。值得尝试各种构建方式以获得更好的硬件利用效率。

其他需要关注的领域包括CPU和内存利用率。如果你观察CPU和/或内存利用率,你可能会发现你的代码中有10%的部分在工作,而其他时候基本上处于空闲状态。

考虑将逻辑重构为使用线程的管道,以便可以同时处理多个图像(如果正在跟踪并需要先前图像的结果,则需要将代码分成多个段,例如预处理/分析,并使用std :: queue在它们之间进行缓冲,而imshow无法从工作线程工作,因此您需要将结果图像推入队列并从主线程进行imshow)
考虑使用持久/全局对象来存储不需要每次重新创建的内核/检测器等内容
你的吞吐量是否随着程序运行时间的增加而减慢?您可能需要查看如何处理主循环范围内的图像/变量的处理方式
将代码分割成函数使其更易于阅读,更易于基准测试,并且更早地取消变量(临时Mat和结果变量在取消范围时释放内存)
如果您正在对Mat像素进行低级处理,并迭代大部分图像,请使用单个并行for并避免编写
根据您运行代码的方式,您可以禁用调试以获得更好的性能
如果您正在流式传输和转储帧,请优先更改相机设置以限制流速,而不是转储帧
如果您正在将12位转换为8位或仅使用图像的某个区域,请优先在相机硬件级别执行此操作
这是一个并行for循环的例子:
cv::parallel_for_(cv::Range(0, img.rows * img.cols), [&](const cv::Range& range)
{
    for (int r = range.start; r < range.end; r++)
    {
        int x = r / img.rows;
        int y = r % img.rows;
        uchar pixelVal = img.at<uchar>(y, x);
        //do work here
    }
});

如果硬件受限(即CPU和/或内存完全被利用),则需要考虑优化进程/操作系统性能/释放系统资源/升级硬件。
  • 增加进程的优先级,使其相对于计算机上运行的其他程序更加贪婪(在Linux中,您可以使用unistd.h中的nice(int inc),在Windows中,您可以使用windows.h中的SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS))
  • 优化电源设置以获得最佳性能
  • 禁用CPU核心停靠
  • 优化采集硬件设置(增加rx / tx缓冲区等),以减轻CPU的工作负担

0

我正在使用一些方法:

  1. [应用程序级别] 对于支持OpenCL的硬件:从cv :: Mat到cv :: UMat并设置cv :: ocl :: setUseOpenCL(true)
  2. [库级别] 在OpenCV CMake中使用另一个并行库:TBB可能比openmp更好
  3. [库级别] 在OpenCV CMake中启用OpenCV中的IPP支持
  4. [应用程序级别] 缓存临时结果。 OpenCV中的大多数函数都会检查输出数组的格式和大小。因此,您可以将所有结果存储为私有成员中的cv :: Mat,并在下一帧上,OpenCV将不会为它们分配和释放内存。
  5. [库 -> 应用程序级别] 放置瓶颈OpenCV函数的源代码,并为其应用punkt [4]。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接