Removed helper functions from header.

Updated module license text.
pull/1387/head
Vitaly Tuzov 8 years ago
parent 1c580151f4
commit 7e46ea166c
  1. 6
      modules/xfeatures2d/include/opencv2/xfeatures2d.hpp
  2. 799
      modules/xfeatures2d/src/fast.cpp

@ -279,12 +279,6 @@ CV_EXPORTS void FASTForPointSet( InputArray image, CV_IN_OUT std::vector<KeyPoin
int threshold, bool nonmaxSuppression=true, int type=FastFeatureDetector::TYPE_9_16); int threshold, bool nonmaxSuppression=true, int type=FastFeatureDetector::TYPE_9_16);
void makeOffsets(int pixel[25], int row_stride, int patternSize);
template<int patternSize>
int cornerScore(const uchar* ptr, const int pixel[], int threshold);
//! @} //! @}
} }

@ -1,44 +1,6 @@
/*M/////////////////////////////////////////////////////////////////////////////////////// // This file is part of OpenCV project.
// // It is subject to the license terms in the LICENSE file found in the top-level directory
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // of this distribution and at http://opencv.org/license.html.
//
// By downloading, copying, installing or using the software you agree to this license.
// If you do not agree to this license, do not download, install,
// copy or use the software.
//
//
// License Agreement
// For Open Source Computer Vision Library
//
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistribution's of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistribution's in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
//
// * The name of the copyright holders may not be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/
#include <opencv2/xfeatures2d.hpp> #include <opencv2/xfeatures2d.hpp>
@ -46,449 +8,455 @@
#define VERIFY_CORNERS 0 #define VERIFY_CORNERS 0
#endif #endif
namespace cv { namespace {
namespace xfeatures2d { using namespace cv;
#if VERIFY_CORNERS
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;
#if VERIFY_CORNERS for( int k = 0; k < N; k++ )
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 x = ptr[pixel[k]];
int v1 = std::max(ptr[0] - threshold - delta, 0); if(x > v0)
int c0 = 0, c1 = 0;
for( int k = 0; k < N; k++ )
{ {
int x = ptr[pixel[k]]; if( ++c0 > K )
if(x > v0) break;
{ c1 = 0;
if( ++c0 > K ) }
break; else if( x < v1 )
c1 = 0; {
} if( ++c1 > K )
else if( x < v1 ) break;
{ c0 = 0;
if( ++c1 > K ) }
break; else
c0 = 0; {
} c0 = c1 = 0;
else
{
c0 = c1 = 0;
}
} }
CV_Assert( (delta == 0 && std::max(c0, c1) > K) ||
(delta == 1 && std::max(c0, c1) <= K) );
} }
CV_Assert( (delta == 0 && std::max(c0, c1) > K) ||
(delta == 1 && std::max(c0, c1) <= K) );
} }
#endif }
#endif
template<>
int cornerScore<16>(const uchar* ptr, const int pixel[], int threshold) 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 = K*3 + 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 )
{ {
const int K = 8, N = K*3 + 1; __m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1));
int k, v = ptr[0]; __m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2));
short d[N]; __m128i a = _mm_min_epi16(v0, v1);
for( k = 0; k < N; k++ ) __m128i b = _mm_max_epi16(v0, v1);
d[k] = (short)(v - ptr[pixel[k]]); v0 = _mm_loadu_si128((__m128i*)(d+k+3));
a = _mm_min_epi16(a, v0);
#if CV_SSE2 b = _mm_max_epi16(b, v0);
__m128i q0 = _mm_set1_epi16(-1000), q1 = _mm_set1_epi16(1000); v0 = _mm_loadu_si128((__m128i*)(d+k+4));
for( k = 0; k < 16; k += 8 ) a = _mm_min_epi16(a, v0);
{ b = _mm_max_epi16(b, v0);
__m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1)); v0 = _mm_loadu_si128((__m128i*)(d+k+5));
__m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2)); a = _mm_min_epi16(a, v0);
__m128i a = _mm_min_epi16(v0, v1); b = _mm_max_epi16(b, v0);
__m128i b = _mm_max_epi16(v0, v1); v0 = _mm_loadu_si128((__m128i*)(d+k+6));
v0 = _mm_loadu_si128((__m128i*)(d+k+3)); a = _mm_min_epi16(a, v0);
a = _mm_min_epi16(a, v0); b = _mm_max_epi16(b, v0);
b = _mm_max_epi16(b, v0); v0 = _mm_loadu_si128((__m128i*)(d+k+7));
v0 = _mm_loadu_si128((__m128i*)(d+k+4)); a = _mm_min_epi16(a, v0);
a = _mm_min_epi16(a, v0); b = _mm_max_epi16(b, v0);
b = _mm_max_epi16(b, v0); v0 = _mm_loadu_si128((__m128i*)(d+k+8));
v0 = _mm_loadu_si128((__m128i*)(d+k+5)); a = _mm_min_epi16(a, v0);
a = _mm_min_epi16(a, v0); b = _mm_max_epi16(b, v0);
b = _mm_max_epi16(b, v0); v0 = _mm_loadu_si128((__m128i*)(d+k));
v0 = _mm_loadu_si128((__m128i*)(d+k+6)); q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
a = _mm_min_epi16(a, v0); q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
b = _mm_max_epi16(b, v0); v0 = _mm_loadu_si128((__m128i*)(d+k+9));
v0 = _mm_loadu_si128((__m128i*)(d+k+7)); q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
a = _mm_min_epi16(a, v0); q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
b = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d+k+8));
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+9));
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 < 16; k += 2 )
{
int a = std::min((int)d[k+1], (int)d[k+2]);
a = std::min(a, (int)d[k+3]);
if( a <= a0 )
continue;
a = std::min(a, (int)d[k+4]);
a = std::min(a, (int)d[k+5]);
a = std::min(a, (int)d[k+6]);
a = std::min(a, (int)d[k+7]);
a = std::min(a, (int)d[k+8]);
a0 = std::max(a0, std::min(a, (int)d[k]));
a0 = std::max(a0, std::min(a, (int)d[k+9]));
}
int b0 = -a0;
for( k = 0; k < 16; 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]);
b = std::max(b, (int)d[k+5]);
if( b >= b0 )
continue;
b = std::max(b, (int)d[k+6]);
b = std::max(b, (int)d[k+7]);
b = std::max(b, (int)d[k+8]);
b0 = std::min(b0, std::max(b, (int)d[k]));
b0 = std::min(b0, std::max(b, (int)d[k+9]));
}
threshold = -b0-1;
#endif
#if VERIFY_CORNERS
testCorner(ptr, pixel, K, N, threshold);
#endif
return threshold;
} }
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
template<> q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
int cornerScore<12>(const uchar* ptr, const int pixel[], int threshold) 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 < 16; k += 2 )
{ {
const int K = 6, N = K*3 + 1; int a = std::min((int)d[k+1], (int)d[k+2]);
int k, v = ptr[0]; a = std::min(a, (int)d[k+3]);
short d[N + 4]; if( a <= a0 )
for( k = 0; k < N; k++ ) continue;
d[k] = (short)(v - ptr[pixel[k]]); a = std::min(a, (int)d[k+4]);
#if CV_SSE2 a = std::min(a, (int)d[k+5]);
for( k = 0; k < 4; k++ ) a = std::min(a, (int)d[k+6]);
d[N+k] = d[k]; a = std::min(a, (int)d[k+7]);
#endif a = std::min(a, (int)d[k+8]);
a0 = std::max(a0, std::min(a, (int)d[k]));
#if CV_SSE2 a0 = std::max(a0, std::min(a, (int)d[k+9]));
__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; int b0 = -a0;
for( k = 0; k < 12; k += 2 ) for( k = 0; k < 16; k += 2 )
{ {
int b = std::max((int)d[k+1], (int)d[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+3]);
b = std::max(b, (int)d[k+4]); b = std::max(b, (int)d[k+4]);
if( b >= b0 ) b = std::max(b, (int)d[k+5]);
continue; if( b >= b0 )
b = std::max(b, (int)d[k+5]); continue;
b = std::max(b, (int)d[k+6]); b = std::max(b, (int)d[k+6]);
b = std::max(b, (int)d[k+7]);
b0 = std::min(b0, std::max(b, (int)d[k])); b = std::max(b, (int)d[k+8]);
b0 = std::min(b0, std::max(b, (int)d[k+7]));
} b0 = std::min(b0, std::max(b, (int)d[k]));
b0 = std::min(b0, std::max(b, (int)d[k+9]));
}
threshold = -b0-1; threshold = -b0-1;
#endif #endif
#if VERIFY_CORNERS #if VERIFY_CORNERS
testCorner(ptr, pixel, K, N, threshold); testCorner(ptr, pixel, K, N, threshold);
#endif #endif
return threshold; return threshold;
} }
template<> template<>
int cornerScore<8>(const uchar* ptr, const int pixel[], int threshold) int cornerScore<12>(const uchar* ptr, const int pixel[], int threshold)
{
const int K = 6, N = K*3 + 1;
int k, v = ptr[0];
short d[N + 4];
for( k = 0; k < N; k++ )
d[k] = (short)(v - ptr[pixel[k]]);
#if CV_SSE2
for( k = 0; k < 4; k++ )
d[N+k] = d[k];
#endif
#if CV_SSE2
__m128i q0 = _mm_set1_epi16(-1000), q1 = _mm_set1_epi16(1000);
for( k = 0; k < 16; k += 8 )
{ {
const int K = 4, N = K*3 + 1; __m128i v0 = _mm_loadu_si128((__m128i*)(d+k+1));
int k, v = ptr[0]; __m128i v1 = _mm_loadu_si128((__m128i*)(d+k+2));
short d[N];
for( k = 0; k < N; k++ )
d[k] = (short)(v - ptr[pixel[k]]);
#if CV_SSE2
__m128i v0 = _mm_loadu_si128((__m128i*)(d+1));
__m128i v1 = _mm_loadu_si128((__m128i*)(d+2));
__m128i a = _mm_min_epi16(v0, v1); __m128i a = _mm_min_epi16(v0, v1);
__m128i b = _mm_max_epi16(v0, v1); __m128i b = _mm_max_epi16(v0, v1);
v0 = _mm_loadu_si128((__m128i*)(d+3)); 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); a = _mm_min_epi16(a, v0);
b = _mm_max_epi16(b, v0); b = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d+4)); v0 = _mm_loadu_si128((__m128i*)(d+k+5));
a = _mm_min_epi16(a, v0); a = _mm_min_epi16(a, v0);
b = _mm_max_epi16(b, v0); b = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d)); v0 = _mm_loadu_si128((__m128i*)(d+k+6));
__m128i q0 = _mm_min_epi16(a, v0); a = _mm_min_epi16(a, v0);
__m128i q1 = _mm_max_epi16(b, v0); b = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d+5)); v0 = _mm_loadu_si128((__m128i*)(d+k));
q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0)); q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0)); q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1)); v0 = _mm_loadu_si128((__m128i*)(d+k+7));
q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0)); q0 = _mm_max_epi16(q0, _mm_min_epi16(a, v0));
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4)); q1 = _mm_min_epi16(q1, _mm_max_epi16(b, v0));
q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2)); }
threshold = (short)_mm_cvtsi128_si32(q0) - 1; q0 = _mm_max_epi16(q0, _mm_sub_epi16(_mm_setzero_si128(), q1));
#else q0 = _mm_max_epi16(q0, _mm_unpackhi_epi64(q0, q0));
int a0 = threshold; q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 4));
for( k = 0; k < 8; k += 2 ) q0 = _mm_max_epi16(q0, _mm_srli_si128(q0, 2));
{ threshold = (short)_mm_cvtsi128_si32(q0) - 1;
int a = std::min((int)d[k+1], (int)d[k+2]); #else
if( a <= a0 ) int a0 = threshold;
continue; for( k = 0; k < 12; k += 2 )
a = std::min(a, (int)d[k+3]); {
a = std::min(a, (int)d[k+4]); int a = std::min((int)d[k+1], (int)d[k+2]);
a0 = std::max(a0, std::min(a, (int)d[k])); if( a <= a0 )
a0 = std::max(a0, std::min(a, (int)d[k+5])); 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; int b0 = -a0;
for( k = 0; k < 8; k += 2 ) for( k = 0; k < 12; k += 2 )
{ {
int b = std::max((int)d[k+1], (int)d[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+3]);
if( b >= b0 ) b = std::max(b, (int)d[k+4]);
continue; if( b >= b0 )
b = std::max(b, (int)d[k+4]); continue;
b = std::max(b, (int)d[k+5]);
b0 = std::min(b0, std::max(b, (int)d[k])); b = std::max(b, (int)d[k+6]);
b0 = std::min(b0, std::max(b, (int)d[k+5]));
} b0 = std::min(b0, std::max(b, (int)d[k]));
b0 = std::min(b0, std::max(b, (int)d[k+7]));
}
threshold = -b0-1; threshold = -b0-1;
#endif #endif
#if VERIFY_CORNERS
testCorner(ptr, pixel, K, N, threshold);
#endif
return threshold;
}
#if VERIFY_CORNERS template<>
testCorner(ptr, pixel, K, N, threshold); int cornerScore<8>(const uchar* ptr, const int pixel[], int threshold)
#endif {
return threshold; const int K = 4, N = K*3 + 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 v0 = _mm_loadu_si128((__m128i*)(d+1));
__m128i v1 = _mm_loadu_si128((__m128i*)(d+2));
__m128i a = _mm_min_epi16(v0, v1);
__m128i b = _mm_max_epi16(v0, v1);
v0 = _mm_loadu_si128((__m128i*)(d+3));
a = _mm_min_epi16(a, v0);
b = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d+4));
a = _mm_min_epi16(a, v0);
b = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d));
__m128i q0 = _mm_min_epi16(a, v0);
__m128i q1 = _mm_max_epi16(b, v0);
v0 = _mm_loadu_si128((__m128i*)(d+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]));
} }
void makeOffsets(int pixel[25], int rowStride, int patternSize) int b0 = -a0;
for( k = 0; k < 8; k += 2 )
{ {
static const int offsets16[][2] = int b = std::max((int)d[k+1], (int)d[k+2]);
{ b = std::max(b, (int)d[k+3]);
{0, 3}, { 1, 3}, { 2, 2}, { 3, 1}, { 3, 0}, { 3, -1}, { 2, -2}, { 1, -3}, if( b >= b0 )
{0, -3}, {-1, -3}, {-2, -2}, {-3, -1}, {-3, 0}, {-3, 1}, {-2, 2}, {-1, 3} 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]));
}
static const int offsets12[][2] = threshold = -b0-1;
{ #endif
{0, 2}, { 1, 2}, { 2, 1}, { 2, 0}, { 2, -1}, { 1, -2},
{0, -2}, {-1, -2}, {-2, -1}, {-2, 0}, {-2, 1}, {-1, 2}
};
static const int offsets8[][2] = #if VERIFY_CORNERS
{ testCorner(ptr, pixel, K, N, threshold);
{0, 1}, { 1, 1}, { 1, 0}, { 1, -1}, #endif
{0, -1}, {-1, -1}, {-1, 0}, {-1, 1} return threshold;
}; }
const int (*offsets)[2] = patternSize == 16 ? offsets16 : void makeOffsets(int pixel[25], int rowStride, int patternSize)
patternSize == 12 ? offsets12 : {
patternSize == 8 ? offsets8 : 0; static const int offsets16[][2] =
{
{0, 3}, { 1, 3}, { 2, 2}, { 3, 1}, { 3, 0}, { 3, -1}, { 2, -2}, { 1, -3},
{0, -3}, {-1, -3}, {-2, -2}, {-3, -1}, {-3, 0}, {-3, 1}, {-2, 2}, {-1, 3}
};
CV_Assert(pixel && offsets); static const int offsets12[][2] =
{
{0, 2}, { 1, 2}, { 2, 1}, { 2, 0}, { 2, -1}, { 1, -2},
{0, -2}, {-1, -2}, {-2, -1}, {-2, 0}, {-2, 1}, {-1, 2}
};
int k = 0; static const int offsets8[][2] =
for( ; k < patternSize; k++ ) {
pixel[k] = offsets[k][0] + offsets[k][1] * rowStride; {0, 1}, { 1, 1}, { 1, 0}, { 1, -1},
for( ; k < 25; k++ ) {0, -1}, {-1, -1}, {-1, 0}, {-1, 1}
pixel[k] = pixel[k - patternSize]; };
}
template<int patternSize> const int (*offsets)[2] = patternSize == 16 ? offsets16 :
void FASTForPointSet_t( InputArray image, std::vector<KeyPoint>& keypoints, int threshold, bool nonmaxSuppression ) { patternSize == 12 ? offsets12 :
patternSize == 8 ? offsets8 : 0;
Mat img = image.getMat(); CV_Assert(pixel && offsets);
const int K = patternSize/2, N = patternSize + K + 1;
int i, k, pixel[25]; int k = 0;
makeOffsets(pixel, (int)img.step, patternSize); for( ; k < patternSize; k++ )
pixel[k] = offsets[k][0] + offsets[k][1] * rowStride;
for( ; k < 25; k++ )
pixel[k] = pixel[k - patternSize];
}
keypoints.clear(); template<int patternSize>
void FASTForPointSet_t( InputArray image, std::vector<KeyPoint>& keypoints, int threshold, bool nonmaxSuppression ) {
threshold = std::min(std::max(threshold, 0), 255); Mat img = image.getMat();
const int K = patternSize/2, N = patternSize + K + 1;
uchar threshold_tab[512]; int i, k, pixel[25];
for( i = -255; i <= 255; i++ ) makeOffsets(pixel, (int)img.step, patternSize);
threshold_tab[i+255] = (uchar)(i < -threshold ? 1 : i > threshold ? 2 : 0);
AutoBuffer<uchar> _buf((img.cols+16)*3*(sizeof(int) + sizeof(uchar)) + 128); keypoints.clear();
uchar* buf[3];
buf[0] = _buf; buf[1] = buf[0] + img.cols; buf[2] = buf[1] + img.cols;
int* cpbuf[3];
cpbuf[0] = (int*)alignPtr(buf[2] + img.cols, sizeof(int)) + 1;
cpbuf[1] = cpbuf[0] + img.cols + 1;
cpbuf[2] = cpbuf[1] + img.cols + 1;
memset(buf[0], 0, img.cols*3);
// Calculate threshold for the keypoints threshold = std::min(std::max(threshold, 0), 255);
for (size_t keyPointIdx=0; keyPointIdx < keypoints.size(); keyPointIdx++) {
// Set response to -1:
// All keypoints with response <= 0 will be removed afterwards
keypoints[keyPointIdx].response = -1;
// Poiter to keyPoint in image uchar threshold_tab[512];
Point keyPoint = keypoints[keyPointIdx].pt; for( i = -255; i <= 255; i++ )
const uchar* ptr = img.ptr<uchar>(keyPoint.y, keyPoint.x); threshold_tab[i+255] = (uchar)(i < -threshold ? 1 : i > threshold ? 2 : 0);
// value of the pixel at certain position AutoBuffer<uchar> _buf((img.cols+16)*3*(sizeof(int) + sizeof(uchar)) + 128);
int v = ptr[0]; uchar* buf[3];
buf[0] = _buf; buf[1] = buf[0] + img.cols; buf[2] = buf[1] + img.cols;
int* cpbuf[3];
cpbuf[0] = (int*)alignPtr(buf[2] + img.cols, sizeof(int)) + 1;
cpbuf[1] = cpbuf[0] + img.cols + 1;
cpbuf[2] = cpbuf[1] + img.cols + 1;
memset(buf[0], 0, img.cols*3);
// Initialize Lookup table // Calculate threshold for the keypoints
// If k=v --> tab[k] is at the center of the thrshold table for (size_t keyPointIdx=0; keyPointIdx < keypoints.size(); keyPointIdx++) {
// The threshold table is made as follows: // Set response to -1:
// -255 -threshold 0 +threshold 255 // All keypoints with response <= 0 will be removed afterwards
// 111111111111111111|0000000000000|0000000000000|222222222222222 keypoints[keyPointIdx].response = -1;
const uchar* tab = &threshold_tab[0] - v + 255;
// Calculate the fast value // Poiter to keyPoint in image
int d = tab[ptr[pixel[0]]] | tab[ptr[pixel[8]]]; Point keyPoint = keypoints[keyPointIdx].pt;
const uchar* ptr = img.ptr<uchar>(keyPoint.y, keyPoint.x);
if( d == 0 ) // value of the pixel at certain position
continue; int v = ptr[0];
d &= tab[ptr[pixel[2]]] | tab[ptr[pixel[10]]]; // Initialize Lookup table
d &= tab[ptr[pixel[4]]] | tab[ptr[pixel[12]]]; // If k=v --> tab[k] is at the center of the thrshold table
d &= tab[ptr[pixel[6]]] | tab[ptr[pixel[14]]]; // The threshold table is made as follows:
// -255 -threshold 0 +threshold 255
// 111111111111111111|0000000000000|0000000000000|222222222222222
const uchar* tab = &threshold_tab[0] - v + 255;
if( d == 0 ) // Calculate the fast value
continue; int d = tab[ptr[pixel[0]]] | tab[ptr[pixel[8]]];
d &= tab[ptr[pixel[1]]] | tab[ptr[pixel[9]]]; if( d == 0 )
d &= tab[ptr[pixel[3]]] | tab[ptr[pixel[11]]]; continue;
d &= tab[ptr[pixel[5]]] | tab[ptr[pixel[13]]];
d &= tab[ptr[pixel[7]]] | tab[ptr[pixel[15]]];
// For at least half pixels darker than v count the number d &= tab[ptr[pixel[2]]] | tab[ptr[pixel[10]]];
if( d & 1 ) d &= tab[ptr[pixel[4]]] | tab[ptr[pixel[12]]];
{ d &= tab[ptr[pixel[6]]] | tab[ptr[pixel[14]]];
int vt = v - threshold, count = 0;
if( d == 0 )
continue;
d &= tab[ptr[pixel[1]]] | tab[ptr[pixel[9]]];
d &= tab[ptr[pixel[3]]] | tab[ptr[pixel[11]]];
d &= tab[ptr[pixel[5]]] | tab[ptr[pixel[13]]];
d &= tab[ptr[pixel[7]]] | tab[ptr[pixel[15]]];
for(k = 0; k < N; k++ ) // For at least half pixels darker than v count the number
if( d & 1 )
{
int vt = v - threshold, count = 0;
for(k = 0; k < N; k++ )
{
int x = ptr[pixel[k]];
if(x < vt)
{ {
int x = ptr[pixel[k]]; if( ++count > K )
if(x < vt)
{ {
if( ++count > K ) // Calculate score
{ keypoints[keyPointIdx].response = (uchar)cornerScore<patternSize>(ptr, pixel, threshold);
// Calculate score // Non Maxima Supression I
keypoints[keyPointIdx].response = (uchar)cornerScore<patternSize>(ptr, pixel, threshold); if (nonmaxSuppression && keyPointIdx>0 && keypoints[keyPointIdx-1].response < keypoints[keyPointIdx].response) {
// Non Maxima Supression I keypoints[keyPointIdx-1].response = -1;
if (nonmaxSuppression && keyPointIdx>0 && keypoints[keyPointIdx-1].response < keypoints[keyPointIdx].response) {
keypoints[keyPointIdx-1].response = -1;
}
break;
} }
break;
} }
else
count = 0;
} }
else
count = 0;
} }
}
// For at least half pixels brighter than v count the number // For at least half pixels brighter than v count the number
if(d & 2 ) if(d & 2 )
{ {
int vt = v + threshold, count = 0; int vt = v + threshold, count = 0;
for(k = 0; k < N; k++ ) for(k = 0; k < N; k++ )
{
int x = ptr[pixel[k]];
if(x > vt)
{ {
int x = ptr[pixel[k]]; if( ++count > K )
if(x > vt)
{ {
if( ++count > K ) // Calculate score
{ keypoints[keyPointIdx].response = (uchar)cornerScore<patternSize>(ptr, pixel, threshold);
// Calculate score // Non Maxima Suppression I
keypoints[keyPointIdx].response = (uchar)cornerScore<patternSize>(ptr, pixel, threshold); if (nonmaxSuppression && keyPointIdx>0 &&keypoints[keyPointIdx-1].response < keypoints[keyPointIdx].response) {
// Non Maxima Suppression I keypoints[keyPointIdx-1].response = -1;
if (nonmaxSuppression && keyPointIdx>0 &&keypoints[keyPointIdx-1].response < keypoints[keyPointIdx].response) {
keypoints[keyPointIdx-1].response = -1;
}
break;
} }
break;
} }
else
count = 0;
} }
else
count = 0;
} }
} }
// Remove unused Keypoints }
size_t maxKeypointSize = keypoints.size();
for (size_t keyPointIdx=maxKeypointSize; keyPointIdx > 0;) { // Remove unused Keypoints
keyPointIdx--; size_t maxKeypointSize = keypoints.size();
if (keypoints[keyPointIdx].response <= 0) { for (size_t keyPointIdx=maxKeypointSize; keyPointIdx > 0;) {
keypoints.erase(keypoints.begin() + keyPointIdx); keyPointIdx--;
} else if (nonmaxSuppression && keyPointIdx>0 && keypoints[keyPointIdx-1].response > keypoints[keyPointIdx].response) { if (keypoints[keyPointIdx].response <= 0) {
// Non Maxima Suppression II keypoints.erase(keypoints.begin() + keyPointIdx);
keypoints.erase(keypoints.begin() + keyPointIdx); } else if (nonmaxSuppression && keyPointIdx>0 && keypoints[keyPointIdx-1].response > keypoints[keyPointIdx].response) {
} // Non Maxima Suppression II
keypoints.erase(keypoints.begin() + keyPointIdx);
} }
} }
}
}
namespace cv {
namespace xfeatures2d {
void FASTForPointSet(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type) void FASTForPointSet(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bool nonmax_suppression, int type)
{ {
@ -509,5 +477,6 @@ namespace cv {
break; break;
} }
} }
} }
} }

Loading…
Cancel
Save