有人可以幫助我理解OpenCV中FAST角點檢測的SSE實現嗎?我理解算法,但不瞭解實現。有人能通過代碼來引導我嗎?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);
我認爲下面有一些做與閾值檢查,但無法瞭解使用三角洲
的__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);
}
「如果掩碼不爲零,但對於前8個像素」拐角條件「不正確,它們只會左移8個像素以檢查下一次迭代中的剩餘像素。 但是,如果前8個像素的第4個像素是角落怎麼辦?不應該將它移到** mask **中的第一個0xff? – will2km
你是對的,計數前導零位和轉換到特定數量的像素會更方便,但它可能過於複雜並導致性能下降。我認爲這種策略對於x86/64 CPU的許多情況是最佳的。 – akarsakov