split FAST in order to reuse it in BRISK
authorVincent Rabaud <vrabaud@willowgarage.com>
Thu, 23 Aug 2012 12:33:11 +0000 (14:33 +0200)
committerVadim Pisarevsky <vadim.pisarevsky@itseez.com>
Thu, 30 Aug 2012 12:28:38 +0000 (16:28 +0400)
modules/features2d/src/fast.cpp
modules/features2d/src/fast_score.cpp [new file with mode: 0644]
modules/features2d/src/fast_score.hpp [new file with mode: 0644]

index b9834bb..9beba21 100644 (file)
@@ -42,335 +42,11 @@ The references are:
 */
 
 #include "precomp.hpp"
+#include "fast_score.hpp"
 
 namespace cv
 {
 
-static void makeOffsets(int pixel[], int row_stride, int patternSize)
-{
-    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 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];
-    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+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+7));
-        a = _mm_min_epi16(a, 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 0
-    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]]);
-
-#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 < 8; 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)
 {
@@ -381,8 +57,6 @@ void FAST_t(InputArray _img, std::vector<KeyPoint>& keypoints, int threshold, bo
 #endif
     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();
 
diff --git a/modules/features2d/src/fast_score.cpp b/modules/features2d/src/fast_score.cpp
new file mode 100644 (file)
index 0000000..aa5881e
--- /dev/null
@@ -0,0 +1,374 @@
+/* This is FAST corner detector, contributed to OpenCV by the author, Edward Rosten.
+   Below is the original copyright and the references */
+
+/*
+Copyright (c) 2006, 2008 Edward Rosten
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    *Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+
+    *Redistributions 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.
+
+    *Neither the name of the University of Cambridge nor the names of
+     its contributors may 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 COPYRIGHT OWNER 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.
+*/
+
+/*
+The references are:
+ * Machine learning for high-speed corner detection,
+   E. Rosten and T. Drummond, ECCV 2006
+ * Faster and better: A machine learning approach to corner detection
+   E. Rosten, R. Porter and T. Drummond, PAMI, 2009
+*/
+
+#include "fast_score.hpp"
+
+namespace cv
+{
+
+void makeOffsets(int pixel[25], int row_stride, int patternSize)
+{
+    CV_Assert(pixel != 0);
+    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;
+    }
+    for(int k = patternSize; k < 25; k++)
+      pixel[k] = pixel[k - patternSize];
+}
+
+/*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 cornerScore<16>(const uchar* ptr, const int pixel[], int threshold)
+{
+    const int K = 8, N = 16 + 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+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+7));
+        a = _mm_min_epi16(a, 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 0
+    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]]);
+
+#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 < 8; 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;
+}
+
+}
diff --git a/modules/features2d/src/fast_score.hpp b/modules/features2d/src/fast_score.hpp
new file mode 100644 (file)
index 0000000..f6e9f6f
--- /dev/null
@@ -0,0 +1,64 @@
+/* This is FAST corner detector, contributed to OpenCV by the author, Edward Rosten.
+   Below is the original copyright and the references */
+
+/*
+Copyright (c) 2006, 2008 Edward Rosten
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+    *Redistributions of source code must retain the above copyright
+     notice, this list of conditions and the following disclaimer.
+
+    *Redistributions 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.
+
+    *Neither the name of the University of Cambridge nor the names of
+     its contributors may 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 COPYRIGHT OWNER 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.
+*/
+
+/*
+The references are:
+ * Machine learning for high-speed corner detection,
+   E. Rosten and T. Drummond, ECCV 2006
+ * Faster and better: A machine learning approach to corner detection
+   E. Rosten, R. Porter and T. Drummond, PAMI, 2009
+*/
+
+#ifndef __OPENCV_FEATURES_2D_FAST_HPP__
+#define __OPENCV_FEATURES_2D_FAST_HPP__
+
+#ifdef __cplusplus
+
+#include "precomp.hpp"
+
+namespace cv
+{
+
+void makeOffsets(int pixel[25], int row_stride, int patternSize);
+
+//static void testCorner(const uchar* ptr, const int pixel[], int K, int N, int threshold);
+
+template<int patternSize>
+int cornerScore(const uchar* ptr, const int pixel[], int threshold);
+
+}
+
+#endif
+#endif