First, fast feature points
There are enough pixels in the surrounding neighborhood of the pixel point to be in a different gray area than the point. In a grayscale image, that is, there are enough pixels for a grayscale value greater than that point's grayscale value or less than the grayscale value of that point.
A discretized, Bresenham-shaped region with a radius of 3 centered on the pixel point is usually selected.
In OpenCV, when Patternsize is 16 o'clock, the coordinates of the 16 points relative to the center point are represented by the following array:
static const int OFFSETS16[][2] =
{
{0, 3}, {1, 3}, {2, 2}, {3, 1}, {3, 0}, {3,-1}, {2,-2},
{0,-3}, {-1,-3}, {-2,-2}, {-3,-1}, {-3, 0}, {-3, 1}, {-2, 2}, {-1, 3}
};
OpenCV uses a function to calculate the position of the points on the circumference relative to the center coordinates in the original image:
void makeoffsets (int pixel[25], int rowstride, int patternsize) {//define three arrays respectively to represent the relative coordinate position of the circumference pixels for the center of the circle when Patternsize is 16, 12, and 8 static const int Offsets16[][2] = {{0, 3}, {1, 3}, {2, 2}, {3, 1}, {3, 0}, {3,-1}, {2,-2} {0,-3}, {-1,-3}, {-2,-2}, {-3,-1}, {-3, 0}, {-3, 1}, {-2, 2}, {-1, 3}}; static const int Offsets12[][2] = {{0, 2}, {1, 2}, {2, 1}, {2, 0}, {2,-1}, {1,-2}, {- 1,-2}, {-2,-1}, {-2, 0}, {-2, 1}, {-1, 2}}; static const int Offsets8[][2] = {{0, 1}, {1, 1}, {1, 0}, {1,-1}, {0,-1}, {-1,-1}, {-1 1}}; According to the Patternsize value, which array const int (*offsets) is the specific application defined above [2] = Patternsize = = 16? Offsets16:patternsize = = 12? Offsets12:patternsize = = 8? offsets8:0; Cv_assert (pixel && offsets); int k = 0; Substituting the number of pixels in each row of the input image to get the absolute coordinate position of the circumference pixels for (; k < patternsize; k++) PIXEL[K] = offsets[k][0] + offsets[k][1] * rowstride; for (; k <; k++)//Because the consecutive pixels are to be computed, the number of values to loop is listed pixel[k] = pixel[k-patternsize];}as shown in the following:
Whether a candidate point is a feature point can be judged by the following formula:
I (x) is the pixel value at any point on the circumference;
I (p) is the candidate point pixel value;
N is a corner, such as N=12, where n points are satisfied on the circumference.
Second, OPENCV fast source code Analysis
Source:http://blog.csdn.net/zhaocj/article/details/40301561
Template<int patternsize>void fast_t (Inputarray _img, std::vector<keypoint>& keypoints, int threshold , bool nonmax_suppression) {//http://blog.csdn.net/zhaocj/article/details/40301561 Mat img = _img.getmat (); K is the number of consecutive pixels in the circumference of the//n used for the pixel points of the circular circumference, because the n is more than the actual circumference pixel number k+1 a const int K = PATTERNSIZE/2, n = patternsize + K + 1; #if cv_s SE2 const int quarterpatternsize = PATTERNSIZE/4; (void) quarterpatternsize; #endif int I, J, K, pixel[25]; Find the offset of the circumference pixel point relative to the center of Makeoffsets (pixel, (int) img.step, patternsize); Keypoints.clear (); The guaranteed threshold value is not greater than 255, not less than 0 threshold = Std::min (Std::max (threshold, 0), 255); #if cv_sse2 __m128i delta = _mm_set1_epi8 ( -128), t = _mm_set1_epi8 ((char) threshold), K16 = _mm_set1_epi8 ((char) K); (void) K16; (void) Delta; (void) T; #endif//Threshold_tab is a threshold list, when the threshold comparison is performed, simply check the table to Uchar threshold_tab[512]; /* Threshold list assignment, the table is divided into three segments: the first paragraph from threshold_tab[0] to Threshold_tab[255-threshold], the value is 1, the value falls in the region to satisfy the corner judgment condition: set S byn consecutive pixel x on the circumference, Ix < IP-T, second paragraph from threshold_tab[255–threshold] to threshold_tab[255 + threshold], value 0, the value falling in the region is not a corner point; Three segments from threshold_tab[255 + threshold] to threshold_tab[511], with a value of 2, the value falling in the range indicates that the corner judgment condition is satisfied: The set S is composed of n contiguous pixels x on the circumference, Ix > Ip + t; for (i = -255; I <= 255; i++) threshold_tab[i+255] = (UCHAR) (i <-threshold? 1:i > Threshold? 2: 0); Autobuffer<uchar> _buf ((img.cols+16) *3* (sizeof (int) + sizeof (UCHAR)) + 128); /* buf[0, buf[1], and buf[2] represent the previous line, the current line, and the last row of the image, respectively. Because in step 2 of non-maxima suppression, you want to compare within a 3x3 corner neighborhood, you need three rows of image data. */uchar* buf[3]; Buf[0] = _buf; BUF[1] = buf[0] + img.cols; BUF[2] = buf[1] + img.cols; int* Cpbuf[3]; /* ALIGNPTR: aligned pointers on some schemas, only memory addresses that can be divisible by a specified number (such as 4,16) can be accessed, or the program will crash, or the result of an error, or data access is slow. For example, many systems require Interger addresses to start with even numbers. Template < typename _tp > static inline _tp* alignptr (_tp* ptr, int n = (int) sizeof (_TP)) {return (_ tp*) (((size_t) ptr + n-1) &-N); } &-N: N is a power of 2, and the other binary is only a 1, for example, the default is 16 when the time is 00010000, take a negative number to get 111110000, the effect is for 2^k, get a low K for 0, the other bit is 1, take this number (-N) and other numbers to do with the operation, is equal to the other number of the low K-bit cut off. The resulting number is necessarily a multiple of 2^k (a number with a low K-bit of 0 is necessarily a multiple of 2^k). This effect is only established for n=2^k. *///cpbuf The coordinate position of the corner point and also the data that requires three rows in a row cpbuf[0] = (int*) alignptr (buf[2] + img.cols, sizeof (int)) + 1;//+1 frees up a location to hold the number of corner points: corn Erpos[-1] = ncorners; CPBUF[1] = cpbuf[0] + img.cols + 1; CPBUF[2] = cpbuf[1] + img.cols + 1; memset (Buf[0], 0, img.cols*3); for (i = 3; i < img.rows-2; i++)//Prevent out of bounds {const uchar* ptr = img.ptr<uchar> (i) + 3;//get the first address pointer of the image Line/ /get an array of rows of buf, CPBUF, for storing the value of the current row's scoring function v uchar* curr = buf[(i-3)%3]; int* Cornerpos = cpbuf[(i-3)%3]; memset (curr, 0, Img.cols); int ncorners = 0; Number of detected corner points if (I < img.rows-3) {j = 3; #if Cv_sse2 if (patternsize = =) {for (; J < img.cols-16-3; J + =, ptr + = 16) {__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); __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[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))); 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; 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 < k++, M >>= 1) if (M & 1) { cornerpos[ncorners++] = j+k; if (nonmax_suppression) curr[j+k] = (UCHAR) cornerscore<patternsize> (ptr+k, Pixel, Threshol D); }}} #endif for (; J < img.cols-3; J + +, ptr++) {int v = ptr[0];//The gray value of the current pixel const uchar* tab = &threshold_tab[0]-V + 255;//is determined by the gray value of the current pixel at the threshold valueThe position in the list/* Pixel[0] represents the offset of a pixel numbered 0 on the circumference relative to the center coordinate ptr[pixel[0] represents a pixel value of 0 on the circumference Tab[ptr[pixel[0]] Represents the value that is queried in the threshold list threshold_tab relative to the pixel value of 0 on the circumference of the current pixel (that is, the center of the Circle) *//check in position 1, 9, 5 and 134-position pixels, turning a subtraction and comparison operation into table-type int d = tab[ptr[pixel[0]] | TAB[PTR[PIXEL[8]]; *//d in four cases: D=0 the value of 0 and 8 is 0, the value of d=1 description number 0 and 8 is at least one 1, and the other cannot be 2; d=2 Description numbers 0 and 8 have at least one value of 2, and the other cannot be 1; d=3 the values 0 and 8 have one 1 and the other is 2. *///1 and 9 are not in accordance with the midpoint condition if (d = = 0)//d=0 It is not possible to have 12 consecutive pixels on the circumference to meet the corner condition, so the current value must not be a corner point Continue Continue with other two pixels in diameter d &= tab[ptr[pixel[2]] | TAB[PTR[PIXEL[10]]; D &= Tab[ptr[pixel[4]] | TAB[PTR[PIXEL[12]]; D &= Tab[ptr[pixel[6]] | TAB[PTR[PIXEL[14]]; /* D=0 indicates that at least one d in the above D is 0,So certainly not a corner point, another case is a D is 2, and another d is 1, and after the phase is also 0, which indicates that one is satisfied with the corner condition 1, and the other satisfies the corner condition 2, so there is certainly no successive 12 pixels to meet the same corner condition, so It must not be a corner point. */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]]; if (D & 1) {//VT is a true corner condition, that is, the Ip–t,count is a count value of continuous pixels int vt = v-th Reshold, count = 0; Traverse the entire circumference for (k = 0; k < N; k++) {int x = ptr[pixel[k]]; Extract the pixel values on the circumference if (X < VT) {if (++count > K) Count continuously and determine if it is greater than K (half of the circumference pixels) {cornerpos[ncorners++] = j;//Save the position of the point and add the number of corners of the current line to 1 if (nonmax_suppression)//For the first step of non-maxima suppression, calculate the scoring function CURR[J] = (uchar) cornerscore<patternsize> (PTR, pixel, threshold); break;//get a corner point, exit the loop}//++count > K}//x < VT else count = 0; }//k}//d & 1 if (D & 2) {int vt = v + threshol D, count = 0; for (k = 0; k < N; k++) {int x = ptr[pixel[k]]; if (x > VT) {if (++count > K) { cornerpos[ncorners++] = j; if (nonmax_suppression) curr[j] = (UCHAR) Cornerscore<pattErnsize> (PTR, pixel, threshold); Break }//++count > K}//x > vt Else count = 0; }//k}//d & 2}//j}//i < img.rows-3 cornerpos[-1] = ncorners;//Save the number of corner points detected by the current line if (i = = 3) The//i=3 description only calculates a row of data and cannot perform the second step of non-maxima suppression, so the following code is not manipulated directly into the next loop continu E Non-maxima suppress//extract the image pixel const uchar* prev = buf[(i-4 + 3) on the previous line and the last two lines the address of the 1th line of the%3];//3 line is const uchar* Pprev = BUF [(i-5 + 3)%3];//3 Line 3rd Address Cornerpos = cpbuf[(i-4 + 3)%3];//extract the corner position detected on the previous line ncorners = cornerpos[-1];//lift Out The number of corners on the previous line for (k = 0; k < ncorners; k++) {j = cornerpos[k]; int score = Prev[j]; if (!nonmax_suppression | | (Score > Prev[j+1] && score > prev[j-1] && score > Pprev[j-1] && score > Pprev[j] && score > pprev[j+1] && score > curr[j-1] && scor E > Curr[j] && score > Curr[j+1]) {keypoints.push_back (KeyPoint (float) j, (Floa T) (i-1), 7.F,-1, (float) score)); }//if}//k}//i}
Fast Algorithm parsing