有人可以帮我理解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);
}
答案 0 :(得分:3)
正如哈罗德所说,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))); ......
这里没有检查4个相邻像素。它会检查4个点,例如,像这样:
int mask = _mm_movemask_epi8(m0); if( mask == 0 ) continue;
if( (mask & 255) == 0 ) { j -= 8; ptr -= 8; continue; }
x + threshold
到c0
个计数器,且小于x - threshold
到c1
个计数器。这里为这些条件生成掩码:
__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);
请注意,如果vector的元素的条件为true,则将其值设置为0xFF或-1,因为我们将其视为signed char。
c0 = _mm_and_si128(_mm_sub_epi8(c0, m0), m0); c1 = _mm_and_si128(_mm_sub_epi8(c1, m1), m1);
如果掩码元素为-1,则自减法以来累积到c0
或c1
计数器(例如c0 - (-1)
)。但如果它等于零,则将其重置为零(_mm_and_si128
)。
他们需要存储最大值的计数器:
max0 = _mm_max_epu8(max0, c0); max1 = _mm_max_epu8(max1, c1);
因此,它们存储了满足&#34;角条件&#34;的最大邻近像素数。
在这里,他们确定哪些像素实际是角落,哪些不是:
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);
}
我希望它会有所帮助。我很抱歉我的英语不好。
答案 1 :(得分:2)
delta
是一个只设置符号位的掩码。他们使用它是因为他们希望比较 unsigned ,但只有一个签名的比较。
添加128(或减去它,因为-128 == 128)并使用xoring执行相同的操作(如果您使用的是字节),因为
a + b == (a ^ b) + ((a & b) << 1)
如果b
只设置了最高位,那么((a & b) << 1)
项必须为零(a & b
可以设置最高位,但它会被移出)。
然后正如您在下图中所看到的那样,将整个范围减去128“移位”,使得有符号的比较将给出与原始范围上的无符号比较相同的结果。
|0 ... 127 ... 255| unsigned
|-128 ... 0 ... 127| signed
我不知道其他人,我希望其他人可以回答这个问题。