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
51namespace cv
52{
53
54class BRISK_Impl : public BRISK
55{
56public:
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
64    int descriptorSize() const
65    {
66        return strings_;
67    }
68
69    int descriptorType() const
70    {
71        return CV_8U;
72    }
73
74    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
91protected:
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
146class CV_EXPORTS BriskLayer
147{
148public:
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&
174  img() const
175  {
176    return img_;
177  }
178  inline const cv::Mat&
179  scores() const
180  {
181    return scores_;
182  }
183  inline float
184  scale() const
185  {
186    return scale_;
187  }
188  inline float
189  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
201private:
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
218class CV_EXPORTS BriskScaleSpace
219{
220public:
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
233protected:
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
275const float BRISK_Impl::basicSize_ = 12.0f;
276const unsigned int BRISK_Impl::scales_ = 64;
277const float BRISK_Impl::scalerange_ = 30.f; // 40->4 Octaves - else, this needs to be adjusted...
278const unsigned int BRISK_Impl::n_rot_ = 1024; // discretization of the rotation look-up
279
280const float BriskScaleSpace::safetyFactor_ = 1.0f;
281const float BriskScaleSpace::basicSize_ = 12.0f;
282
283// constructors
284BRISK_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
312BRISK_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
322void
323BRISK_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:
449inline int
450BRISK_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
608inline bool
609RoiPredicate(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
616void
617BRISK_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
629void
630BRISK_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
804BRISK_Impl::~BRISK_Impl()
805{
806  delete[] patternPoints_;
807  delete[] shortPairs_;
808  delete[] longPairs_;
809  delete[] scaleList_;
810  delete[] sizeList_;
811}
812
813void
814BRISK_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:
829BriskScaleSpace::BriskScaleSpace(int _octaves)
830{
831  if (_octaves == 0)
832    layers_ = 1;
833  else
834    layers_ = 2 * _octaves;
835}
836BriskScaleSpace::~BriskScaleSpace()
837{
838
839}
840// construct the image pyramids
841void
842BriskScaleSpace::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
863void
864BriskScaleSpace::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:
985inline int
986BriskScaleSpace::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}
1028inline int
1029BriskScaleSpace::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
1129inline bool
1130BriskScaleSpace::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)
1248inline float
1249BriskScaleSpace::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
1406inline float
1407BriskScaleSpace::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
1586inline float
1587BriskScaleSpace::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
1785inline float
1786BriskScaleSpace::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
1831inline float
1832BriskScaleSpace::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
1877inline float
1878BriskScaleSpace::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
1923inline float
1924BriskScaleSpace::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
2067BriskLayer::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
2080BriskLayer::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
2104void
2105BriskLayer::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
2117inline int
2118BriskLayer::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
2135inline int
2136BriskLayer::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
2148inline int
2149BriskLayer::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)
2182inline int
2183BriskLayer::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
2288inline void
2289BriskLayer::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
2299inline void
2300BriskLayer::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
2309Ptr<BRISK> BRISK::create(int thresh, int octaves, float patternScale)
2310{
2311    return makePtr<BRISK_Impl>(thresh, octaves, patternScale);
2312}
2313
2314// custom setup
2315Ptr<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