【问题标题】:Faster mean calculation (openCV, C++)更快的平均计算(openCV,C++)
【发布时间】:2016-02-10 09:26:10
【问题描述】:

我正在计算 C++ 中图像内多个平方区域的平均值。因此,我在图像上移动了一个平方区域并使用 openCV“均值”函数计算均值,但将其替换为 std。平均计算(见下文),它出乎意料地更快。然而,在 Android 设备上它需要大约 8 毫秒,因为平均计算被调用了大约 400 次(每次平均计算需要大约 0.025 毫秒)

uchar rectSize = 10;
Rect roi(0,0,rectSize, rectSize);
int pxNumber = rectSize * rectSize;
uchar value;

//Shifting the region to the bottom
for(uchar y=0; y<NumberOfRectangles_Y; y++)
{
    p = outBitMat.ptr<uchar>(y);
    roi.x = rectSize;

    //Shifting the region to the right
    for(uchar x=0; x<NumberOfRectangles_X; x++, ++p)
    {
        meanCalc(normalized(roi),rectSize, pxNumber, value);
        roi.x += rectSize;
    }

    roi.y += rectSize;
}


 void meanCalc(const cv::Mat& normalized, uchar& rectSize, int& pxNumber, uchar& value)
{
   for(uchar y=0; y < rectSize; y++)
   {
      p = normalized.ptr<uchar>(y);

      for(uchar x=0; x < rectSize; x++, ++p)
      {
        sum += *p;
      }
   }
   value =  sum / (float)pxNumber;
}

有没有办法加快图像内每个矩形窗口的平均计算速度?我可以进行某种预像素排序以仅计算一次平均值并更快吗?

提前致谢

更新

根据用户 6502 的回答和总和表的使用,我得出以下结论:

Mat tab;
integral(image,tab);
int* input = (int*)(tab.data);
value = (input[yStart*tabWidth + xStart] + input[(yStart+rectSize)*tabWidth + xStart+rectSize]
                   - input[yStart*tabWidth + xStart+rectSize] - input[(yStart+rectSize)*tabWidth + xStart]) / (double)pxNumber;

因此这个函数需要几乎相同的时间。是不是只有在计算大量重叠区域时,总和表才有用。因为在我的情况下,我只触摸每个像素进行一次计算。

【问题讨论】:

标签: c++ performance opencv mean


【解决方案1】:

您可以通过预先计算“summed area table”,在恒定时间内(与矩形大小无关)计算任何矩形的平均值。

您需要计算一个表格,其中元素(i, j) 是矩形中从(0, 0)(i, j) 的所有原始数据的总和,这可以在数据的单次传递中完成。

获得表格后,(x0, y0)(x1, y1) 之间的值的总和可以通过以下公式在恒定时间内计算:

tab(x0, y0) + tab(x1, y1) - tab(x0, y1) - tab(x1, y0)

要了解算法的工作原理,首先考虑一维情况会更容易:要在恒定时间内计算从 v[x0]v[x1] 的值的总和,您可以预先计算一个表

st[0] = v[0];
for (int i=1; i<n; i++) st[i] = st[i-1] + v[i];

然后你可以通过st[x1] - st[x0]的差来知道原始数据任意区间的总和。

该算法确实可以轻松扩展到n 维度。

此外,乍一看可能并不明显,但可以为多核架构实现总面积表的预计算,以利用并行执行。

对于 2d,一个简单的分解是考虑计算 2d sum table 与计算每行的 1d sum table,然后为结果上的每一列计算 1d sum table 相同。

【讨论】:

  • 这是由cv::integral在OpenCV中完成的
  • 感谢您提出这个想法!如果有性能改进,我只是在实施和测量运行时间。之后我会发布我的结果。
  • 也称为积分图像。我认为这也用于 Viola-Jones 人脸检测算法。
【解决方案2】:

您可以使用来自Simd Library的优化版menCalc函数:

SIMD_API void SimdValueSum(const uint8_t * src, size_t stride, 
    size_t width, size_t height, uint64_t * sum);

因为使用不同的 SIMD,如 SSE、AVX 等,所以速度要快得多。

【讨论】:

    猜你喜欢
    • 2020-10-20
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 2020-03-12
    • 1970-01-01
    • 2022-09-27
    • 2017-03-12
    • 1970-01-01
    相关资源
    最近更新 更多