我正在尝试重写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的倍数,但没有性能提升。
答案 0 :(得分:1)
事实证明它与编译器有关。添加编译器标志-O2
后,mydilate
的运行速度与OpenCV版本一样快。