有人可以帮助我了解 OpenCV 中 FAST 角点检测的 SSE 实现吗?我了解算法但不了解实现。有人可以引导我完成代码吗?

代码很长,所以提前谢谢你。

我使用的是 OpenCV 2.4.11,代码如下:

__m128i delta = _mm_set1_epi8(-128);
__m128i t = _mm_set1_epi8((char)threshold);
__m128i m0, m1;
__m128i v0 = _mm_loadu_si128((const __m128i*)ptr);

我认为以下与阈值检查有关,但无法理解 delta 的使用
__m128i v1 = _mm_xor_si128(_mm_subs_epu8(v0, t), delta);
v0 = _mm_xor_si128(_mm_adds_epu8(v0, t), delta);

现在它检查相邻的 4 个像素,但同样, delta 的用途是什么?
__m128i x0 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[0])), delta);
__m128i x1 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[4])), delta);
__m128i x2 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[8])), delta);
__m128i x3 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[12])), delta);
m0 = _mm_and_si128(_mm_cmpgt_epi8(x0, v0), _mm_cmpgt_epi8(x1, v0));
m1 = _mm_and_si128(_mm_cmpgt_epi8(v1, x0), _mm_cmpgt_epi8(v1, x1));
m0 = _mm_or_si128(m0, _mm_and_si128(_mm_cmpgt_epi8(x1, v0), _mm_cmpgt_epi8(x2, v0)));
m1 = _mm_or_si128(m1, _mm_and_si128(_mm_cmpgt_epi8(v1, x1), _mm_cmpgt_epi8(v1, x2)));
m0 = _mm_or_si128(m0, _mm_and_si128(_mm_cmpgt_epi8(x2, v0), _mm_cmpgt_epi8(x3, v0)));
m1 = _mm_or_si128(m1, _mm_and_si128(_mm_cmpgt_epi8(v1, x2), _mm_cmpgt_epi8(v1, x3)));
m0 = _mm_or_si128(m0, _mm_and_si128(_mm_cmpgt_epi8(x3, v0), _mm_cmpgt_epi8(x0, v0)));
m1 = _mm_or_si128(m1, _mm_and_si128(_mm_cmpgt_epi8(v1, x3), _mm_cmpgt_epi8(v1, x0)));
m0 = _mm_or_si128(m0, m1);

在这里,它检查相邻像素的连续性。 (正确的?)
int mask = _mm_movemask_epi8(m0);
if( mask == 0 )
    continue;

这对我来说是另一个难题。为什么要左移 8 个字节?我假设 掩码 告诉我角候选的位置,但为什么是 8 个字节?
if( (mask & 255) == 0 )
{
    j -= 8;
    ptr -= 8;
    continue;
}

这个时候我放弃了...
__m128i c0 = _mm_setzero_si128(), c1 = c0, max0 = c0, max1 = c0;
for( k = 0; k < N; k++ )
{
    __m128i x = _mm_xor_si128(_mm_loadu_si128((const __m128i*)(ptr + pixel[k])), delta);
    m0 = _mm_cmpgt_epi8(x, v0);
    m1 = _mm_cmpgt_epi8(v1, x);

    c0 = _mm_and_si128(_mm_sub_epi8(c0, m0), m0);
    c1 = _mm_and_si128(_mm_sub_epi8(c1, m1), m1);

    max0 = _mm_max_epu8(max0, c0);
    max1 = _mm_max_epu8(max1, c1);
}

max0 = _mm_max_epu8(max0, max1);
int m = _mm_movemask_epi8(_mm_cmpgt_epi8(max0, K16));

for( k = 0; m > 0 && k < 16; k++, m >>= 1 )
    if(m & 1)
    {
        cornerpos[ncorners++] = j+k;
        if(nonmax_suppression)
            curr[j+k] = (uchar)cornerScore<patternSize>(ptr+k, pixel, threshold);
    }

最佳答案

正如哈罗德所说,delta 用于进行无符号比较。

让我们按步骤描述这个实现:


  • 这里不是检查 4 个相邻像素。例如,它检查 4 个点,如下所示:
  • 在这里,他们检查这 4 个点的“角点条件”是否为真,因为如果不为真,则没有 8 个相邻像素满足“角点条件”,因此它不是角点像素。如果掩码为零,则意味着 vector 中的所有像素都不能成为角点,因此我们向左移动 16 个像素。


  • 如果掩码不为零,但前 8 个像素的“角点条件”不为真,则它们仅左移 8 个像素以检查下一次迭代中的剩余像素。


  • 最后一步。在这里,他们计算大于 x + thresholdc0 计数器和小于 x - thresholdc1 计数器的相邻像素的数量。

  • 这里为这种情况生成掩码:



    请注意,如果 vector 元素的条件为真,则他的值设置为 0xFF 或 -1,因为我们将他视为有符号字符。



    如果 mask 的元素是 -1 ,它会从减法开始累积到 c0c1 计数器(例如 c0 - (-1) )。但是如果它等于零,他们会将计数器重置为零( _mm_and_si128 )。

    比他们需要存储计数器的最大值:



    因此,它们存储满足“角点条件”的最大相邻像素数。

    在这里,他们确定哪些像素实际上是角,哪些不是:
    max0 = _mm_max_epu8(max0, max1);
    int m = _mm_movemask_epi8(_mm_cmpgt_epi8(max0, K16));
    
    for( k = 0; m > 0 && k < 16; k++, m >>= 1 )
        if(m & 1)
        {
            cornerpos[ncorners++] = j+k;
            if(nonmax_suppression)
                curr[j+k] = (uchar)cornerScore<patternSize>(ptr+k, pixel, threshold);
        }
    

    我希望它会有所帮助。我很抱歉我的英语不好。

    关于c - OpenCV FAST 角点检测 SSE 实现演练,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30881857/

    10-10 13:10