使用SSE的OpenCV灰度图像的平方根

时间:2015-03-11 13:30:33

标签: c++ opencv sse simd

给出一个灰色的cv :: Mat(CV_8UC1)我想返回另一个包含元素的平方根(CV_32FC1)的cv :: Mat,我想用SSE2内在函数来做。我在从8位值转换为32个浮点值以执行平方根时遇到一些问题。我真的很感激任何帮助。这是我现在的代码(它没有给出正确的值):

uchar *source = (uchar *)cv::alignPtr(image.data, 16);
float *sqDataPtr = cv::alignPtr((float *)Squared.data, 16); 
for (x = 0; x < (pixels - 16); x += 16) {
    __m128i a0 = _mm_load_si128((__m128i *)(source + x));

    __m128i first8 = _mm_unpacklo_epi8(a0, _mm_set1_epi8(0));
    __m128i last8 = _mm_unpackhi_epi8(a0, _mm_set1_epi8(0));

    __m128i first4i = _mm_unpacklo_epi16(first8, _mm_set1_epi16(0));
    __m128i second4i = _mm_unpackhi_epi16(first8, _mm_set1_epi16(0));
    __m128 first4 = _mm_cvtepi32_ps(first4i);
    __m128 second4 = _mm_cvtepi32_ps(second4i);

    __m128i third4i = _mm_unpacklo_epi16(last8, _mm_set1_epi16(0));
    __m128i fourth4i = _mm_unpackhi_epi16(last8, _mm_set1_epi16(0));
    __m128 third4 = _mm_cvtepi32_ps(third4i);
    __m128 fourth4 = _mm_cvtepi32_ps(fourth4i);

    //  Store
    _mm_store_ps(sqDataPtr + x, _mm_sqrt_ps(first4));
    _mm_store_ps(sqDataPtr + x + 4, _mm_sqrt_ps(second4));
    _mm_store_ps(sqDataPtr + x + 8, _mm_sqrt_ps(third4));
    _mm_store_ps(sqDataPtr + x + 12, _mm_sqrt_ps(fourth4));
}

2 个答案:

答案 0 :(得分:1)

SSE代码看起来没问题,只是您没有处理最后16个像素:

for (x = 0; x < (pixels - 16); x += 16)

应该是:

for (x = 0; x <= (pixels - 16); x += 16)

请注意,如果您的图片宽度不是16的倍数,那么您需要在最后一个完整向量之后处理剩余的像素。

另请注意,您正在使用范围为0..255的sqrt值。您可能希望归一化值在0..1.0范围内,在这种情况下,您希望相应地缩放值。

答案 1 :(得分:1)

我没有SSE2的经验,但我认为如果性能是问题,你应该使用查找表。查找表的创建很快,因为您只有256个可能的值。将4个字节从查找表复制到目标矩阵应该是一个非常有效的操作。