1 /*********************************************************************
2  * Software License Agreement (BSD License)
3  *
4  *  Copyright (C) 2011  The Autonomous Systems Lab (ASL), ETH Zurich,
5  *                Stefan Leutenegger, Simon Lynen and Margarita Chli.
6  *  Copyright (c) 2009, Willow Garage, Inc.
7  *  All rights reserved.
8  *
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *
13  *   * Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *   * Redistributions in binary form must reproduce the above
16  *     copyright notice, this list of conditions and the following
17  *     disclaimer in the documentation and/or other materials provided
18  *     with the distribution.
19  *   * Neither the name of the Willow Garage nor the names of its
20  *     contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission.
22  *
23  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34  *  POSSIBILITY OF SUCH DAMAGE.
35  *********************************************************************/
36 
37 /*
38  BRISK - Binary Robust Invariant Scalable Keypoints
39  Reference implementation of
40  [1] Stefan Leutenegger,Margarita Chli and Roland Siegwart, BRISK:
41  Binary Robust Invariant Scalable Keypoints, in Proceedings of
42  the IEEE International Conference on Computer Vision (ICCV2011).
43  */
44 
45 #include "precomp.hpp"
46 #include <fstream>
47 #include <stdlib.h>
48 
49 #include "agast_score.hpp"
50 
51 namespace cv
52 {
53 
54 class BRISK_Impl : public BRISK
55 {
56 public:
57     explicit BRISK_Impl(int thresh=30, int octaves=3, float patternScale=1.0f);
58     // custom setup
59     explicit BRISK_Impl(const std::vector<float> &radiusList, const std::vector<int> &numberList,
60         float dMax=5.85f, float dMin=8.2f, const std::vector<int> indexChange=std::vector<int>());
61 
62     virtual ~BRISK_Impl();
63 
descriptorSize() const64     int descriptorSize() const
65     {
66         return strings_;
67     }
68 
descriptorType() const69     int descriptorType() const
70     {
71         return CV_8U;
72     }
73 
defaultNorm() const74     int defaultNorm() const
75     {
76         return NORM_HAMMING;
77     }
78 
79     // call this to generate the kernel:
80     // circle of radius r (pixels), with n points;
81     // short pairings with dMax, long pairings with dMin
82     void generateKernel(const std::vector<float> &radiusList,
83         const std::vector<int> &numberList, float dMax=5.85f, float dMin=8.2f,
84         const std::vector<int> &indexChange=std::vector<int>());
85 
86     void detectAndCompute( InputArray image, InputArray mask,
87                      CV_OUT std::vector<KeyPoint>& keypoints,
88                      OutputArray descriptors,
89                      bool useProvidedKeypoints );
90 
91 protected:
92 
93     void computeKeypointsNoOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints) const;
94     void computeDescriptorsAndOrOrientation(InputArray image, InputArray mask, std::vector<KeyPoint>& keypoints,
95                                        OutputArray descriptors, bool doDescriptors, bool doOrientation,
96                                        bool useProvidedKeypoints) const;
97 
98     // Feature parameters
99     CV_PROP_RW int threshold;
100     CV_PROP_RW int octaves;
101 
102     // some helper structures for the Brisk pattern representation
103     struct BriskPatternPoint{
104         float x;         // x coordinate relative to center
105         float y;         // x coordinate relative to center
106         float sigma;     // Gaussian smoothing sigma
107     };
108     struct BriskShortPair{
109         unsigned int i;  // index of the first pattern point
110         unsigned int j;  // index of other pattern point
111     };
112     struct BriskLongPair{
113         unsigned int i;  // index of the first pattern point
114         unsigned int j;  // index of other pattern point
115         int weighted_dx; // 1024.0/dx
116         int weighted_dy; // 1024.0/dy
117     };
118     inline int smoothedIntensity(const cv::Mat& image,
119                 const cv::Mat& integral,const float key_x,
120                 const float key_y, const unsigned int scale,
121                 const unsigned int rot, const unsigned int point) const;
122     // pattern properties
123     BriskPatternPoint* patternPoints_;     //[i][rotation][scale]
124     unsigned int points_;                 // total number of collocation points
125     float* scaleList_;                     // lists the scaling per scale index [scale]
126     unsigned int* sizeList_;             // lists the total pattern size per scale index [scale]
127     static const unsigned int scales_;    // scales discretization
128     static const float scalerange_;     // span of sizes 40->4 Octaves - else, this needs to be adjusted...
129     static const unsigned int n_rot_;    // discretization of the rotation look-up
130 
131     // pairs
132     int strings_;                        // number of uchars the descriptor consists of
133     float dMax_;                         // short pair maximum distance
134     float dMin_;                         // long pair maximum distance
135     BriskShortPair* shortPairs_;         // d<_dMax
136     BriskLongPair* longPairs_;             // d>_dMin
137     unsigned int noShortPairs_;         // number of shortParis
138     unsigned int noLongPairs_;             // number of longParis
139 
140     // general
141     static const float basicSize_;
142 };
143 
144 
145 // a layer in the Brisk detector pyramid
146 class CV_EXPORTS BriskLayer
147 {
148 public:
149   // constructor arguments
150   struct CV_EXPORTS CommonParams
151   {
152     static const int HALFSAMPLE = 0;
153     static const int TWOTHIRDSAMPLE = 1;
154   };
155   // construct a base layer
156   BriskLayer(const cv::Mat& img, float scale = 1.0f, float offset = 0.0f);
157   // derive a layer
158   BriskLayer(const BriskLayer& layer, int mode);
159 
160   // Agast without non-max suppression
161   void
162   getAgastPoints(int threshold, std::vector<cv::KeyPoint>& keypoints);
163 
164   // get scores - attention, this is in layer coordinates, not scale=1 coordinates!
165   inline int
166   getAgastScore(int x, int y, int threshold) const;
167   inline int
168   getAgastScore_5_8(int x, int y, int threshold) const;
169   inline int
170   getAgastScore(float xf, float yf, int threshold, float scale = 1.0f) const;
171 
172   // accessors
173   inline const cv::Mat&
img() const174   img() const
175   {
176     return img_;
177   }
178   inline const cv::Mat&
scores() const179   scores() const
180   {
181     return scores_;
182   }
183   inline float
scale() const184   scale() const
185   {
186     return scale_;
187   }
188   inline float
offset() const189   offset() const
190   {
191     return offset_;
192   }
193 
194   // half sampling
195   static inline void
196   halfsample(const cv::Mat& srcimg, cv::Mat& dstimg);
197   // two third sampling
198   static inline void
199   twothirdsample(const cv::Mat& srcimg, cv::Mat& dstimg);
200 
201 private:
202   // access gray values (smoothed/interpolated)
203   inline int
204   value(const cv::Mat& mat, float xf, float yf, float scale) const;
205   // the image
206   cv::Mat img_;
207   // its Agast scores
208   cv::Mat_<uchar> scores_;
209   // coordinate transformation
210   float scale_;
211   float offset_;
212   // agast
213   cv::Ptr<cv::AgastFeatureDetector> oast_9_16_;
214   int pixel_5_8_[25];
215   int pixel_9_16_[25];
216 };
217 
218 class CV_EXPORTS BriskScaleSpace
219 {
220 public:
221   // construct telling the octaves number:
222   BriskScaleSpace(int _octaves = 3);
223   ~BriskScaleSpace();
224 
225   // construct the image pyramids
226   void
227   constructPyramid(const cv::Mat& image);
228 
229   // get Keypoints
230   void
231   getKeypoints(const int _threshold, std::vector<cv::KeyPoint>& keypoints);
232 
233 protected:
234   // nonmax suppression:
235   inline bool
236   isMax2D(const int layer, const int x_layer, const int y_layer);
237   // 1D (scale axis) refinement:
238   inline float
239   refine1D(const float s_05, const float s0, const float s05, float& max) const; // around octave
240   inline float
241   refine1D_1(const float s_05, const float s0, const float s05, float& max) const; // around intra
242   inline float
243   refine1D_2(const float s_05, const float s0, const float s05, float& max) const; // around octave 0 only
244   // 2D maximum refinement:
245   inline float
246   subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, const int s_1_0, const int s_1_1, const int s_1_2,
247              const int s_2_0, const int s_2_1, const int s_2_2, float& delta_x, float& delta_y) const;
248   // 3D maximum refinement centered around (x_layer,y_layer)
249   inline float
250   refine3D(const int layer, const int x_layer, const int y_layer, float& x, float& y, float& scale, bool& ismax) const;
251 
252   // interpolated score access with recalculation when needed:
253   inline int
254   getScoreAbove(const int layer, const int x_layer, const int y_layer) const;
255   inline int
256   getScoreBelow(const int layer, const int x_layer, const int y_layer) const;
257 
258   // return the maximum of score patches above or below
259   inline float
260   getScoreMaxAbove(const int layer, const int x_layer, const int y_layer, const int threshold, bool& ismax,
261                    float& dx, float& dy) const;
262   inline float
263   getScoreMaxBelow(const int layer, const int x_layer, const int y_layer, const int threshold, bool& ismax,
264                    float& dx, float& dy) const;
265 
266   // the image pyramids:
267   int layers_;
268   std::vector<BriskLayer> pyramid_;
269 
270   // some constant parameters:
271   static const float safetyFactor_;
272   static const float basicSize_;
273 };
274 
275 const float BRISK_Impl::basicSize_ = 12.0f;
276 const unsigned int BRISK_Impl::scales_ = 64;
277 const float BRISK_Impl::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted...
278 const unsigned int BRISK_Impl::n_rot_ = 1024; // discretization of the rotation look-up
279 
280 const float BriskScaleSpace::safetyFactor_ = 1.0f;
281 const float BriskScaleSpace::basicSize_ = 12.0f;
282 
283 // constructors
BRISK_Impl(int thresh,int octaves_in,float patternScale)284 BRISK_Impl::BRISK_Impl(int thresh, int octaves_in, float patternScale)
285 {
286   threshold = thresh;
287   octaves = octaves_in;
288 
289   std::vector<float> rList;
290   std::vector<int> nList;
291 
292   // this is the standard pattern found to be suitable also
293   rList.resize(5);
294   nList.resize(5);
295   const double f = 0.85 * patternScale;
296 
297   rList[0] = (float)(f * 0.);
298   rList[1] = (float)(f * 2.9);
299   rList[2] = (float)(f * 4.9);
300   rList[3] = (float)(f * 7.4);
301   rList[4] = (float)(f * 10.8);
302 
303   nList[0] = 1;
304   nList[1] = 10;
305   nList[2] = 14;
306   nList[3] = 15;
307   nList[4] = 20;
308 
309   generateKernel(rList, nList, (float)(5.85 * patternScale), (float)(8.2 * patternScale));
310 }
311 
BRISK_Impl(const std::vector<float> & radiusList,const std::vector<int> & numberList,float dMax,float dMin,const std::vector<int> indexChange)312 BRISK_Impl::BRISK_Impl(const std::vector<float> &radiusList,
313                        const std::vector<int> &numberList,
314                        float dMax, float dMin,
315                        const std::vector<int> indexChange)
316 {
317   generateKernel(radiusList, numberList, dMax, dMin, indexChange);
318   threshold = 20;
319   octaves = 3;
320 }
321 
322 void
generateKernel(const std::vector<float> & radiusList,const std::vector<int> & numberList,float dMax,float dMin,const std::vector<int> & _indexChange)323 BRISK_Impl::generateKernel(const std::vector<float> &radiusList,
324                            const std::vector<int> &numberList,
325                            float dMax, float dMin,
326                            const std::vector<int>& _indexChange)
327 {
328   std::vector<int> indexChange = _indexChange;
329   dMax_ = dMax;
330   dMin_ = dMin;
331 
332   // get the total number of points
333   const int rings = (int)radiusList.size();
334   CV_Assert(radiusList.size() != 0 && radiusList.size() == numberList.size());
335   points_ = 0; // remember the total number of points
336   for (int ring = 0; ring < rings; ring++)
337   {
338     points_ += numberList[ring];
339   }
340   // set up the patterns
341   patternPoints_ = new BriskPatternPoint[points_ * scales_ * n_rot_];
342   BriskPatternPoint* patternIterator = patternPoints_;
343 
344   // define the scale discretization:
345   static const float lb_scale = (float)(std::log(scalerange_) / std::log(2.0));
346   static const float lb_scale_step = lb_scale / (scales_);
347 
348   scaleList_ = new float[scales_];
349   sizeList_ = new unsigned int[scales_];
350 
351   const float sigma_scale = 1.3f;
352 
353   for (unsigned int scale = 0; scale < scales_; ++scale)
354   {
355     scaleList_[scale] = (float)std::pow((double) 2.0, (double) (scale * lb_scale_step));
356     sizeList_[scale] = 0;
357 
358     // generate the pattern points look-up
359     double alpha, theta;
360     for (size_t rot = 0; rot < n_rot_; ++rot)
361     {
362       theta = double(rot) * 2 * CV_PI / double(n_rot_); // this is the rotation of the feature
363       for (int ring = 0; ring < rings; ++ring)
364       {
365         for (int num = 0; num < numberList[ring]; ++num)
366         {
367           // the actual coordinates on the circle
368           alpha = (double(num)) * 2 * CV_PI / double(numberList[ring]);
369           patternIterator->x = (float)(scaleList_[scale] * radiusList[ring] * cos(alpha + theta)); // feature rotation plus angle of the point
370           patternIterator->y = (float)(scaleList_[scale] * radiusList[ring] * sin(alpha + theta));
371           // and the gaussian kernel sigma
372           if (ring == 0)
373           {
374             patternIterator->sigma = sigma_scale * scaleList_[scale] * 0.5f;
375           }
376           else
377           {
378             patternIterator->sigma = (float)(sigma_scale * scaleList_[scale] * (double(radiusList[ring]))
379                                      * sin(CV_PI / numberList[ring]));
380           }
381           // adapt the sizeList if necessary
382           const unsigned int size = cvCeil(((scaleList_[scale] * radiusList[ring]) + patternIterator->sigma)) + 1;
383           if (sizeList_[scale] < size)
384           {
385             sizeList_[scale] = size;
386           }
387 
388           // increment the iterator
389           ++patternIterator;
390         }
391       }
392     }
393   }
394 
395   // now also generate pairings
396   shortPairs_ = new BriskShortPair[points_ * (points_ - 1) / 2];
397   longPairs_ = new BriskLongPair[points_ * (points_ - 1) / 2];
398   noShortPairs_ = 0;
399   noLongPairs_ = 0;
400 
401   // fill indexChange with 0..n if empty
402   unsigned int indSize = (unsigned int)indexChange.size();
403   if (indSize == 0)
404   {
405     indexChange.resize(points_ * (points_ - 1) / 2);
406     indSize = (unsigned int)indexChange.size();
407 
408     for (unsigned int i = 0; i < indSize; i++)
409       indexChange[i] = i;
410   }
411   const float dMin_sq = dMin_ * dMin_;
412   const float dMax_sq = dMax_ * dMax_;
413   for (unsigned int i = 1; i < points_; i++)
414   {
415     for (unsigned int j = 0; j < i; j++)
416     { //(find all the pairs)
417       // point pair distance:
418       const float dx = patternPoints_[j].x - patternPoints_[i].x;
419       const float dy = patternPoints_[j].y - patternPoints_[i].y;
420       const float norm_sq = (dx * dx + dy * dy);
421       if (norm_sq > dMin_sq)
422       {
423         // save to long pairs
424         BriskLongPair& longPair = longPairs_[noLongPairs_];
425         longPair.weighted_dx = int((dx / (norm_sq)) * 2048.0 + 0.5);
426         longPair.weighted_dy = int((dy / (norm_sq)) * 2048.0 + 0.5);
427         longPair.i = i;
428         longPair.j = j;
429         ++noLongPairs_;
430       }
431       else if (norm_sq < dMax_sq)
432       {
433         // save to short pairs
434         CV_Assert(noShortPairs_ < indSize);
435         // make sure the user passes something sensible
436         BriskShortPair& shortPair = shortPairs_[indexChange[noShortPairs_]];
437         shortPair.j = j;
438         shortPair.i = i;
439         ++noShortPairs_;
440       }
441     }
442   }
443 
444   // no bits:
445   strings_ = (int) ceil((float(noShortPairs_)) / 128.0) * 4 * 4;
446 }
447 
448 // simple alternative:
449 inline int
smoothedIntensity(const cv::Mat & image,const cv::Mat & integral,const float key_x,const float key_y,const unsigned int scale,const unsigned int rot,const unsigned int point) const450 BRISK_Impl::smoothedIntensity(const cv::Mat& image, const cv::Mat& integral, const float key_x,
451                                             const float key_y, const unsigned int scale, const unsigned int rot,
452                                             const unsigned int point) const
453 {
454 
455   // get the float position
456   const BriskPatternPoint& briskPoint = patternPoints_[scale * n_rot_ * points_ + rot * points_ + point];
457   const float xf = briskPoint.x + key_x;
458   const float yf = briskPoint.y + key_y;
459   const int x = int(xf);
460   const int y = int(yf);
461   const int& imagecols = image.cols;
462 
463   // get the sigma:
464   const float sigma_half = briskPoint.sigma;
465   const float area = 4.0f * sigma_half * sigma_half;
466 
467   // calculate output:
468   int ret_val;
469   if (sigma_half < 0.5)
470   {
471     //interpolation multipliers:
472     const int r_x = (int)((xf - x) * 1024);
473     const int r_y = (int)((yf - y) * 1024);
474     const int r_x_1 = (1024 - r_x);
475     const int r_y_1 = (1024 - r_y);
476     const uchar* ptr = &image.at<uchar>(y, x);
477     size_t step = image.step;
478     // just interpolate:
479     ret_val = r_x_1 * r_y_1 * ptr[0] + r_x * r_y_1 * ptr[1] +
480               r_x * r_y * ptr[step] + r_x_1 * r_y * ptr[step+1];
481     return (ret_val + 512) / 1024;
482   }
483 
484   // this is the standard case (simple, not speed optimized yet):
485 
486   // scaling:
487   const int scaling = (int)(4194304.0 / area);
488   const int scaling2 = int(float(scaling) * area / 1024.0);
489 
490   // the integral image is larger:
491   const int integralcols = imagecols + 1;
492 
493   // calculate borders
494   const float x_1 = xf - sigma_half;
495   const float x1 = xf + sigma_half;
496   const float y_1 = yf - sigma_half;
497   const float y1 = yf + sigma_half;
498 
499   const int x_left = int(x_1 + 0.5);
500   const int y_top = int(y_1 + 0.5);
501   const int x_right = int(x1 + 0.5);
502   const int y_bottom = int(y1 + 0.5);
503 
504   // overlap area - multiplication factors:
505   const float r_x_1 = float(x_left) - x_1 + 0.5f;
506   const float r_y_1 = float(y_top) - y_1 + 0.5f;
507   const float r_x1 = x1 - float(x_right) + 0.5f;
508   const float r_y1 = y1 - float(y_bottom) + 0.5f;
509   const int dx = x_right - x_left - 1;
510   const int dy = y_bottom - y_top - 1;
511   const int A = (int)((r_x_1 * r_y_1) * scaling);
512   const int B = (int)((r_x1 * r_y_1) * scaling);
513   const int C = (int)((r_x1 * r_y1) * scaling);
514   const int D = (int)((r_x_1 * r_y1) * scaling);
515   const int r_x_1_i = (int)(r_x_1 * scaling);
516   const int r_y_1_i = (int)(r_y_1 * scaling);
517   const int r_x1_i = (int)(r_x1 * scaling);
518   const int r_y1_i = (int)(r_y1 * scaling);
519 
520   if (dx + dy > 2)
521   {
522     // now the calculation:
523     const uchar* ptr = image.ptr() + x_left + imagecols * y_top;
524     // first the corners:
525     ret_val = A * int(*ptr);
526     ptr += dx + 1;
527     ret_val += B * int(*ptr);
528     ptr += dy * imagecols + 1;
529     ret_val += C * int(*ptr);
530     ptr -= dx + 1;
531     ret_val += D * int(*ptr);
532 
533     // next the edges:
534     const int* ptr_integral = integral.ptr<int>() + x_left + integralcols * y_top + 1;
535     // find a simple path through the different surface corners
536     const int tmp1 = (*ptr_integral);
537     ptr_integral += dx;
538     const int tmp2 = (*ptr_integral);
539     ptr_integral += integralcols;
540     const int tmp3 = (*ptr_integral);
541     ptr_integral++;
542     const int tmp4 = (*ptr_integral);
543     ptr_integral += dy * integralcols;
544     const int tmp5 = (*ptr_integral);
545     ptr_integral--;
546     const int tmp6 = (*ptr_integral);
547     ptr_integral += integralcols;
548     const int tmp7 = (*ptr_integral);
549     ptr_integral -= dx;
550     const int tmp8 = (*ptr_integral);
551     ptr_integral -= integralcols;
552     const int tmp9 = (*ptr_integral);
553     ptr_integral--;
554     const int tmp10 = (*ptr_integral);
555     ptr_integral -= dy * integralcols;
556     const int tmp11 = (*ptr_integral);
557     ptr_integral++;
558     const int tmp12 = (*ptr_integral);
559 
560     // assign the weighted surface integrals:
561     const int upper = (tmp3 - tmp2 + tmp1 - tmp12) * r_y_1_i;
562     const int middle = (tmp6 - tmp3 + tmp12 - tmp9) * scaling;
563     const int left = (tmp9 - tmp12 + tmp11 - tmp10) * r_x_1_i;
564     const int right = (tmp5 - tmp4 + tmp3 - tmp6) * r_x1_i;
565     const int bottom = (tmp7 - tmp6 + tmp9 - tmp8) * r_y1_i;
566 
567     return (ret_val + upper + middle + left + right + bottom + scaling2 / 2) / scaling2;
568   }
569 
570   // now the calculation:
571   const uchar* ptr = image.ptr() + x_left + imagecols * y_top;
572   // first row:
573   ret_val = A * int(*ptr);
574   ptr++;
575   const uchar* end1 = ptr + dx;
576   for (; ptr < end1; ptr++)
577   {
578     ret_val += r_y_1_i * int(*ptr);
579   }
580   ret_val += B * int(*ptr);
581   // middle ones:
582   ptr += imagecols - dx - 1;
583   const uchar* end_j = ptr + dy * imagecols;
584   for (; ptr < end_j; ptr += imagecols - dx - 1)
585   {
586     ret_val += r_x_1_i * int(*ptr);
587     ptr++;
588     const uchar* end2 = ptr + dx;
589     for (; ptr < end2; ptr++)
590     {
591       ret_val += int(*ptr) * scaling;
592     }
593     ret_val += r_x1_i * int(*ptr);
594   }
595   // last row:
596   ret_val += D * int(*ptr);
597   ptr++;
598   const uchar* end3 = ptr + dx;
599   for (; ptr < end3; ptr++)
600   {
601     ret_val += r_y1_i * int(*ptr);
602   }
603   ret_val += C * int(*ptr);
604 
605   return (ret_val + scaling2 / 2) / scaling2;
606 }
607 
608 inline bool
RoiPredicate(const float minX,const float minY,const float maxX,const float maxY,const KeyPoint & keyPt)609 RoiPredicate(const float minX, const float minY, const float maxX, const float maxY, const KeyPoint& keyPt)
610 {
611   const Point2f& pt = keyPt.pt;
612   return (pt.x < minX) || (pt.x >= maxX) || (pt.y < minY) || (pt.y >= maxY);
613 }
614 
615 // computes the descriptor
616 void
detectAndCompute(InputArray _image,InputArray _mask,std::vector<KeyPoint> & keypoints,OutputArray _descriptors,bool useProvidedKeypoints)617 BRISK_Impl::detectAndCompute( InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
618                               OutputArray _descriptors, bool useProvidedKeypoints)
619 {
620   bool doOrientation=true;
621 
622   // If the user specified cv::noArray(), this will yield false. Otherwise it will return true.
623   bool doDescriptors = _descriptors.needed();
624 
625   computeDescriptorsAndOrOrientation(_image, _mask, keypoints, _descriptors, doDescriptors, doOrientation,
626                                        useProvidedKeypoints);
627 }
628 
629 void
computeDescriptorsAndOrOrientation(InputArray _image,InputArray _mask,std::vector<KeyPoint> & keypoints,OutputArray _descriptors,bool doDescriptors,bool doOrientation,bool useProvidedKeypoints) const630 BRISK_Impl::computeDescriptorsAndOrOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints,
631                                      OutputArray _descriptors, bool doDescriptors, bool doOrientation,
632                                      bool useProvidedKeypoints) const
633 {
634   Mat image = _image.getMat(), mask = _mask.getMat();
635   if( image.type() != CV_8UC1 )
636       cvtColor(image, image, COLOR_BGR2GRAY);
637 
638   if (!useProvidedKeypoints)
639   {
640     doOrientation = true;
641     computeKeypointsNoOrientation(_image, _mask, keypoints);
642   }
643 
644   //Remove keypoints very close to the border
645   size_t ksize = keypoints.size();
646   std::vector<int> kscales; // remember the scale per keypoint
647   kscales.resize(ksize);
648   static const float log2 = 0.693147180559945f;
649   static const float lb_scalerange = (float)(std::log(scalerange_) / (log2));
650   std::vector<cv::KeyPoint>::iterator beginning = keypoints.begin();
651   std::vector<int>::iterator beginningkscales = kscales.begin();
652   static const float basicSize06 = basicSize_ * 0.6f;
653   for (size_t k = 0; k < ksize; k++)
654   {
655     unsigned int scale;
656       scale = std::max((int) (scales_ / lb_scalerange * (std::log(keypoints[k].size / (basicSize06)) / log2) + 0.5), 0);
657       // saturate
658       if (scale >= scales_)
659         scale = scales_ - 1;
660       kscales[k] = scale;
661     const int border = sizeList_[scale];
662     const int border_x = image.cols - border;
663     const int border_y = image.rows - border;
664     if (RoiPredicate((float)border, (float)border, (float)border_x, (float)border_y, keypoints[k]))
665     {
666       keypoints.erase(beginning + k);
667       kscales.erase(beginningkscales + k);
668       if (k == 0)
669       {
670         beginning = keypoints.begin();
671         beginningkscales = kscales.begin();
672       }
673       ksize--;
674       k--;
675     }
676   }
677 
678   // first, calculate the integral image over the whole image:
679   // current integral image
680   cv::Mat _integral; // the integral image
681   cv::integral(image, _integral);
682 
683   int* _values = new int[points_]; // for temporary use
684 
685   // resize the descriptors:
686   cv::Mat descriptors;
687   if (doDescriptors)
688   {
689     _descriptors.create((int)ksize, strings_, CV_8U);
690     descriptors = _descriptors.getMat();
691     descriptors.setTo(0);
692   }
693 
694   // now do the extraction for all keypoints:
695 
696   // temporary variables containing gray values at sample points:
697   int t1;
698   int t2;
699 
700   // the feature orientation
701   const uchar* ptr = descriptors.ptr();
702   for (size_t k = 0; k < ksize; k++)
703   {
704     cv::KeyPoint& kp = keypoints[k];
705     const int& scale = kscales[k];
706     int* pvalues = _values;
707     const float& x = kp.pt.x;
708     const float& y = kp.pt.y;
709 
710     if (doOrientation)
711     {
712         // get the gray values in the unrotated pattern
713         for (unsigned int i = 0; i < points_; i++)
714         {
715           *(pvalues++) = smoothedIntensity(image, _integral, x, y, scale, 0, i);
716         }
717 
718         int direction0 = 0;
719         int direction1 = 0;
720         // now iterate through the long pairings
721         const BriskLongPair* max = longPairs_ + noLongPairs_;
722         for (BriskLongPair* iter = longPairs_; iter < max; ++iter)
723         {
724           t1 = *(_values + iter->i);
725           t2 = *(_values + iter->j);
726           const int delta_t = (t1 - t2);
727           // update the direction:
728           const int tmp0 = delta_t * (iter->weighted_dx) / 1024;
729           const int tmp1 = delta_t * (iter->weighted_dy) / 1024;
730           direction0 += tmp0;
731           direction1 += tmp1;
732         }
733         kp.angle = (float)(atan2((float) direction1, (float) direction0) / CV_PI * 180.0);
734 
735         if (!doDescriptors)
736         {
737           if (kp.angle < 0)
738             kp.angle += 360.f;
739         }
740     }
741 
742     if (!doDescriptors)
743       continue;
744 
745     int theta;
746     if (kp.angle==-1)
747     {
748         // don't compute the gradient direction, just assign a rotation of 0°
749         theta = 0;
750     }
751     else
752     {
753         theta = (int) (n_rot_ * (kp.angle / (360.0)) + 0.5);
754         if (theta < 0)
755           theta += n_rot_;
756         if (theta >= int(n_rot_))
757           theta -= n_rot_;
758     }
759 
760     if (kp.angle < 0)
761       kp.angle += 360.f;
762 
763     // now also extract the stuff for the actual direction:
764     // let us compute the smoothed values
765     int shifter = 0;
766 
767     //unsigned int mean=0;
768     pvalues = _values;
769     // get the gray values in the rotated pattern
770     for (unsigned int i = 0; i < points_; i++)
771     {
772       *(pvalues++) = smoothedIntensity(image, _integral, x, y, scale, theta, i);
773     }
774 
775     // now iterate through all the pairings
776     unsigned int* ptr2 = (unsigned int*) ptr;
777     const BriskShortPair* max = shortPairs_ + noShortPairs_;
778     for (BriskShortPair* iter = shortPairs_; iter < max; ++iter)
779     {
780       t1 = *(_values + iter->i);
781       t2 = *(_values + iter->j);
782       if (t1 > t2)
783       {
784         *ptr2 |= ((1) << shifter);
785 
786       } // else already initialized with zero
787       // take care of the iterators:
788       ++shifter;
789       if (shifter == 32)
790       {
791         shifter = 0;
792         ++ptr2;
793       }
794     }
795 
796     ptr += strings_;
797   }
798 
799   // clean-up
800   delete[] _values;
801 }
802 
803 
~BRISK_Impl()804 BRISK_Impl::~BRISK_Impl()
805 {
806   delete[] patternPoints_;
807   delete[] shortPairs_;
808   delete[] longPairs_;
809   delete[] scaleList_;
810   delete[] sizeList_;
811 }
812 
813 void
computeKeypointsNoOrientation(InputArray _image,InputArray _mask,std::vector<KeyPoint> & keypoints) const814 BRISK_Impl::computeKeypointsNoOrientation(InputArray _image, InputArray _mask, std::vector<KeyPoint>& keypoints) const
815 {
816   Mat image = _image.getMat(), mask = _mask.getMat();
817   if( image.type() != CV_8UC1 )
818       cvtColor(_image, image, COLOR_BGR2GRAY);
819 
820   BriskScaleSpace briskScaleSpace(octaves);
821   briskScaleSpace.constructPyramid(image);
822   briskScaleSpace.getKeypoints(threshold, keypoints);
823 
824   // remove invalid points
825   KeyPointsFilter::runByPixelsMask(keypoints, mask);
826 }
827 
828 // construct telling the octaves number:
BriskScaleSpace(int _octaves)829 BriskScaleSpace::BriskScaleSpace(int _octaves)
830 {
831   if (_octaves == 0)
832     layers_ = 1;
833   else
834     layers_ = 2 * _octaves;
835 }
~BriskScaleSpace()836 BriskScaleSpace::~BriskScaleSpace()
837 {
838 
839 }
840 // construct the image pyramids
841 void
constructPyramid(const cv::Mat & image)842 BriskScaleSpace::constructPyramid(const cv::Mat& image)
843 {
844 
845   // set correct size:
846   pyramid_.clear();
847 
848   // fill the pyramid:
849   pyramid_.push_back(BriskLayer(image.clone()));
850   if (layers_ > 1)
851   {
852     pyramid_.push_back(BriskLayer(pyramid_.back(), BriskLayer::CommonParams::TWOTHIRDSAMPLE));
853   }
854   const int octaves2 = layers_;
855 
856   for (uchar i = 2; i < octaves2; i += 2)
857   {
858     pyramid_.push_back(BriskLayer(pyramid_[i - 2], BriskLayer::CommonParams::HALFSAMPLE));
859     pyramid_.push_back(BriskLayer(pyramid_[i - 1], BriskLayer::CommonParams::HALFSAMPLE));
860   }
861 }
862 
863 void
getKeypoints(const int threshold_,std::vector<cv::KeyPoint> & keypoints)864 BriskScaleSpace::getKeypoints(const int threshold_, std::vector<cv::KeyPoint>& keypoints)
865 {
866   // make sure keypoints is empty
867   keypoints.resize(0);
868   keypoints.reserve(2000);
869 
870   // assign thresholds
871   int safeThreshold_ = (int)(threshold_ * safetyFactor_);
872   std::vector<std::vector<cv::KeyPoint> > agastPoints;
873   agastPoints.resize(layers_);
874 
875   // go through the octaves and intra layers and calculate agast corner scores:
876   for (int i = 0; i < layers_; i++)
877   {
878     // call OAST16_9 without nms
879     BriskLayer& l = pyramid_[i];
880     l.getAgastPoints(safeThreshold_, agastPoints[i]);
881   }
882 
883   if (layers_ == 1)
884   {
885     // just do a simple 2d subpixel refinement...
886     const size_t num = agastPoints[0].size();
887     for (size_t n = 0; n < num; n++)
888     {
889       const cv::Point2f& point = agastPoints.at(0)[n].pt;
890       // first check if it is a maximum:
891       if (!isMax2D(0, (int)point.x, (int)point.y))
892         continue;
893 
894       // let's do the subpixel and float scale refinement:
895       BriskLayer& l = pyramid_[0];
896       int s_0_0 = l.getAgastScore(point.x - 1, point.y - 1, 1);
897       int s_1_0 = l.getAgastScore(point.x, point.y - 1, 1);
898       int s_2_0 = l.getAgastScore(point.x + 1, point.y - 1, 1);
899       int s_2_1 = l.getAgastScore(point.x + 1, point.y, 1);
900       int s_1_1 = l.getAgastScore(point.x, point.y, 1);
901       int s_0_1 = l.getAgastScore(point.x - 1, point.y, 1);
902       int s_0_2 = l.getAgastScore(point.x - 1, point.y + 1, 1);
903       int s_1_2 = l.getAgastScore(point.x, point.y + 1, 1);
904       int s_2_2 = l.getAgastScore(point.x + 1, point.y + 1, 1);
905       float delta_x, delta_y;
906       float max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x, delta_y);
907 
908       // store:
909       keypoints.push_back(cv::KeyPoint(float(point.x) + delta_x, float(point.y) + delta_y, basicSize_, -1, max, 0));
910 
911     }
912 
913     return;
914   }
915 
916   float x, y, scale, score;
917   for (int i = 0; i < layers_; i++)
918   {
919     BriskLayer& l = pyramid_[i];
920     const size_t num = agastPoints[i].size();
921     if (i == layers_ - 1)
922     {
923       for (size_t n = 0; n < num; n++)
924       {
925         const cv::Point2f& point = agastPoints.at(i)[n].pt;
926         // consider only 2D maxima...
927         if (!isMax2D(i, (int)point.x, (int)point.y))
928           continue;
929 
930         bool ismax;
931         float dx, dy;
932         getScoreMaxBelow(i, (int)point.x, (int)point.y, l.getAgastScore(point.x, point.y, safeThreshold_), ismax, dx, dy);
933         if (!ismax)
934           continue;
935 
936         // get the patch on this layer:
937         int s_0_0 = l.getAgastScore(point.x - 1, point.y - 1, 1);
938         int s_1_0 = l.getAgastScore(point.x, point.y - 1, 1);
939         int s_2_0 = l.getAgastScore(point.x + 1, point.y - 1, 1);
940         int s_2_1 = l.getAgastScore(point.x + 1, point.y, 1);
941         int s_1_1 = l.getAgastScore(point.x, point.y, 1);
942         int s_0_1 = l.getAgastScore(point.x - 1, point.y, 1);
943         int s_0_2 = l.getAgastScore(point.x - 1, point.y + 1, 1);
944         int s_1_2 = l.getAgastScore(point.x, point.y + 1, 1);
945         int s_2_2 = l.getAgastScore(point.x + 1, point.y + 1, 1);
946         float delta_x, delta_y;
947         float max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x, delta_y);
948 
949         // store:
950         keypoints.push_back(
951             cv::KeyPoint((float(point.x) + delta_x) * l.scale() + l.offset(),
952                          (float(point.y) + delta_y) * l.scale() + l.offset(), basicSize_ * l.scale(), -1, max, i));
953       }
954     }
955     else
956     {
957       // not the last layer:
958       for (size_t n = 0; n < num; n++)
959       {
960         const cv::Point2f& point = agastPoints.at(i)[n].pt;
961 
962         // first check if it is a maximum:
963         if (!isMax2D(i, (int)point.x, (int)point.y))
964           continue;
965 
966         // let's do the subpixel and float scale refinement:
967         bool ismax=false;
968         score = refine3D(i, (int)point.x, (int)point.y, x, y, scale, ismax);
969         if (!ismax)
970         {
971           continue;
972         }
973 
974         // finally store the detected keypoint:
975         if (score > float(threshold_))
976         {
977           keypoints.push_back(cv::KeyPoint(x, y, basicSize_ * scale, -1, score, i));
978         }
979       }
980     }
981   }
982 }
983 
984 // interpolated score access with recalculation when needed:
985 inline int
getScoreAbove(const int layer,const int x_layer,const int y_layer) const986 BriskScaleSpace::getScoreAbove(const int layer, const int x_layer, const int y_layer) const
987 {
988   CV_Assert(layer < layers_-1);
989   const BriskLayer& l = pyramid_[layer + 1];
990   if (layer % 2 == 0)
991   { // octave
992     const int sixths_x = 4 * x_layer - 1;
993     const int x_above = sixths_x / 6;
994     const int sixths_y = 4 * y_layer - 1;
995     const int y_above = sixths_y / 6;
996     const int r_x = (sixths_x % 6);
997     const int r_x_1 = 6 - r_x;
998     const int r_y = (sixths_y % 6);
999     const int r_y_1 = 6 - r_y;
1000     uchar score = 0xFF
1001         & ((r_x_1 * r_y_1 * l.getAgastScore(x_above, y_above, 1) + r_x * r_y_1
1002                                                                    * l.getAgastScore(x_above + 1, y_above, 1)
1003             + r_x_1 * r_y * l.getAgastScore(x_above, y_above + 1, 1)
1004             + r_x * r_y * l.getAgastScore(x_above + 1, y_above + 1, 1) + 18)
1005            / 36);
1006 
1007     return score;
1008   }
1009   else
1010   { // intra
1011     const int eighths_x = 6 * x_layer - 1;
1012     const int x_above = eighths_x / 8;
1013     const int eighths_y = 6 * y_layer - 1;
1014     const int y_above = eighths_y / 8;
1015     const int r_x = (eighths_x % 8);
1016     const int r_x_1 = 8 - r_x;
1017     const int r_y = (eighths_y % 8);
1018     const int r_y_1 = 8 - r_y;
1019     uchar score = 0xFF
1020         & ((r_x_1 * r_y_1 * l.getAgastScore(x_above, y_above, 1) + r_x * r_y_1
1021                                                                    * l.getAgastScore(x_above + 1, y_above, 1)
1022             + r_x_1 * r_y * l.getAgastScore(x_above, y_above + 1, 1)
1023             + r_x * r_y * l.getAgastScore(x_above + 1, y_above + 1, 1) + 32)
1024            / 64);
1025     return score;
1026   }
1027 }
1028 inline int
getScoreBelow(const int layer,const int x_layer,const int y_layer) const1029 BriskScaleSpace::getScoreBelow(const int layer, const int x_layer, const int y_layer) const
1030 {
1031   CV_Assert(layer);
1032   const BriskLayer& l = pyramid_[layer - 1];
1033   int sixth_x;
1034   int quarter_x;
1035   float xf;
1036   int sixth_y;
1037   int quarter_y;
1038   float yf;
1039 
1040   // scaling:
1041   float offs;
1042   float area;
1043   int scaling;
1044   int scaling2;
1045 
1046   if (layer % 2 == 0)
1047   { // octave
1048     sixth_x = 8 * x_layer + 1;
1049     xf = float(sixth_x) / 6.0f;
1050     sixth_y = 8 * y_layer + 1;
1051     yf = float(sixth_y) / 6.0f;
1052 
1053     // scaling:
1054     offs = 2.0f / 3.0f;
1055     area = 4.0f * offs * offs;
1056     scaling = (int)(4194304.0 / area);
1057     scaling2 = (int)(float(scaling) * area);
1058   }
1059   else
1060   {
1061     quarter_x = 6 * x_layer + 1;
1062     xf = float(quarter_x) / 4.0f;
1063     quarter_y = 6 * y_layer + 1;
1064     yf = float(quarter_y) / 4.0f;
1065 
1066     // scaling:
1067     offs = 3.0f / 4.0f;
1068     area = 4.0f * offs * offs;
1069     scaling = (int)(4194304.0 / area);
1070     scaling2 = (int)(float(scaling) * area);
1071   }
1072 
1073   // calculate borders
1074   const float x_1 = xf - offs;
1075   const float x1 = xf + offs;
1076   const float y_1 = yf - offs;
1077   const float y1 = yf + offs;
1078 
1079   const int x_left = int(x_1 + 0.5);
1080   const int y_top = int(y_1 + 0.5);
1081   const int x_right = int(x1 + 0.5);
1082   const int y_bottom = int(y1 + 0.5);
1083 
1084   // overlap area - multiplication factors:
1085   const float r_x_1 = float(x_left) - x_1 + 0.5f;
1086   const float r_y_1 = float(y_top) - y_1 + 0.5f;
1087   const float r_x1 = x1 - float(x_right) + 0.5f;
1088   const float r_y1 = y1 - float(y_bottom) + 0.5f;
1089   const int dx = x_right - x_left - 1;
1090   const int dy = y_bottom - y_top - 1;
1091   const int A = (int)((r_x_1 * r_y_1) * scaling);
1092   const int B = (int)((r_x1 * r_y_1) * scaling);
1093   const int C = (int)((r_x1 * r_y1) * scaling);
1094   const int D = (int)((r_x_1 * r_y1) * scaling);
1095   const int r_x_1_i = (int)(r_x_1 * scaling);
1096   const int r_y_1_i = (int)(r_y_1 * scaling);
1097   const int r_x1_i = (int)(r_x1 * scaling);
1098   const int r_y1_i = (int)(r_y1 * scaling);
1099 
1100   // first row:
1101   int ret_val = A * int(l.getAgastScore(x_left, y_top, 1));
1102   for (int X = 1; X <= dx; X++)
1103   {
1104     ret_val += r_y_1_i * int(l.getAgastScore(x_left + X, y_top, 1));
1105   }
1106   ret_val += B * int(l.getAgastScore(x_left + dx + 1, y_top, 1));
1107   // middle ones:
1108   for (int Y = 1; Y <= dy; Y++)
1109   {
1110     ret_val += r_x_1_i * int(l.getAgastScore(x_left, y_top + Y, 1));
1111 
1112     for (int X = 1; X <= dx; X++)
1113     {
1114       ret_val += int(l.getAgastScore(x_left + X, y_top + Y, 1)) * scaling;
1115     }
1116     ret_val += r_x1_i * int(l.getAgastScore(x_left + dx + 1, y_top + Y, 1));
1117   }
1118   // last row:
1119   ret_val += D * int(l.getAgastScore(x_left, y_top + dy + 1, 1));
1120   for (int X = 1; X <= dx; X++)
1121   {
1122     ret_val += r_y1_i * int(l.getAgastScore(x_left + X, y_top + dy + 1, 1));
1123   }
1124   ret_val += C * int(l.getAgastScore(x_left + dx + 1, y_top + dy + 1, 1));
1125 
1126   return ((ret_val + scaling2 / 2) / scaling2);
1127 }
1128 
1129 inline bool
isMax2D(const int layer,const int x_layer,const int y_layer)1130 BriskScaleSpace::isMax2D(const int layer, const int x_layer, const int y_layer)
1131 {
1132   const cv::Mat& scores = pyramid_[layer].scores();
1133   const int scorescols = scores.cols;
1134   const uchar* data = scores.ptr() + y_layer * scorescols + x_layer;
1135   // decision tree:
1136   const uchar center = (*data);
1137   data--;
1138   const uchar s_10 = *data;
1139   if (center < s_10)
1140     return false;
1141   data += 2;
1142   const uchar s10 = *data;
1143   if (center < s10)
1144     return false;
1145   data -= (scorescols + 1);
1146   const uchar s0_1 = *data;
1147   if (center < s0_1)
1148     return false;
1149   data += 2 * scorescols;
1150   const uchar s01 = *data;
1151   if (center < s01)
1152     return false;
1153   data--;
1154   const uchar s_11 = *data;
1155   if (center < s_11)
1156     return false;
1157   data += 2;
1158   const uchar s11 = *data;
1159   if (center < s11)
1160     return false;
1161   data -= 2 * scorescols;
1162   const uchar s1_1 = *data;
1163   if (center < s1_1)
1164     return false;
1165   data -= 2;
1166   const uchar s_1_1 = *data;
1167   if (center < s_1_1)
1168     return false;
1169 
1170   // reject neighbor maxima
1171   std::vector<int> delta;
1172   // put together a list of 2d-offsets to where the maximum is also reached
1173   if (center == s_1_1)
1174   {
1175     delta.push_back(-1);
1176     delta.push_back(-1);
1177   }
1178   if (center == s0_1)
1179   {
1180     delta.push_back(0);
1181     delta.push_back(-1);
1182   }
1183   if (center == s1_1)
1184   {
1185     delta.push_back(1);
1186     delta.push_back(-1);
1187   }
1188   if (center == s_10)
1189   {
1190     delta.push_back(-1);
1191     delta.push_back(0);
1192   }
1193   if (center == s10)
1194   {
1195     delta.push_back(1);
1196     delta.push_back(0);
1197   }
1198   if (center == s_11)
1199   {
1200     delta.push_back(-1);
1201     delta.push_back(1);
1202   }
1203   if (center == s01)
1204   {
1205     delta.push_back(0);
1206     delta.push_back(1);
1207   }
1208   if (center == s11)
1209   {
1210     delta.push_back(1);
1211     delta.push_back(1);
1212   }
1213   const unsigned int deltasize = (unsigned int)delta.size();
1214   if (deltasize != 0)
1215   {
1216     // in this case, we have to analyze the situation more carefully:
1217     // the values are gaussian blurred and then we really decide
1218     data = scores.ptr() + y_layer * scorescols + x_layer;
1219     int smoothedcenter = 4 * center + 2 * (s_10 + s10 + s0_1 + s01) + s_1_1 + s1_1 + s_11 + s11;
1220     for (unsigned int i = 0; i < deltasize; i += 2)
1221     {
1222       data = scores.ptr() + (y_layer - 1 + delta[i + 1]) * scorescols + x_layer + delta[i] - 1;
1223       int othercenter = *data;
1224       data++;
1225       othercenter += 2 * (*data);
1226       data++;
1227       othercenter += *data;
1228       data += scorescols;
1229       othercenter += 2 * (*data);
1230       data--;
1231       othercenter += 4 * (*data);
1232       data--;
1233       othercenter += 2 * (*data);
1234       data += scorescols;
1235       othercenter += *data;
1236       data++;
1237       othercenter += 2 * (*data);
1238       data++;
1239       othercenter += *data;
1240       if (othercenter > smoothedcenter)
1241         return false;
1242     }
1243   }
1244   return true;
1245 }
1246 
1247 // 3D maximum refinement centered around (x_layer,y_layer)
1248 inline float
refine3D(const int layer,const int x_layer,const int y_layer,float & x,float & y,float & scale,bool & ismax) const1249 BriskScaleSpace::refine3D(const int layer, const int x_layer, const int y_layer, float& x, float& y, float& scale,
1250                           bool& ismax) const
1251 {
1252   ismax = true;
1253   const BriskLayer& thisLayer = pyramid_[layer];
1254   const int center = thisLayer.getAgastScore(x_layer, y_layer, 1);
1255 
1256   // check and get above maximum:
1257   float delta_x_above = 0, delta_y_above = 0;
1258   float max_above = getScoreMaxAbove(layer, x_layer, y_layer, center, ismax, delta_x_above, delta_y_above);
1259 
1260   if (!ismax)
1261     return 0.0f;
1262 
1263   float max; // to be returned
1264 
1265   if (layer % 2 == 0)
1266   { // on octave
1267     // treat the patch below:
1268     float delta_x_below, delta_y_below;
1269     float max_below_float;
1270     int max_below = 0;
1271     if (layer == 0)
1272     {
1273       // guess the lower intra octave...
1274       const BriskLayer& l = pyramid_[0];
1275       int s_0_0 = l.getAgastScore_5_8(x_layer - 1, y_layer - 1, 1);
1276       max_below = s_0_0;
1277       int s_1_0 = l.getAgastScore_5_8(x_layer, y_layer - 1, 1);
1278       max_below = std::max(s_1_0, max_below);
1279       int s_2_0 = l.getAgastScore_5_8(x_layer + 1, y_layer - 1, 1);
1280       max_below = std::max(s_2_0, max_below);
1281       int s_2_1 = l.getAgastScore_5_8(x_layer + 1, y_layer, 1);
1282       max_below = std::max(s_2_1, max_below);
1283       int s_1_1 = l.getAgastScore_5_8(x_layer, y_layer, 1);
1284       max_below = std::max(s_1_1, max_below);
1285       int s_0_1 = l.getAgastScore_5_8(x_layer - 1, y_layer, 1);
1286       max_below = std::max(s_0_1, max_below);
1287       int s_0_2 = l.getAgastScore_5_8(x_layer - 1, y_layer + 1, 1);
1288       max_below = std::max(s_0_2, max_below);
1289       int s_1_2 = l.getAgastScore_5_8(x_layer, y_layer + 1, 1);
1290       max_below = std::max(s_1_2, max_below);
1291       int s_2_2 = l.getAgastScore_5_8(x_layer + 1, y_layer + 1, 1);
1292       max_below = std::max(s_2_2, max_below);
1293 
1294       max_below_float = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_below,
1295                                    delta_y_below);
1296       max_below_float = (float)max_below;
1297     }
1298     else
1299     {
1300       max_below_float = getScoreMaxBelow(layer, x_layer, y_layer, center, ismax, delta_x_below, delta_y_below);
1301       if (!ismax)
1302         return 0;
1303     }
1304 
1305     // get the patch on this layer:
1306     int s_0_0 = thisLayer.getAgastScore(x_layer - 1, y_layer - 1, 1);
1307     int s_1_0 = thisLayer.getAgastScore(x_layer, y_layer - 1, 1);
1308     int s_2_0 = thisLayer.getAgastScore(x_layer + 1, y_layer - 1, 1);
1309     int s_2_1 = thisLayer.getAgastScore(x_layer + 1, y_layer, 1);
1310     int s_1_1 = thisLayer.getAgastScore(x_layer, y_layer, 1);
1311     int s_0_1 = thisLayer.getAgastScore(x_layer - 1, y_layer, 1);
1312     int s_0_2 = thisLayer.getAgastScore(x_layer - 1, y_layer + 1, 1);
1313     int s_1_2 = thisLayer.getAgastScore(x_layer, y_layer + 1, 1);
1314     int s_2_2 = thisLayer.getAgastScore(x_layer + 1, y_layer + 1, 1);
1315     float delta_x_layer, delta_y_layer;
1316     float max_layer = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_layer,
1317                                  delta_y_layer);
1318 
1319     // calculate the relative scale (1D maximum):
1320     if (layer == 0)
1321     {
1322       scale = refine1D_2(max_below_float, std::max(float(center), max_layer), max_above, max);
1323     }
1324     else
1325       scale = refine1D(max_below_float, std::max(float(center), max_layer), max_above, max);
1326 
1327     if (scale > 1.0)
1328     {
1329       // interpolate the position:
1330       const float r0 = (1.5f - scale) / .5f;
1331       const float r1 = 1.0f - r0;
1332       x = (r0 * delta_x_layer + r1 * delta_x_above + float(x_layer)) * thisLayer.scale() + thisLayer.offset();
1333       y = (r0 * delta_y_layer + r1 * delta_y_above + float(y_layer)) * thisLayer.scale() + thisLayer.offset();
1334     }
1335     else
1336     {
1337       if (layer == 0)
1338       {
1339         // interpolate the position:
1340         const float r0 = (scale - 0.5f) / 0.5f;
1341         const float r_1 = 1.0f - r0;
1342         x = r0 * delta_x_layer + r_1 * delta_x_below + float(x_layer);
1343         y = r0 * delta_y_layer + r_1 * delta_y_below + float(y_layer);
1344       }
1345       else
1346       {
1347         // interpolate the position:
1348         const float r0 = (scale - 0.75f) / 0.25f;
1349         const float r_1 = 1.0f - r0;
1350         x = (r0 * delta_x_layer + r_1 * delta_x_below + float(x_layer)) * thisLayer.scale() + thisLayer.offset();
1351         y = (r0 * delta_y_layer + r_1 * delta_y_below + float(y_layer)) * thisLayer.scale() + thisLayer.offset();
1352       }
1353     }
1354   }
1355   else
1356   {
1357     // on intra
1358     // check the patch below:
1359     float delta_x_below, delta_y_below;
1360     float max_below = getScoreMaxBelow(layer, x_layer, y_layer, center, ismax, delta_x_below, delta_y_below);
1361     if (!ismax)
1362       return 0.0f;
1363 
1364     // get the patch on this layer:
1365     int s_0_0 = thisLayer.getAgastScore(x_layer - 1, y_layer - 1, 1);
1366     int s_1_0 = thisLayer.getAgastScore(x_layer, y_layer - 1, 1);
1367     int s_2_0 = thisLayer.getAgastScore(x_layer + 1, y_layer - 1, 1);
1368     int s_2_1 = thisLayer.getAgastScore(x_layer + 1, y_layer, 1);
1369     int s_1_1 = thisLayer.getAgastScore(x_layer, y_layer, 1);
1370     int s_0_1 = thisLayer.getAgastScore(x_layer - 1, y_layer, 1);
1371     int s_0_2 = thisLayer.getAgastScore(x_layer - 1, y_layer + 1, 1);
1372     int s_1_2 = thisLayer.getAgastScore(x_layer, y_layer + 1, 1);
1373     int s_2_2 = thisLayer.getAgastScore(x_layer + 1, y_layer + 1, 1);
1374     float delta_x_layer, delta_y_layer;
1375     float max_layer = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, delta_x_layer,
1376                                  delta_y_layer);
1377 
1378     // calculate the relative scale (1D maximum):
1379     scale = refine1D_1(max_below, std::max(float(center), max_layer), max_above, max);
1380     if (scale > 1.0)
1381     {
1382       // interpolate the position:
1383       const float r0 = 4.0f - scale * 3.0f;
1384       const float r1 = 1.0f - r0;
1385       x = (r0 * delta_x_layer + r1 * delta_x_above + float(x_layer)) * thisLayer.scale() + thisLayer.offset();
1386       y = (r0 * delta_y_layer + r1 * delta_y_above + float(y_layer)) * thisLayer.scale() + thisLayer.offset();
1387     }
1388     else
1389     {
1390       // interpolate the position:
1391       const float r0 = scale * 3.0f - 2.0f;
1392       const float r_1 = 1.0f - r0;
1393       x = (r0 * delta_x_layer + r_1 * delta_x_below + float(x_layer)) * thisLayer.scale() + thisLayer.offset();
1394       y = (r0 * delta_y_layer + r_1 * delta_y_below + float(y_layer)) * thisLayer.scale() + thisLayer.offset();
1395     }
1396   }
1397 
1398   // calculate the absolute scale:
1399   scale *= thisLayer.scale();
1400 
1401   // that's it, return the refined maximum:
1402   return max;
1403 }
1404 
1405 // return the maximum of score patches above or below
1406 inline float
getScoreMaxAbove(const int layer,const int x_layer,const int y_layer,const int threshold,bool & ismax,float & dx,float & dy) const1407 BriskScaleSpace::getScoreMaxAbove(const int layer, const int x_layer, const int y_layer, const int threshold,
1408                                   bool& ismax, float& dx, float& dy) const
1409 {
1410 
1411   ismax = false;
1412   // relevant floating point coordinates
1413   float x_1;
1414   float x1;
1415   float y_1;
1416   float y1;
1417 
1418   // the layer above
1419   CV_Assert(layer + 1 < layers_);
1420   const BriskLayer& layerAbove = pyramid_[layer + 1];
1421 
1422   if (layer % 2 == 0)
1423   {
1424     // octave
1425     x_1 = float(4 * (x_layer) - 1 - 2) / 6.0f;
1426     x1 = float(4 * (x_layer) - 1 + 2) / 6.0f;
1427     y_1 = float(4 * (y_layer) - 1 - 2) / 6.0f;
1428     y1 = float(4 * (y_layer) - 1 + 2) / 6.0f;
1429   }
1430   else
1431   {
1432     // intra
1433     x_1 = float(6 * (x_layer) - 1 - 3) / 8.0f;
1434     x1 = float(6 * (x_layer) - 1 + 3) / 8.0f;
1435     y_1 = float(6 * (y_layer) - 1 - 3) / 8.0f;
1436     y1 = float(6 * (y_layer) - 1 + 3) / 8.0f;
1437   }
1438 
1439   // check the first row
1440   int max_x = (int)x_1 + 1;
1441   int max_y = (int)y_1 + 1;
1442   float tmp_max;
1443   float maxval = (float)layerAbove.getAgastScore(x_1, y_1, 1);
1444   if (maxval > threshold)
1445     return 0;
1446   for (int x = (int)x_1 + 1; x <= int(x1); x++)
1447   {
1448     tmp_max = (float)layerAbove.getAgastScore(float(x), y_1, 1);
1449     if (tmp_max > threshold)
1450       return 0;
1451     if (tmp_max > maxval)
1452     {
1453       maxval = tmp_max;
1454       max_x = x;
1455     }
1456   }
1457   tmp_max = (float)layerAbove.getAgastScore(x1, y_1, 1);
1458   if (tmp_max > threshold)
1459     return 0;
1460   if (tmp_max > maxval)
1461   {
1462     maxval = tmp_max;
1463     max_x = int(x1);
1464   }
1465 
1466   // middle rows
1467   for (int y = (int)y_1 + 1; y <= int(y1); y++)
1468   {
1469     tmp_max = (float)layerAbove.getAgastScore(x_1, float(y), 1);
1470     if (tmp_max > threshold)
1471       return 0;
1472     if (tmp_max > maxval)
1473     {
1474       maxval = tmp_max;
1475       max_x = int(x_1 + 1);
1476       max_y = y;
1477     }
1478     for (int x = (int)x_1 + 1; x <= int(x1); x++)
1479     {
1480       tmp_max = (float)layerAbove.getAgastScore(x, y, 1);
1481       if (tmp_max > threshold)
1482         return 0;
1483       if (tmp_max > maxval)
1484       {
1485         maxval = tmp_max;
1486         max_x = x;
1487         max_y = y;
1488       }
1489     }
1490     tmp_max = (float)layerAbove.getAgastScore(x1, float(y), 1);
1491     if (tmp_max > threshold)
1492       return 0;
1493     if (tmp_max > maxval)
1494     {
1495       maxval = tmp_max;
1496       max_x = int(x1);
1497       max_y = y;
1498     }
1499   }
1500 
1501   // bottom row
1502   tmp_max = (float)layerAbove.getAgastScore(x_1, y1, 1);
1503   if (tmp_max > maxval)
1504   {
1505     maxval = tmp_max;
1506     max_x = int(x_1 + 1);
1507     max_y = int(y1);
1508   }
1509   for (int x = (int)x_1 + 1; x <= int(x1); x++)
1510   {
1511     tmp_max = (float)layerAbove.getAgastScore(float(x), y1, 1);
1512     if (tmp_max > maxval)
1513     {
1514       maxval = tmp_max;
1515       max_x = x;
1516       max_y = int(y1);
1517     }
1518   }
1519   tmp_max = (float)layerAbove.getAgastScore(x1, y1, 1);
1520   if (tmp_max > maxval)
1521   {
1522     maxval = tmp_max;
1523     max_x = int(x1);
1524     max_y = int(y1);
1525   }
1526 
1527   //find dx/dy:
1528   int s_0_0 = layerAbove.getAgastScore(max_x - 1, max_y - 1, 1);
1529   int s_1_0 = layerAbove.getAgastScore(max_x, max_y - 1, 1);
1530   int s_2_0 = layerAbove.getAgastScore(max_x + 1, max_y - 1, 1);
1531   int s_2_1 = layerAbove.getAgastScore(max_x + 1, max_y, 1);
1532   int s_1_1 = layerAbove.getAgastScore(max_x, max_y, 1);
1533   int s_0_1 = layerAbove.getAgastScore(max_x - 1, max_y, 1);
1534   int s_0_2 = layerAbove.getAgastScore(max_x - 1, max_y + 1, 1);
1535   int s_1_2 = layerAbove.getAgastScore(max_x, max_y + 1, 1);
1536   int s_2_2 = layerAbove.getAgastScore(max_x + 1, max_y + 1, 1);
1537   float dx_1, dy_1;
1538   float refined_max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, dx_1, dy_1);
1539 
1540   // calculate dx/dy in above coordinates
1541   float real_x = float(max_x) + dx_1;
1542   float real_y = float(max_y) + dy_1;
1543   bool returnrefined = true;
1544   if (layer % 2 == 0)
1545   {
1546     dx = (real_x * 6.0f + 1.0f) / 4.0f - float(x_layer);
1547     dy = (real_y * 6.0f + 1.0f) / 4.0f - float(y_layer);
1548   }
1549   else
1550   {
1551     dx = (real_x * 8.0f + 1.0f) / 6.0f - float(x_layer);
1552     dy = (real_y * 8.0f + 1.0f) / 6.0f - float(y_layer);
1553   }
1554 
1555   // saturate
1556   if (dx > 1.0f)
1557   {
1558     dx = 1.0f;
1559     returnrefined = false;
1560   }
1561   if (dx < -1.0f)
1562   {
1563     dx = -1.0f;
1564     returnrefined = false;
1565   }
1566   if (dy > 1.0f)
1567   {
1568     dy = 1.0f;
1569     returnrefined = false;
1570   }
1571   if (dy < -1.0f)
1572   {
1573     dy = -1.0f;
1574     returnrefined = false;
1575   }
1576 
1577   // done and ok.
1578   ismax = true;
1579   if (returnrefined)
1580   {
1581     return std::max(refined_max, maxval);
1582   }
1583   return maxval;
1584 }
1585 
1586 inline float
getScoreMaxBelow(const int layer,const int x_layer,const int y_layer,const int threshold,bool & ismax,float & dx,float & dy) const1587 BriskScaleSpace::getScoreMaxBelow(const int layer, const int x_layer, const int y_layer, const int threshold,
1588                                   bool& ismax, float& dx, float& dy) const
1589 {
1590   ismax = false;
1591 
1592   // relevant floating point coordinates
1593   float x_1;
1594   float x1;
1595   float y_1;
1596   float y1;
1597 
1598   if (layer % 2 == 0)
1599   {
1600     // octave
1601     x_1 = float(8 * (x_layer) + 1 - 4) / 6.0f;
1602     x1 = float(8 * (x_layer) + 1 + 4) / 6.0f;
1603     y_1 = float(8 * (y_layer) + 1 - 4) / 6.0f;
1604     y1 = float(8 * (y_layer) + 1 + 4) / 6.0f;
1605   }
1606   else
1607   {
1608     x_1 = float(6 * (x_layer) + 1 - 3) / 4.0f;
1609     x1 = float(6 * (x_layer) + 1 + 3) / 4.0f;
1610     y_1 = float(6 * (y_layer) + 1 - 3) / 4.0f;
1611     y1 = float(6 * (y_layer) + 1 + 3) / 4.0f;
1612   }
1613 
1614   // the layer below
1615   CV_Assert(layer > 0);
1616   const BriskLayer& layerBelow = pyramid_[layer - 1];
1617 
1618   // check the first row
1619   int max_x = (int)x_1 + 1;
1620   int max_y = (int)y_1 + 1;
1621   float tmp_max;
1622   float max = (float)layerBelow.getAgastScore(x_1, y_1, 1);
1623   if (max > threshold)
1624     return 0;
1625   for (int x = (int)x_1 + 1; x <= int(x1); x++)
1626   {
1627     tmp_max = (float)layerBelow.getAgastScore(float(x), y_1, 1);
1628     if (tmp_max > threshold)
1629       return 0;
1630     if (tmp_max > max)
1631     {
1632       max = tmp_max;
1633       max_x = x;
1634     }
1635   }
1636   tmp_max = (float)layerBelow.getAgastScore(x1, y_1, 1);
1637   if (tmp_max > threshold)
1638     return 0;
1639   if (tmp_max > max)
1640   {
1641     max = tmp_max;
1642     max_x = int(x1);
1643   }
1644 
1645   // middle rows
1646   for (int y = (int)y_1 + 1; y <= int(y1); y++)
1647   {
1648     tmp_max = (float)layerBelow.getAgastScore(x_1, float(y), 1);
1649     if (tmp_max > threshold)
1650       return 0;
1651     if (tmp_max > max)
1652     {
1653       max = tmp_max;
1654       max_x = int(x_1 + 1);
1655       max_y = y;
1656     }
1657     for (int x = (int)x_1 + 1; x <= int(x1); x++)
1658     {
1659       tmp_max = (float)layerBelow.getAgastScore(x, y, 1);
1660       if (tmp_max > threshold)
1661         return 0;
1662       if (tmp_max == max)
1663       {
1664         const int t1 = 2
1665             * (layerBelow.getAgastScore(x - 1, y, 1) + layerBelow.getAgastScore(x + 1, y, 1)
1666                + layerBelow.getAgastScore(x, y + 1, 1) + layerBelow.getAgastScore(x, y - 1, 1))
1667                        + (layerBelow.getAgastScore(x + 1, y + 1, 1) + layerBelow.getAgastScore(x - 1, y + 1, 1)
1668                           + layerBelow.getAgastScore(x + 1, y - 1, 1) + layerBelow.getAgastScore(x - 1, y - 1, 1));
1669         const int t2 = 2
1670             * (layerBelow.getAgastScore(max_x - 1, max_y, 1) + layerBelow.getAgastScore(max_x + 1, max_y, 1)
1671                + layerBelow.getAgastScore(max_x, max_y + 1, 1) + layerBelow.getAgastScore(max_x, max_y - 1, 1))
1672                        + (layerBelow.getAgastScore(max_x + 1, max_y + 1, 1) + layerBelow.getAgastScore(max_x - 1,
1673                                                                                                        max_y + 1, 1)
1674                           + layerBelow.getAgastScore(max_x + 1, max_y - 1, 1)
1675                           + layerBelow.getAgastScore(max_x - 1, max_y - 1, 1));
1676         if (t1 > t2)
1677         {
1678           max_x = x;
1679           max_y = y;
1680         }
1681       }
1682       if (tmp_max > max)
1683       {
1684         max = tmp_max;
1685         max_x = x;
1686         max_y = y;
1687       }
1688     }
1689     tmp_max = (float)layerBelow.getAgastScore(x1, float(y), 1);
1690     if (tmp_max > threshold)
1691       return 0;
1692     if (tmp_max > max)
1693     {
1694       max = tmp_max;
1695       max_x = int(x1);
1696       max_y = y;
1697     }
1698   }
1699 
1700   // bottom row
1701   tmp_max = (float)layerBelow.getAgastScore(x_1, y1, 1);
1702   if (tmp_max > max)
1703   {
1704     max = tmp_max;
1705     max_x = int(x_1 + 1);
1706     max_y = int(y1);
1707   }
1708   for (int x = (int)x_1 + 1; x <= int(x1); x++)
1709   {
1710     tmp_max = (float)layerBelow.getAgastScore(float(x), y1, 1);
1711     if (tmp_max > max)
1712     {
1713       max = tmp_max;
1714       max_x = x;
1715       max_y = int(y1);
1716     }
1717   }
1718   tmp_max = (float)layerBelow.getAgastScore(x1, y1, 1);
1719   if (tmp_max > max)
1720   {
1721     max = tmp_max;
1722     max_x = int(x1);
1723     max_y = int(y1);
1724   }
1725 
1726   //find dx/dy:
1727   int s_0_0 = layerBelow.getAgastScore(max_x - 1, max_y - 1, 1);
1728   int s_1_0 = layerBelow.getAgastScore(max_x, max_y - 1, 1);
1729   int s_2_0 = layerBelow.getAgastScore(max_x + 1, max_y - 1, 1);
1730   int s_2_1 = layerBelow.getAgastScore(max_x + 1, max_y, 1);
1731   int s_1_1 = layerBelow.getAgastScore(max_x, max_y, 1);
1732   int s_0_1 = layerBelow.getAgastScore(max_x - 1, max_y, 1);
1733   int s_0_2 = layerBelow.getAgastScore(max_x - 1, max_y + 1, 1);
1734   int s_1_2 = layerBelow.getAgastScore(max_x, max_y + 1, 1);
1735   int s_2_2 = layerBelow.getAgastScore(max_x + 1, max_y + 1, 1);
1736   float dx_1, dy_1;
1737   float refined_max = subpixel2D(s_0_0, s_0_1, s_0_2, s_1_0, s_1_1, s_1_2, s_2_0, s_2_1, s_2_2, dx_1, dy_1);
1738 
1739   // calculate dx/dy in above coordinates
1740   float real_x = float(max_x) + dx_1;
1741   float real_y = float(max_y) + dy_1;
1742   bool returnrefined = true;
1743   if (layer % 2 == 0)
1744   {
1745     dx = (float)((real_x * 6.0 + 1.0) / 8.0) - float(x_layer);
1746     dy = (float)((real_y * 6.0 + 1.0) / 8.0) - float(y_layer);
1747   }
1748   else
1749   {
1750     dx = (float)((real_x * 4.0 - 1.0) / 6.0) - float(x_layer);
1751     dy = (float)((real_y * 4.0 - 1.0) / 6.0) - float(y_layer);
1752   }
1753 
1754   // saturate
1755   if (dx > 1.0)
1756   {
1757     dx = 1.0f;
1758     returnrefined = false;
1759   }
1760   if (dx < -1.0f)
1761   {
1762     dx = -1.0f;
1763     returnrefined = false;
1764   }
1765   if (dy > 1.0f)
1766   {
1767     dy = 1.0f;
1768     returnrefined = false;
1769   }
1770   if (dy < -1.0f)
1771   {
1772     dy = -1.0f;
1773     returnrefined = false;
1774   }
1775 
1776   // done and ok.
1777   ismax = true;
1778   if (returnrefined)
1779   {
1780     return std::max(refined_max, max);
1781   }
1782   return max;
1783 }
1784 
1785 inline float
refine1D(const float s_05,const float s0,const float s05,float & max) const1786 BriskScaleSpace::refine1D(const float s_05, const float s0, const float s05, float& max) const
1787 {
1788   int i_05 = int(1024.0 * s_05 + 0.5);
1789   int i0 = int(1024.0 * s0 + 0.5);
1790   int i05 = int(1024.0 * s05 + 0.5);
1791 
1792   //   16.0000  -24.0000    8.0000
1793   //  -40.0000   54.0000  -14.0000
1794   //   24.0000  -27.0000    6.0000
1795 
1796   int three_a = 16 * i_05 - 24 * i0 + 8 * i05;
1797   // second derivative must be negative:
1798   if (three_a >= 0)
1799   {
1800     if (s0 >= s_05 && s0 >= s05)
1801     {
1802       max = s0;
1803       return 1.0f;
1804     }
1805     if (s_05 >= s0 && s_05 >= s05)
1806     {
1807       max = s_05;
1808       return 0.75f;
1809     }
1810     if (s05 >= s0 && s05 >= s_05)
1811     {
1812       max = s05;
1813       return 1.5f;
1814     }
1815   }
1816 
1817   int three_b = -40 * i_05 + 54 * i0 - 14 * i05;
1818   // calculate max location:
1819   float ret_val = -float(three_b) / float(2 * three_a);
1820   // saturate and return
1821   if (ret_val < 0.75)
1822     ret_val = 0.75;
1823   else if (ret_val > 1.5)
1824     ret_val = 1.5; // allow to be slightly off bounds ...?
1825   int three_c = +24 * i_05 - 27 * i0 + 6 * i05;
1826   max = float(three_c) + float(three_a) * ret_val * ret_val + float(three_b) * ret_val;
1827   max /= 3072.0f;
1828   return ret_val;
1829 }
1830 
1831 inline float
refine1D_1(const float s_05,const float s0,const float s05,float & max) const1832 BriskScaleSpace::refine1D_1(const float s_05, const float s0, const float s05, float& max) const
1833 {
1834   int i_05 = int(1024.0 * s_05 + 0.5);
1835   int i0 = int(1024.0 * s0 + 0.5);
1836   int i05 = int(1024.0 * s05 + 0.5);
1837 
1838   //  4.5000   -9.0000    4.5000
1839   //-10.5000   18.0000   -7.5000
1840   //  6.0000   -8.0000    3.0000
1841 
1842   int two_a = 9 * i_05 - 18 * i0 + 9 * i05;
1843   // second derivative must be negative:
1844   if (two_a >= 0)
1845   {
1846     if (s0 >= s_05 && s0 >= s05)
1847     {
1848       max = s0;
1849       return 1.0f;
1850     }
1851     if (s_05 >= s0 && s_05 >= s05)
1852     {
1853       max = s_05;
1854       return 0.6666666666666666666666666667f;
1855     }
1856     if (s05 >= s0 && s05 >= s_05)
1857     {
1858       max = s05;
1859       return 1.3333333333333333333333333333f;
1860     }
1861   }
1862 
1863   int two_b = -21 * i_05 + 36 * i0 - 15 * i05;
1864   // calculate max location:
1865   float ret_val = -float(two_b) / float(2 * two_a);
1866   // saturate and return
1867   if (ret_val < 0.6666666666666666666666666667f)
1868     ret_val = 0.666666666666666666666666667f;
1869   else if (ret_val > 1.33333333333333333333333333f)
1870     ret_val = 1.333333333333333333333333333f;
1871   int two_c = +12 * i_05 - 16 * i0 + 6 * i05;
1872   max = float(two_c) + float(two_a) * ret_val * ret_val + float(two_b) * ret_val;
1873   max /= 2048.0f;
1874   return ret_val;
1875 }
1876 
1877 inline float
refine1D_2(const float s_05,const float s0,const float s05,float & max) const1878 BriskScaleSpace::refine1D_2(const float s_05, const float s0, const float s05, float& max) const
1879 {
1880   int i_05 = int(1024.0 * s_05 + 0.5);
1881   int i0 = int(1024.0 * s0 + 0.5);
1882   int i05 = int(1024.0 * s05 + 0.5);
1883 
1884   //   18.0000  -30.0000   12.0000
1885   //  -45.0000   65.0000  -20.0000
1886   //   27.0000  -30.0000    8.0000
1887 
1888   int a = 2 * i_05 - 4 * i0 + 2 * i05;
1889   // second derivative must be negative:
1890   if (a >= 0)
1891   {
1892     if (s0 >= s_05 && s0 >= s05)
1893     {
1894       max = s0;
1895       return 1.0f;
1896     }
1897     if (s_05 >= s0 && s_05 >= s05)
1898     {
1899       max = s_05;
1900       return 0.7f;
1901     }
1902     if (s05 >= s0 && s05 >= s_05)
1903     {
1904       max = s05;
1905       return 1.5f;
1906     }
1907   }
1908 
1909   int b = -5 * i_05 + 8 * i0 - 3 * i05;
1910   // calculate max location:
1911   float ret_val = -float(b) / float(2 * a);
1912   // saturate and return
1913   if (ret_val < 0.7f)
1914     ret_val = 0.7f;
1915   else if (ret_val > 1.5f)
1916     ret_val = 1.5f; // allow to be slightly off bounds ...?
1917   int c = +3 * i_05 - 3 * i0 + 1 * i05;
1918   max = float(c) + float(a) * ret_val * ret_val + float(b) * ret_val;
1919   max /= 1024;
1920   return ret_val;
1921 }
1922 
1923 inline float
subpixel2D(const int s_0_0,const int s_0_1,const int s_0_2,const int s_1_0,const int s_1_1,const int s_1_2,const int s_2_0,const int s_2_1,const int s_2_2,float & delta_x,float & delta_y) const1924 BriskScaleSpace::subpixel2D(const int s_0_0, const int s_0_1, const int s_0_2, const int s_1_0, const int s_1_1,
1925                             const int s_1_2, const int s_2_0, const int s_2_1, const int s_2_2, float& delta_x,
1926                             float& delta_y) const
1927 {
1928 
1929   // the coefficients of the 2d quadratic function least-squares fit:
1930   int tmp1 = s_0_0 + s_0_2 - 2 * s_1_1 + s_2_0 + s_2_2;
1931   int coeff1 = 3 * (tmp1 + s_0_1 - ((s_1_0 + s_1_2) << 1) + s_2_1);
1932   int coeff2 = 3 * (tmp1 - ((s_0_1 + s_2_1) << 1) + s_1_0 + s_1_2);
1933   int tmp2 = s_0_2 - s_2_0;
1934   int tmp3 = (s_0_0 + tmp2 - s_2_2);
1935   int tmp4 = tmp3 - 2 * tmp2;
1936   int coeff3 = -3 * (tmp3 + s_0_1 - s_2_1);
1937   int coeff4 = -3 * (tmp4 + s_1_0 - s_1_2);
1938   int coeff5 = (s_0_0 - s_0_2 - s_2_0 + s_2_2) << 2;
1939   int coeff6 = -(s_0_0 + s_0_2 - ((s_1_0 + s_0_1 + s_1_2 + s_2_1) << 1) - 5 * s_1_1 + s_2_0 + s_2_2) << 1;
1940 
1941   // 2nd derivative test:
1942   int H_det = 4 * coeff1 * coeff2 - coeff5 * coeff5;
1943 
1944   if (H_det == 0)
1945   {
1946     delta_x = 0.0f;
1947     delta_y = 0.0f;
1948     return float(coeff6) / 18.0f;
1949   }
1950 
1951   if (!(H_det > 0 && coeff1 < 0))
1952   {
1953     // The maximum must be at the one of the 4 patch corners.
1954     int tmp_max = coeff3 + coeff4 + coeff5;
1955     delta_x = 1.0f;
1956     delta_y = 1.0f;
1957 
1958     int tmp = -coeff3 + coeff4 - coeff5;
1959     if (tmp > tmp_max)
1960     {
1961       tmp_max = tmp;
1962       delta_x = -1.0f;
1963       delta_y = 1.0f;
1964     }
1965     tmp = coeff3 - coeff4 - coeff5;
1966     if (tmp > tmp_max)
1967     {
1968       tmp_max = tmp;
1969       delta_x = 1.0f;
1970       delta_y = -1.0f;
1971     }
1972     tmp = -coeff3 - coeff4 + coeff5;
1973     if (tmp > tmp_max)
1974     {
1975       tmp_max = tmp;
1976       delta_x = -1.0f;
1977       delta_y = -1.0f;
1978     }
1979     return float(tmp_max + coeff1 + coeff2 + coeff6) / 18.0f;
1980   }
1981 
1982   // this is hopefully the normal outcome of the Hessian test
1983   delta_x = float(2 * coeff2 * coeff3 - coeff4 * coeff5) / float(-H_det);
1984   delta_y = float(2 * coeff1 * coeff4 - coeff3 * coeff5) / float(-H_det);
1985   // TODO: this is not correct, but easy, so perform a real boundary maximum search:
1986   bool tx = false;
1987   bool tx_ = false;
1988   bool ty = false;
1989   bool ty_ = false;
1990   if (delta_x > 1.0)
1991     tx = true;
1992   else if (delta_x < -1.0)
1993     tx_ = true;
1994   if (delta_y > 1.0)
1995     ty = true;
1996   if (delta_y < -1.0)
1997     ty_ = true;
1998 
1999   if (tx || tx_ || ty || ty_)
2000   {
2001     // get two candidates:
2002     float delta_x1 = 0.0f, delta_x2 = 0.0f, delta_y1 = 0.0f, delta_y2 = 0.0f;
2003     if (tx)
2004     {
2005       delta_x1 = 1.0f;
2006       delta_y1 = -float(coeff4 + coeff5) / float(2 * coeff2);
2007       if (delta_y1 > 1.0f)
2008         delta_y1 = 1.0f;
2009       else if (delta_y1 < -1.0f)
2010         delta_y1 = -1.0f;
2011     }
2012     else if (tx_)
2013     {
2014       delta_x1 = -1.0f;
2015       delta_y1 = -float(coeff4 - coeff5) / float(2 * coeff2);
2016       if (delta_y1 > 1.0f)
2017         delta_y1 = 1.0f;
2018       else if (delta_y1 < -1.0)
2019         delta_y1 = -1.0f;
2020     }
2021     if (ty)
2022     {
2023       delta_y2 = 1.0f;
2024       delta_x2 = -float(coeff3 + coeff5) / float(2 * coeff1);
2025       if (delta_x2 > 1.0f)
2026         delta_x2 = 1.0f;
2027       else if (delta_x2 < -1.0f)
2028         delta_x2 = -1.0f;
2029     }
2030     else if (ty_)
2031     {
2032       delta_y2 = -1.0f;
2033       delta_x2 = -float(coeff3 - coeff5) / float(2 * coeff1);
2034       if (delta_x2 > 1.0f)
2035         delta_x2 = 1.0f;
2036       else if (delta_x2 < -1.0f)
2037         delta_x2 = -1.0f;
2038     }
2039     // insert both options for evaluation which to pick
2040     float max1 = (coeff1 * delta_x1 * delta_x1 + coeff2 * delta_y1 * delta_y1 + coeff3 * delta_x1 + coeff4 * delta_y1
2041                   + coeff5 * delta_x1 * delta_y1 + coeff6)
2042                  / 18.0f;
2043     float max2 = (coeff1 * delta_x2 * delta_x2 + coeff2 * delta_y2 * delta_y2 + coeff3 * delta_x2 + coeff4 * delta_y2
2044                   + coeff5 * delta_x2 * delta_y2 + coeff6)
2045                  / 18.0f;
2046     if (max1 > max2)
2047     {
2048       delta_x = delta_x1;
2049       delta_y = delta_x1;
2050       return max1;
2051     }
2052     else
2053     {
2054       delta_x = delta_x2;
2055       delta_y = delta_x2;
2056       return max2;
2057     }
2058   }
2059 
2060   // this is the case of the maximum inside the boundaries:
2061   return (coeff1 * delta_x * delta_x + coeff2 * delta_y * delta_y + coeff3 * delta_x + coeff4 * delta_y
2062           + coeff5 * delta_x * delta_y + coeff6)
2063          / 18.0f;
2064 }
2065 
2066 // construct a layer
BriskLayer(const cv::Mat & img_in,float scale_in,float offset_in)2067 BriskLayer::BriskLayer(const cv::Mat& img_in, float scale_in, float offset_in)
2068 {
2069   img_ = img_in;
2070   scores_ = cv::Mat_<uchar>::zeros(img_in.rows, img_in.cols);
2071   // attention: this means that the passed image reference must point to persistent memory
2072   scale_ = scale_in;
2073   offset_ = offset_in;
2074   // create an agast detector
2075   oast_9_16_ = AgastFeatureDetector::create(1, false, AgastFeatureDetector::OAST_9_16);
2076   makeAgastOffsets(pixel_5_8_, (int)img_.step, AgastFeatureDetector::AGAST_5_8);
2077   makeAgastOffsets(pixel_9_16_, (int)img_.step, AgastFeatureDetector::OAST_9_16);
2078 }
2079 // derive a layer
BriskLayer(const BriskLayer & layer,int mode)2080 BriskLayer::BriskLayer(const BriskLayer& layer, int mode)
2081 {
2082   if (mode == CommonParams::HALFSAMPLE)
2083   {
2084     img_.create(layer.img().rows / 2, layer.img().cols / 2, CV_8U);
2085     halfsample(layer.img(), img_);
2086     scale_ = layer.scale() * 2;
2087     offset_ = 0.5f * scale_ - 0.5f;
2088   }
2089   else
2090   {
2091     img_.create(2 * (layer.img().rows / 3), 2 * (layer.img().cols / 3), CV_8U);
2092     twothirdsample(layer.img(), img_);
2093     scale_ = layer.scale() * 1.5f;
2094     offset_ = 0.5f * scale_ - 0.5f;
2095   }
2096   scores_ = cv::Mat::zeros(img_.rows, img_.cols, CV_8U);
2097   oast_9_16_ = AgastFeatureDetector::create(1, false, AgastFeatureDetector::OAST_9_16);
2098   makeAgastOffsets(pixel_5_8_, (int)img_.step, AgastFeatureDetector::AGAST_5_8);
2099   makeAgastOffsets(pixel_9_16_, (int)img_.step, AgastFeatureDetector::OAST_9_16);
2100 }
2101 
2102 // Agast
2103 // wraps the agast class
2104 void
getAgastPoints(int threshold,std::vector<KeyPoint> & keypoints)2105 BriskLayer::getAgastPoints(int threshold, std::vector<KeyPoint>& keypoints)
2106 {
2107   oast_9_16_->setThreshold(threshold);
2108   oast_9_16_->detect(img_, keypoints);
2109 
2110   // also write scores
2111   const size_t num = keypoints.size();
2112 
2113   for (size_t i = 0; i < num; i++)
2114     scores_((int)keypoints[i].pt.y, (int)keypoints[i].pt.x) = saturate_cast<uchar>(keypoints[i].response);
2115 }
2116 
2117 inline int
getAgastScore(int x,int y,int threshold) const2118 BriskLayer::getAgastScore(int x, int y, int threshold) const
2119 {
2120   if (x < 3 || y < 3)
2121     return 0;
2122   if (x >= img_.cols - 3 || y >= img_.rows - 3)
2123     return 0;
2124   uchar& score = (uchar&)scores_(y, x);
2125   if (score > 2)
2126   {
2127     return score;
2128   }
2129   score = (uchar)agast_cornerScore<AgastFeatureDetector::OAST_9_16>(&img_.at<uchar>(y, x), pixel_9_16_, threshold - 1);
2130   if (score < threshold)
2131     score = 0;
2132   return score;
2133 }
2134 
2135 inline int
getAgastScore_5_8(int x,int y,int threshold) const2136 BriskLayer::getAgastScore_5_8(int x, int y, int threshold) const
2137 {
2138   if (x < 2 || y < 2)
2139     return 0;
2140   if (x >= img_.cols - 2 || y >= img_.rows - 2)
2141     return 0;
2142   int score = agast_cornerScore<AgastFeatureDetector::AGAST_5_8>(&img_.at<uchar>(y, x), pixel_5_8_, threshold - 1);
2143   if (score < threshold)
2144     score = 0;
2145   return score;
2146 }
2147 
2148 inline int
getAgastScore(float xf,float yf,int threshold_in,float scale_in) const2149 BriskLayer::getAgastScore(float xf, float yf, int threshold_in, float scale_in) const
2150 {
2151   if (scale_in <= 1.0f)
2152   {
2153     // just do an interpolation inside the layer
2154     const int x = int(xf);
2155     const float rx1 = xf - float(x);
2156     const float rx = 1.0f - rx1;
2157     const int y = int(yf);
2158     const float ry1 = yf - float(y);
2159     const float ry = 1.0f - ry1;
2160 
2161     return (uchar)(rx * ry * getAgastScore(x, y, threshold_in) + rx1 * ry * getAgastScore(x + 1, y, threshold_in)
2162            + rx * ry1 * getAgastScore(x, y + 1, threshold_in) + rx1 * ry1 * getAgastScore(x + 1, y + 1, threshold_in));
2163   }
2164   else
2165   {
2166     // this means we overlap area smoothing
2167     const float halfscale = scale_in / 2.0f;
2168     // get the scores first:
2169     for (int x = int(xf - halfscale); x <= int(xf + halfscale + 1.0f); x++)
2170     {
2171       for (int y = int(yf - halfscale); y <= int(yf + halfscale + 1.0f); y++)
2172       {
2173         getAgastScore(x, y, threshold_in);
2174       }
2175     }
2176     // get the smoothed value
2177     return value(scores_, xf, yf, scale_in);
2178   }
2179 }
2180 
2181 // access gray values (smoothed/interpolated)
2182 inline int
value(const cv::Mat & mat,float xf,float yf,float scale_in) const2183 BriskLayer::value(const cv::Mat& mat, float xf, float yf, float scale_in) const
2184 {
2185   CV_Assert(!mat.empty());
2186   // get the position
2187   const int x = cvFloor(xf);
2188   const int y = cvFloor(yf);
2189   const cv::Mat& image = mat;
2190   const int& imagecols = image.cols;
2191 
2192   // get the sigma_half:
2193   const float sigma_half = scale_in / 2;
2194   const float area = 4.0f * sigma_half * sigma_half;
2195   // calculate output:
2196   int ret_val;
2197   if (sigma_half < 0.5)
2198   {
2199     //interpolation multipliers:
2200     const int r_x = (int)((xf - x) * 1024);
2201     const int r_y = (int)((yf - y) * 1024);
2202     const int r_x_1 = (1024 - r_x);
2203     const int r_y_1 = (1024 - r_y);
2204     const uchar* ptr = image.ptr() + x + y * imagecols;
2205     // just interpolate:
2206     ret_val = (r_x_1 * r_y_1 * int(*ptr));
2207     ptr++;
2208     ret_val += (r_x * r_y_1 * int(*ptr));
2209     ptr += imagecols;
2210     ret_val += (r_x * r_y * int(*ptr));
2211     ptr--;
2212     ret_val += (r_x_1 * r_y * int(*ptr));
2213     return 0xFF & ((ret_val + 512) / 1024 / 1024);
2214   }
2215 
2216   // this is the standard case (simple, not speed optimized yet):
2217 
2218   // scaling:
2219   const int scaling = (int)(4194304.0f / area);
2220   const int scaling2 = (int)(float(scaling) * area / 1024.0f);
2221 
2222   // calculate borders
2223   const float x_1 = xf - sigma_half;
2224   const float x1 = xf + sigma_half;
2225   const float y_1 = yf - sigma_half;
2226   const float y1 = yf + sigma_half;
2227 
2228   const int x_left = int(x_1 + 0.5);
2229   const int y_top = int(y_1 + 0.5);
2230   const int x_right = int(x1 + 0.5);
2231   const int y_bottom = int(y1 + 0.5);
2232 
2233   // overlap area - multiplication factors:
2234   const float r_x_1 = float(x_left) - x_1 + 0.5f;
2235   const float r_y_1 = float(y_top) - y_1 + 0.5f;
2236   const float r_x1 = x1 - float(x_right) + 0.5f;
2237   const float r_y1 = y1 - float(y_bottom) + 0.5f;
2238   const int dx = x_right - x_left - 1;
2239   const int dy = y_bottom - y_top - 1;
2240   const int A = (int)((r_x_1 * r_y_1) * scaling);
2241   const int B = (int)((r_x1 * r_y_1) * scaling);
2242   const int C = (int)((r_x1 * r_y1) * scaling);
2243   const int D = (int)((r_x_1 * r_y1) * scaling);
2244   const int r_x_1_i = (int)(r_x_1 * scaling);
2245   const int r_y_1_i = (int)(r_y_1 * scaling);
2246   const int r_x1_i = (int)(r_x1 * scaling);
2247   const int r_y1_i = (int)(r_y1 * scaling);
2248 
2249   // now the calculation:
2250   const uchar* ptr = image.ptr() + x_left + imagecols * y_top;
2251   // first row:
2252   ret_val = A * int(*ptr);
2253   ptr++;
2254   const uchar* end1 = ptr + dx;
2255   for (; ptr < end1; ptr++)
2256   {
2257     ret_val += r_y_1_i * int(*ptr);
2258   }
2259   ret_val += B * int(*ptr);
2260   // middle ones:
2261   ptr += imagecols - dx - 1;
2262   const uchar* end_j = ptr + dy * imagecols;
2263   for (; ptr < end_j; ptr += imagecols - dx - 1)
2264   {
2265     ret_val += r_x_1_i * int(*ptr);
2266     ptr++;
2267     const uchar* end2 = ptr + dx;
2268     for (; ptr < end2; ptr++)
2269     {
2270       ret_val += int(*ptr) * scaling;
2271     }
2272     ret_val += r_x1_i * int(*ptr);
2273   }
2274   // last row:
2275   ret_val += D * int(*ptr);
2276   ptr++;
2277   const uchar* end3 = ptr + dx;
2278   for (; ptr < end3; ptr++)
2279   {
2280     ret_val += r_y1_i * int(*ptr);
2281   }
2282   ret_val += C * int(*ptr);
2283 
2284   return 0xFF & ((ret_val + scaling2 / 2) / scaling2 / 1024);
2285 }
2286 
2287 // half sampling
2288 inline void
halfsample(const cv::Mat & srcimg,cv::Mat & dstimg)2289 BriskLayer::halfsample(const cv::Mat& srcimg, cv::Mat& dstimg)
2290 {
2291   // make sure the destination image is of the right size:
2292   CV_Assert(srcimg.cols / 2 == dstimg.cols);
2293   CV_Assert(srcimg.rows / 2 == dstimg.rows);
2294 
2295   // handle non-SSE case
2296   resize(srcimg, dstimg, dstimg.size(), 0, 0, INTER_AREA);
2297 }
2298 
2299 inline void
twothirdsample(const cv::Mat & srcimg,cv::Mat & dstimg)2300 BriskLayer::twothirdsample(const cv::Mat& srcimg, cv::Mat& dstimg)
2301 {
2302   // make sure the destination image is of the right size:
2303   CV_Assert((srcimg.cols / 3) * 2 == dstimg.cols);
2304   CV_Assert((srcimg.rows / 3) * 2 == dstimg.rows);
2305 
2306   resize(srcimg, dstimg, dstimg.size(), 0, 0, INTER_AREA);
2307 }
2308 
create(int thresh,int octaves,float patternScale)2309 Ptr<BRISK> BRISK::create(int thresh, int octaves, float patternScale)
2310 {
2311     return makePtr<BRISK_Impl>(thresh, octaves, patternScale);
2312 }
2313 
2314 // custom setup
create(const std::vector<float> & radiusList,const std::vector<int> & numberList,float dMax,float dMin,const std::vector<int> & indexChange)2315 Ptr<BRISK> BRISK::create(const std::vector<float> &radiusList, const std::vector<int> &numberList,
2316                          float dMax, float dMin, const std::vector<int>& indexChange)
2317 {
2318     return makePtr<BRISK_Impl>(radiusList, numberList, dMax, dMin, indexChange);
2319 }
2320 
2321 }
2322