【问题标题】:Getting better performance using OpenCV?使用 OpenCV 获得更好的性能?
【发布时间】:2011-11-29 04:13:55
【问题描述】:

我需要实时处理,但 OpenCV 的内部功能不提供此功能。我正在做手势识别,它工作得几乎完美,除了结果输出非常滞后和缓慢。我知道这不是因为我的算法,而是因为 OpenCV 的处理时间。我有什么办法可以加快速度吗?

Ps:我不想使用 IPP 库,所以请不要建议。我需要 OpenCV 本身的性能提升

【问题讨论】:

  • 分析openCV代码并亲自查看...
  • 我没有能力或时间去做这正是你问问题的原因
  • 对不起,如果我错过了,重点是 10 次中有 9 次,除非是新功能/错误,否则 OpenCV 代码可能不是问题。如果你在另一边,那么你可以具体点你正在使用的 OpenCV 代码。
  • 好的,谢谢你的帮助:)

标签: c++ performance video opencv


【解决方案1】:

我正在使用一些方法:

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

【讨论】:

    【解决方案2】:

    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 像素进行低级处理,并在其中迭代大部分图像,请使用单个并行处理并避免写入
    • 根据您运行代码的方式,您可以禁用调试以获得更好的性能
    • 如果您正在流式传输和转储帧,最好更改相机设置以限制流式传输速率而不是转储帧
    • 如果您要将 1 位 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 中 SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS)。 h)
    • 优化电源设置以获得最佳性能
    • 禁用 CPU 内核停放
    • 优化采集硬件设置(增加 rx/tx 缓冲区等)以减轻 CPU 的工作负担

    【讨论】:

      【解决方案3】:

      改进图像分析的传统技术:

      1. 将图像缩小为单色样本。
      2. 缩小样本范围,例如从 8 位单色到 4 位单色。
      3. 减小图像的大小,例如1024x1924 到 64x64。
      4. 降低帧速率,例如 60fps 到 5fps。
      5. 执行更高级别的函数来猜测目标区域的位置,比如较低的分辨率,然后对裁剪后的输出执行常规分析,例如在确定手势之前执行图像识别以定位手。

      【讨论】:

      • 1) 我无法将图像设为单色,因为颜色很重要且至关重要 2) 我无法减小深度,因为我的算法依赖于精度 3) 我无法减小程序大小依赖于清晰度 4)我需要更大的图像才能使程序正常运行 5)您能否澄清/扩展一下?因为我不太明白你的建议是什么
      • Steve-o 说话很有智慧。获得良好性能的关键是减少昂贵的操作,而不是更快地进行昂贵的操作。以实践中的建议#5为例;当我跟踪我的机器人车辆时,我只是在最后一帧而不是整个帧中对我发现车辆附近的区域进行图像处理。
      • @fdh 这些是每个解决计算机视觉问题的人都会遇到的相同问题,并且解决方案通常是违反直觉的。您可以用更少的数据获得更好的性能。
      猜你喜欢
      • 1970-01-01
      • 2021-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-13
      • 2011-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多