【问题标题】:In-place RGB->BGR color conversion is slower in OpenCV在 OpenCV 中就地 RGB->BGR 颜色转换较慢
【发布时间】:2021-08-05 13:52:04
【问题描述】:

OpenCV中的就地RGB->BGR颜色转换例程是否节省了一些内存,但需要更长的时间?如果是,谁能解释为什么?

我的应用程序调用 OpenCV(4.2.0 版)中的 cv::cvtColor(srcMat, dstMat, cv::COLOR_RGB2BGR) 例程。为了使应用程序更快,我尝试了该例程的就地版本(通过使用相同的 Mat 对象来调用源和目标)。我预计速度会略有提高,因为就地版本不会分配新内存。

为了测试我的预期,我在 10,000 个 250x250 RGB 图像上循环运行我的应用程序。令我惊讶的是,当使用就地版本时,我的应用程序变慢了。其实我看到图片越大(500x500 vs 250x250),in-place 版和普通版的差别就越大。

这是预期的吗?如果是这样,是不是因为in-place版本做了一个swap操作(更多语句),而普通版本只是一个copy操作?

有人愿意尝试重现这种行为吗?通过以 2 种不同的方式对以下 sn-p 进行计时,可以轻松完成:1) 使用下面的 sn-p,以及 2) 按照 sn-p 中 cmets 中的简要说明进行就地版本。

// Read image
Mat srcMat = imread(filename);

// Comment out this line for the in-place version
Mat dstMat;

for (int i=0; i<10000; i++)
{
  // Use srcMat instead of dstMat in the in-place version
  cv::cvtColor(srcMat, dstMat, cv::COLOR_RGB2BGR);
}

谢谢。

【问题讨论】:

  • 您在哪个 CPU 上遇到此问题,甚至可能是操作系统?您使用的是哪种 OpenCV 版本? |好问题,但很难回答。
  • CPU:Intel(R) Xeon(R) CPU E5-2450 v2 @ 2.50GHz。它有 16 个超线程内核。我的应用程序运行 32 个线程,每个(并行)线程处理一个图像。操作系统:Unix。使用 ICC 编译器优化 OpenCV 构建。
  • 我猜这是某种处理循环中的操作。在这种情况下,我只需要一个在迭代中持续存在的Mat,而不是就地执行它,并将其用作cvtColor 的目的地。只要目标具有正确的数据类型和大小,它就不会被重新分配。通常是这种情况,额外的内存不太可能是关键的。 |哦,其中 32 个并行,我想在那种情况下它可能更重要:)
  • 由于loop carried dependencies,就地处理阻止了一些编译(和执行)优化。我不能说这就是这里的解释,但它可能是。
  • @DanMašek 接下来,我现在尝试了一个在迭代中持续存在的目标矩阵。这个新版本的性能比 in-place 版本好(srcMat 和 dstMat 相同),但仍然比普通版本稍差。我仍在调查这一切,但到目前为止,似乎不为目标矩阵分配内存并没有提高性能。

标签: performance opencv memory in-place


【解决方案1】:

您可以在来源中挖掘找到原因。

可能的代码路径很少(是否使用 OpenCL,是否使用 IPP)。
在我的机器上,cv::cvtColor 的执行到达了color.hpp 中的函数CvtColorIPPLoopCopy

template <typename Cvt>
bool CvtColorIPPLoopCopy(const uchar * src_data, size_t src_step, int src_type, uchar * dst_data, size_t dst_step, int width, int height, const Cvt& cvt)
{
    Mat temp;
    Mat src(Size(width, height), src_type, const_cast<uchar*>(src_data), src_step);
    Mat source = src;
    if( src_data == dst_data )
    {
        src.copyTo(temp);
        source = temp;
    }
    bool ok;
    parallel_for_(Range(0, source.rows),
                  CvtColorIPPLoop_Invoker<Cvt>(source.data, source.step, dst_data, dst_step,
                                               source.cols, cvt, &ok),
                  source.total()/(double)(1<<16) );
    return ok;
}

代码检查是否src_data == dst_data,如果相等则将源图像复制到临时图像中:

if( src_data == dst_data )
{
    src.copyTo(temp);
    source = temp;
}

额外的数据副本可能是就地处理需要更长时间的原因。


注意:
我不能说这是肯定的原因,因为还有其他可能的代码路径。
有许多高性能优化函数不支持“就地”处理。
当 OpenCV 需要执行不支持“就地”处理的功能时,解决方案可能是将源图像复制到临时位置。
相同的做法可以用于其他执行代码路径。

正如我所评论的,
由于循环携带的依赖关系,就地处理会阻止一些编译(和执行)优化。
在某些情况下,还存在有关“就地”处理的并行化问题。
这就是许多优化的“原始”函数不支持“就地”处理的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-06-07
    • 2015-08-15
    • 1970-01-01
    • 1970-01-01
    • 2015-11-27
    • 2018-11-30
    • 2012-11-02
    相关资源
    最近更新 更多