重写OpenCV扩展的SIMD性能

时间:2015-03-16 04:16:34

标签: c++ opencv optimization simd sse2

我正在尝试重写OpenCV dilate函数来练习SIMD编程。为简单起见,仅考虑不可分离的情况。大部分代码看起来像OpenCV版本。然而,结果表明OpenCV的速度提高了10倍以上。

** Input **
-- Image size: [5472 x 3648]
-- Dilate structuring element:
[1, 1, 1, 1, 1, 1, 1;
 1, 1, 1, 1, 1, 1, 1;
 1, 1, 1, 1, 1, 1, 1;
 1, 1, 1, 0, 1, 1, 1;
 1, 1, 1, 1, 1, 1, 1;
 1, 1, 1, 1, 1, 1, 1;
 1, 1, 1, 1, 1, 1, 1]

** Result **
OpenCV: 0.043147 sec
My Function: 0.49147 sec

代码:

Mat mydilate(const Mat& src, const Mat& de)
{
    int xb = de.cols / 2;
    int yb = de.rows / 2;
    Mat img_whole = Mat::zeros(src.rows + 2 * yb, src.cols + 2 * xb, CV_8U);
    src.copyTo(img_whole(Rect(xb, yb, src.cols, src.rows)));

    vector<Point> coords;
    vector<const uchar*> sptr;
    for (int i = 0; i < de.rows; i++) {
        for (int j = 0; j < de.cols; j++) {
            if (de.ptr(i)[j] == 1) {
                coords.push_back(Point(j, i));
            }
        }
    }

    Mat result(src.rows, src.cols, CV_8U);
    int width = result.cols;
    vector<uchar> pts;
    int nz = coords.size();
    pts.resize(nz);

    sptr.resize(nz);
    for (int y = 0; y < result.rows; y++) {

        uchar *pdst = result.ptr(y);
        for (int k = 0; k < nz; k++)
            sptr[k] = img_whole.ptr(y + coords[k].y) + coords[k].x;

        uchar **ssptr = (uchar **)&sptr[0];

        for (int x = 0; x < width - 16; x += 16) 
        {
            __m128i s0 = _mm_loadu_si128((const __m128i *)(ssptr[0] + x));
            for (int i = 1; i < nz; i++) 
            {
                __m128i x0 = _mm_loadu_si128((const __m128i *)(ssptr[i] + x));
                s0 = _mm_max_epu8(s0, x0);
            }
            _mm_storeu_si128((__m128i*)(pdst + x), s0);
        }

    }

    return result;
}

这个功能的瓶颈是什么?我还尝试将源指针对齐为16的倍数,但没有性能提升。

1 个答案:

答案 0 :(得分:1)

事实证明它与编译器有关。添加编译器标志-O2后,mydilate的运行速度与OpenCV版本一样快。