|
|
|
@@ -46,27 +46,93 @@ The references are:
|
|
|
|
|
namespace cv
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
static void makeOffsets(int pixel[], int row_stride)
|
|
|
|
|
static void makeOffsets(int pixel[], int row_stride, int patternSize)
|
|
|
|
|
{
|
|
|
|
|
pixel[0] = 0 + row_stride * 3;
|
|
|
|
|
pixel[1] = 1 + row_stride * 3;
|
|
|
|
|
pixel[2] = 2 + row_stride * 2;
|
|
|
|
|
pixel[3] = 3 + row_stride * 1;
|
|
|
|
|
pixel[4] = 3 + row_stride * 0;
|
|
|
|
|
pixel[5] = 3 + row_stride * -1;
|
|
|
|
|
pixel[6] = 2 + row_stride * -2;
|
|
|
|
|
pixel[7] = 1 + row_stride * -3;
|
|
|
|
|
pixel[8] = 0 + row_stride * -3;
|
|
|
|
|
pixel[9] = -1 + row_stride * -3;
|
|
|
|
|
pixel[10] = -2 + row_stride * -2;
|
|
|
|
|
pixel[11] = -3 + row_stride * -1;
|
|
|
|
|
pixel[12] = -3 + row_stride * 0;
|
|
|
|
|
pixel[13] = -3 + row_stride * 1;
|
|
|
|
|
pixel[14] = -2 + row_stride * 2;
|
|
|
|
|
pixel[15] = -1 + row_stride * 3;
|
|
|
|
|
switch(patternSize) {
|
|
|
|
|
case 16:
|
|
|
|
|
pixel[0] = 0 + row_stride * 3;
|
|
|
|
|
pixel[1] = 1 + row_stride * 3;
|
|
|
|
|
pixel[2] = 2 + row_stride * 2;
|
|
|
|
|
pixel[3] = 3 + row_stride * 1;
|
|
|
|
|
pixel[4] = 3 + row_stride * 0;
|
|
|
|
|
pixel[5] = 3 + row_stride * -1;
|
|
|
|
|
pixel[6] = 2 + row_stride * -2;
|
|
|
|
|
pixel[7] = 1 + row_stride * -3;
|
|
|
|
|
pixel[8] = 0 + row_stride * -3;
|
|
|
|
|
pixel[9] = -1 + row_stride * -3;
|
|
|
|
|
pixel[10] = -2 + row_stride * -2;
|
|
|
|
|
pixel[11] = -3 + row_stride * -1;
|
|
|
|
|
pixel[12] = -3 + row_stride * 0;
|
|
|
|
|
pixel[13] = -3 + row_stride * 1;
|
|
|
|
|
pixel[14] = -2 + row_stride * 2;
|
|
|
|
|
pixel[15] = -1 + row_stride * 3;
|
|
|
|
|
break;
|
|
|
|
|
case 12:
|
|
|
|
|
pixel[0] = 0 + row_stride * 2;
|
|
|
|
|
pixel[1] = 1 + row_stride * 2;
|
|
|
|
|
pixel[2] = 2 + row_stride * 1;
|
|
|
|
|
pixel[3] = 2 + row_stride * 0;
|
|
|
|
|
pixel[4] = 2 + row_stride * -1;
|
|
|
|
|
pixel[5] = 1 + row_stride * -2;
|
|
|
|
|
pixel[6] = 0 + row_stride * -2;
|
|
|
|
|
pixel[7] = -1 + row_stride * -2;
|
|
|
|
|
pixel[8] = -2 + row_stride * -1;
|
|
|
|
|
pixel[9] = -2 + row_stride * 0;
|
|
|
|
|
pixel[10] = -2 + row_stride * 1;
|
|
|
|
|
pixel[11] = -1 + row_stride * 2;
|
|
|
|
|
break;
|
|
|
|
|
case 8:
|
|
|
|
|
pixel[0] = 0 + row_stride * 1;
|
|
|
|
|
pixel[1] = 1 + row_stride * 1;
|
|
|
|
|
pixel[2] = 1 + row_stride * 0;
|
|
|
|
|
pixel[3] = 1 + row_stride * -1;
|
|
|
|
|
pixel[4] = 0 + row_stride * -1;
|
|
|
|
|
pixel[5] = -1 + row_stride * -1;
|
|
|
|
|
pixel[6] = 0 + row_stride * 0;
|
|
|
|
|
pixel[7] = 1 + row_stride * 1;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
|
|
|
|
|
/*static void testCorner(const uchar* ptr, const int pixel[], int K, int N, int threshold) {
|
|
|
|
|
// check that with the computed "threshold" the pixel is still a corner
|
|
|
|
|
// and that with the increased-by-1 "threshold" the pixel is not a corner anymore
|
|
|
|
|
for( int delta = 0; delta <= 1; delta++ )
|
|
|
|
|
{
|
|
|
|
|
int v0 = std::min(ptr[0] + threshold + delta, 255);
|
|
|
|
|
int v1 = std::max(ptr[0] - threshold - delta, 0);
|
|
|
|
|
int c0 = 0, c1 = 0;
|
|
|
|
|
|
|
|
|
|
for( int k = 0; k < N; k++ )
|
|
|
|
|
{
|
|
|
|
|
int x = ptr[pixel[k]];
|
|
|
|
|
if(x > v0)
|
|
|
|
|
{
|
|
|
|
|
if( ++c0 > K )
|
|
|
|
|
break;
|
|
|
|
|
c1 = 0;
|
|
|
|
|
}
|
|
|
|
|
else if( x < v1 )
|
|
|
|
|
{
|
|
|
|
|
if( ++c1 > K )
|
|
|
|
|
break;
|
|
|
|
|
c0 = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c0 = c1 = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CV_Assert( (delta == 0 && std::max(c0, c1) > K) ||
|
|
|
|
|
(delta == 1 && std::max(c0, c1) <= K) );
|
|
|
|
|
}
|
|
|
|
|
}*/
|
|
|
|
|
|
|
|
|
|
template<int patternSize>
|
|
|
|
|
int cornerScore(const uchar* ptr, const int pixel[], int threshold);
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
int cornerScore<16>(const uchar* ptr, const int pixel[], int threshold)
|
|
|
|
|
{
|
|
|
|
|
const int K = 8, N = 16 + K + 1;
|
|
|
|
|
int k, v = ptr[0];
|
|
|
|
@@ -150,50 +216,170 @@ static int cornerScore(const uchar* ptr, const int pixel[], int threshold)
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
// check that with the computed "threshold" the pixel is still a corner
|
|
|
|
|
// and that with the increased-by-1 "threshold" the pixel is not a corner anymore
|
|
|
|
|
for( int delta = 0; delta <= 1; delta++ )
|
|
|
|
|
{
|
|
|
|
|
int v0 = std::min(ptr[0] + threshold + delta, 255);
|
|
|
|
|
int v1 = std::max(ptr[0] - threshold - delta, 0);
|
|
|
|
|
int c0 = 0, c1 = 0;
|
|
|
|
|
|
|
|
|
|
for( int k = 0; k < N; k++ )
|
|
|
|
|
{
|
|
|
|
|
int x = ptr[pixel[k]];
|
|
|
|
|
if(x > v0)
|
|
|
|
|
{
|
|
|
|
|
if( ++c0 > K )
|
|
|
|
|
break;
|
|
|
|
|
c1 = 0;
|
|
|
|
|
}
|
|
|
|
|
else if( x < v1 )
|
|
|
|
|
{
|
|
|
|
|
if( ++c1 > K )
|
|
|
|
|
break;
|
|
|
|
|
c0 = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c0 = c1 = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
CV_Assert( (delta == 0 && std::max(c0, c1) > K) ||
|
|
|
|
|
(delta == 1 && std::max(c0, c1) <= K) );
|
|
|
|
|
}
|
|
|
|
|
testCorner(ptr, pixel, K, N, threshold);
|
|
|
|
|
#endif
|
|
|
|
|
return threshold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
int cornerScore<12>(const uchar* ptr, const int pixel[], int threshold)
|
|
|
|
|
{
|
|
|
|
|
const int K = 6, N = 12 + K + 1;
|
|
|
|
|
int k, v = ptr[0];
|
|
|
|
|
short d[N];
|
|
|
|
|
for( k = 0; k < N; k++ )
|
|
|
|
|
d[k] = (short)(v - ptr[pixel[k]]);
|
|
|
|
|
|
|
|
|
|
void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression)
|
|
|
|
|
#if CV_SSE2
|
|
|
|
|
__m128i q0 = _mm_set1_epi16(-1000), q1 = _mm_set1_epi16(1000);
|
|
|
|
|
for( k = 0; k < 16; k += 8 )
|
|
|
|
|
{
|
|
|
|
|
__m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1));
|
|
|
|
|
__m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2));
|
|
|
|
|
__m128i a = _mm_min_epi16(v0, v1);
|
|
|
|
|
__m128i b = _mm_max_epi16(v0, v1);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+3));
|
|
|
|
|
a = _mm_min_epi16(a, v0);
|
|
|
|
|
b = _mm_max_epi16(b, v0);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+4));
|
|
|
|
|
a = _mm_min_epi16(a, v0);
|
|
|
|
|
b = _mm_max_epi16(b, v0);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+5));
|
|
|
|
|
a = _mm_min_epi16(a, v0);
|
|
|
|
|
b = _mm_max_epi16(b, v0);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+6));
|
|
|
|
|
a = _mm_min_epi16(a, v0);
|
|
|
|
|
b = _mm_max_epi16(b, v0);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
|
|
|
|
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+7));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
|
|
|
|
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
|
|
|
|
}
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2));
|
|
|
|
|
threshold = (short)_mm_cvtsi128_si32(q0) - 1;
|
|
|
|
|
#else
|
|
|
|
|
int a0 = threshold;
|
|
|
|
|
for( k = 0; k < 12; k += 2 )
|
|
|
|
|
{
|
|
|
|
|
int a = std::min((int)d[k+1], (int)d[k+2]);
|
|
|
|
|
if( a <= a0 )
|
|
|
|
|
continue;
|
|
|
|
|
a = std::min(a, (int)d[k+3]);
|
|
|
|
|
a = std::min(a, (int)d[k+4]);
|
|
|
|
|
a = std::min(a, (int)d[k+5]);
|
|
|
|
|
a = std::min(a, (int)d[k+6]);
|
|
|
|
|
a0 = std::max(a0, std::min(a, (int)d[k]));
|
|
|
|
|
a0 = std::max(a0, std::min(a, (int)d[k+7]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int b0 = -a0;
|
|
|
|
|
for( k = 0; k < 12; k += 2 )
|
|
|
|
|
{
|
|
|
|
|
int b = std::max((int)d[k+1], (int)d[k+2]);
|
|
|
|
|
b = std::max(b, (int)d[k+3]);
|
|
|
|
|
b = std::max(b, (int)d[k+4]);
|
|
|
|
|
if( b >= b0 )
|
|
|
|
|
continue;
|
|
|
|
|
b = std::max(b, (int)d[k+5]);
|
|
|
|
|
b = std::max(b, (int)d[k+6]);
|
|
|
|
|
|
|
|
|
|
b0 = std::min(b0, std::max(b, (int)d[k]));
|
|
|
|
|
b0 = std::min(b0, std::max(b, (int)d[k+7]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
threshold = -b0-1;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
testCorner(ptr, pixel, K, N, threshold);
|
|
|
|
|
#endif
|
|
|
|
|
return threshold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<>
|
|
|
|
|
int cornerScore<8>(const uchar* ptr, const int pixel[], int threshold)
|
|
|
|
|
{
|
|
|
|
|
const int K = 4, N = 8 + K + 1;
|
|
|
|
|
int k, v = ptr[0];
|
|
|
|
|
short d[N];
|
|
|
|
|
for( k = 0; k < N; k++ )
|
|
|
|
|
d[k] = (short)(v - ptr[pixel[k]]);
|
|
|
|
|
|
|
|
|
|
#if CV_SSE2
|
|
|
|
|
__m128i q0 = _mm_set1_epi16(-1000), q1 = _mm_set1_epi16(1000);
|
|
|
|
|
for( k = 0; k < 16; k += 8 )
|
|
|
|
|
{
|
|
|
|
|
__m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1));
|
|
|
|
|
__m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2));
|
|
|
|
|
__m128i a = _mm_min_epi16(v0, v1);
|
|
|
|
|
__m128i b = _mm_max_epi16(v0, v1);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+3));
|
|
|
|
|
a = _mm_min_epi16(a, v0);
|
|
|
|
|
b = _mm_max_epi16(b, v0);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+4));
|
|
|
|
|
a = _mm_min_epi16(a, v0);
|
|
|
|
|
b = _mm_max_epi16(b, v0);
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
|
|
|
|
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
|
|
|
|
v0 = _mm_loadu_si128((__m128i*)(d+k+5));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
|
|
|
|
|
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
|
|
|
|
|
}
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4));
|
|
|
|
|
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2));
|
|
|
|
|
threshold = (short)_mm_cvtsi128_si32(q0) - 1;
|
|
|
|
|
#else
|
|
|
|
|
int a0 = threshold;
|
|
|
|
|
for( k = 0; k < 8; k += 2 )
|
|
|
|
|
{
|
|
|
|
|
int a = std::min((int)d[k+1], (int)d[k+2]);
|
|
|
|
|
if( a <= a0 )
|
|
|
|
|
continue;
|
|
|
|
|
a = std::min(a, (int)d[k+3]);
|
|
|
|
|
a = std::min(a, (int)d[k+4]);
|
|
|
|
|
a0 = std::max(a0, std::min(a, (int)d[k]));
|
|
|
|
|
a0 = std::max(a0, std::min(a, (int)d[k+5]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int b0 = -a0;
|
|
|
|
|
for( k = 0; k < 12; k += 2 )
|
|
|
|
|
{
|
|
|
|
|
int b = std::max((int)d[k+1], (int)d[k+2]);
|
|
|
|
|
b = std::max(b, (int)d[k+3]);
|
|
|
|
|
if( b >= b0 )
|
|
|
|
|
continue;
|
|
|
|
|
b = std::max(b, (int)d[k+4]);
|
|
|
|
|
|
|
|
|
|
b0 = std::min(b0, std::max(b, (int)d[k]));
|
|
|
|
|
b0 = std::min(b0, std::max(b, (int)d[k+5]));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
threshold = -b0-1;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
testCorner(ptr, pixel, K, N, threshold);
|
|
|
|
|
#endif
|
|
|
|
|
return threshold;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<int patternSize>
|
|
|
|
|
void FAST_t(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression)
|
|
|
|
|
{
|
|
|
|
|
Mat img = _img.getMat();
|
|
|
|
|
const int K = 8, N = 16 + K + 1;
|
|
|
|
|
int i, j, k, pixel[N];
|
|
|
|
|
makeOffsets(pixel, (int)img.step);
|
|
|
|
|
for(k = 16; k < N; k++)
|
|
|
|
|
pixel[k] = pixel[k - 16];
|
|
|
|
|
const int K = patternSize/2, N = patternSize + K + 1, quarterPatternSize = patternSize/4;
|
|
|
|
|
int i, j, k, pixel[25];
|
|
|
|
|
makeOffsets(pixel, (int)img.step, patternSize);
|
|
|
|
|
for(k = patternSize; k < 25; k++)
|
|
|
|
|
pixel[k] = pixel[k - patternSize];
|
|
|
|
|
|
|
|
|
|
keypoints.clear();
|
|
|
|
|
|
|
|
|
@@ -235,9 +421,9 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
|
|
|
|
|
v0 = _mm_xor_si128(_mm_adds_epu8(v0, t), 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);
|
|
|
|
|
__m128i x1 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[quarterPatternSize])), delta);
|
|
|
|
|
__m128i x2 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[2*quarterPatternSize])), delta);
|
|
|
|
|
__m128i x3 = _mm_sub_epi8(_mm_loadu_si128((const __m128i*)(ptr + pixel[3*quarterPatternSize])), 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)));
|
|
|
|
@@ -279,7 +465,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
|
|
|
|
|
{
|
|
|
|
|
cornerpos[ncorners++] = j+k;
|
|
|
|
|
if(nonmax_suppression)
|
|
|
|
|
curr[j+k] = (uchar)cornerScore(ptr+k, pixel, threshold);
|
|
|
|
|
curr[j+k] = (uchar)cornerScore<patternSize>(ptr+k, pixel, threshold);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
@@ -317,7 +503,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
|
|
|
|
|
{
|
|
|
|
|
cornerpos[ncorners++] = j;
|
|
|
|
|
if(nonmax_suppression)
|
|
|
|
|
curr[j] = (uchar)cornerScore(ptr, pixel, threshold);
|
|
|
|
|
curr[j] = (uchar)cornerScore<patternSize>(ptr, pixel, threshold);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -339,7 +525,7 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
|
|
|
|
|
{
|
|
|
|
|
cornerpos[ncorners++] = j;
|
|
|
|
|
if(nonmax_suppression)
|
|
|
|
|
curr[j] = (uchar)cornerScore(ptr, pixel, threshold);
|
|
|
|
|
curr[j] = (uchar)cornerScore<patternSize>(ptr, pixel, threshold);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -375,19 +561,36 @@ void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FAST(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
|
|
|
|
|
{
|
|
|
|
|
switch(type) {
|
|
|
|
|
case FastFeatureDetector::TYPE_5_8:
|
|
|
|
|
FAST_t<8>(_img, keypoints, threshold, nonmax_suppression);
|
|
|
|
|
break;
|
|
|
|
|
case FastFeatureDetector::TYPE_7_12:
|
|
|
|
|
FAST_t<12>(_img, keypoints, threshold, nonmax_suppression);
|
|
|
|
|
break;
|
|
|
|
|
case FastFeatureDetector::TYPE_9_16:
|
|
|
|
|
FAST_t<16>(_img, keypoints, threshold, nonmax_suppression);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* FastFeatureDetector
|
|
|
|
|
*/
|
|
|
|
|
FastFeatureDetector::FastFeatureDetector( int _threshold, bool _nonmaxSuppression )
|
|
|
|
|
: threshold(_threshold), nonmaxSuppression(_nonmaxSuppression)
|
|
|
|
|
: threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type(FastFeatureDetector::TYPE_9_16)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
FastFeatureDetector::FastFeatureDetector( int _threshold, bool _nonmaxSuppression, int _type )
|
|
|
|
|
: threshold(_threshold), nonmaxSuppression(_nonmaxSuppression), type(_type)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void FastFeatureDetector::detectImpl( const Mat& image, vector<KeyPoint>& keypoints, const Mat& mask ) const
|
|
|
|
|
{
|
|
|
|
|
Mat grayImage = image;
|
|
|
|
|
if( image.type() != CV_8U ) cvtColor( image, grayImage, CV_BGR2GRAY );
|
|
|
|
|
FAST( grayImage, keypoints, threshold, nonmaxSuppression );
|
|
|
|
|
FAST( grayImage, keypoints, threshold, nonmaxSuppression, type );
|
|
|
|
|
KeyPointsFilter::runByPixelsMask( keypoints, mask );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|