1 /*
2  * Software License Agreement (BSD License)
3  *
4  *  Point Cloud Library (PCL) - www.pointclouds.org
5  *  Copyright (C) 2011, The Autonomous Systems Lab (ASL), ETH Zurich,
6  *                      Stefan Leutenegger, Simon Lynen and Margarita Chli.
7  *  Copyright (c) 2012-, Open Perception, Inc.
8  *
9  *  All rights reserved.
10  *
11  *  Redistribution and use in source and threshold_inary forms, with or without
12  *  modification, are permitted provided that the following conditions
13  *  are met:
14  *
15  *   * Redistributions of source code must retain the above copyright
16  *     notice, this list of conditions and the following disclaimer.
17  *   * Redistributions in threshold_inary form must reproduce the above
18  *     copyright notice, this list of conditions and the following
19  *     disclaimer in the documentation and/or other materials provided
20  *     with the distribution.
21  *   * Neither the name of the copyright holder(s) nor the names of its
22  *     contributors may threshold_e used to endorse or promote products derived
23  *     from this software without specific prior written permission.
24  *
25  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
28  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
29  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
30  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
31  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
35  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  *  POSSIBILITY OF SUCH DAMAGE.
37  *
38  */
39 
40 #include <pcl/pcl_config.h>
41 #include <pcl/pcl_macros.h>
42 #include <pcl/keypoints/brisk_2d.h>
43 #include <pcl/point_types.h>
44 #include <pcl/common/utils.h> // pcl::utils::ignore
45 #include <pcl/impl/instantiate.hpp>
46 #if defined(__SSSE3__) && !defined(__i386__)
47 #include <tmmintrin.h>
48 #include <emmintrin.h>
49 #endif
50 
51 const int pcl::keypoints::brisk::Layer::CommonParams::HALFSAMPLE = 0;
52 const int pcl::keypoints::brisk::Layer::CommonParams::TWOTHIRDSAMPLE = 1;
53 
54 /////////////////////////////////////////////////////////////////////////////////////////
55 // construct telling the octaves number:
ScaleSpace(int octaves)56 pcl::keypoints::brisk::ScaleSpace::ScaleSpace (int octaves)
57   : safety_factor_ (1.0)
58   , basic_size_ (12.0)
59 {
60   if (octaves == 0)
61     layers_ = 1;
62   else
63     layers_ = std::uint8_t (2 * octaves);
64 }
65 
66 /////////////////////////////////////////////////////////////////////////////////////////
~ScaleSpace()67 pcl::keypoints::brisk::ScaleSpace::~ScaleSpace ()
68 {
69 }
70 
71 /////////////////////////////////////////////////////////////////////////////////////////
72 // construct the image pyramids
73 void
constructPyramid(const std::vector<unsigned char> & image,int width,int height)74 pcl::keypoints::brisk::ScaleSpace::constructPyramid (
75     const std::vector<unsigned char>& image, int width, int height)
76 {
77   // set correct size:
78   pyramid_.clear ();
79 
80   // fill the pyramid
81   pyramid_.emplace_back(std::vector<unsigned char> (image), width, height);
82   if (layers_ > 1)
83     pyramid_.emplace_back(pyramid_.back (), pcl::keypoints::brisk::Layer::CommonParams::TWOTHIRDSAMPLE);
84   const int octaves2 = layers_;
85 
86   for (int i = 2; i < octaves2; i += 2)
87   {
88     pyramid_.emplace_back(pyramid_[i-2], pcl::keypoints::brisk::Layer::CommonParams::HALFSAMPLE);
89     pyramid_.emplace_back(pyramid_[i-1], pcl::keypoints::brisk::Layer::CommonParams::HALFSAMPLE);
90   }
91 }
92 
93 /////////////////////////////////////////////////////////////////////////////////////////
94 void
getKeypoints(const int threshold,std::vector<pcl::PointWithScale,Eigen::aligned_allocator<pcl::PointWithScale>> & keypoints)95 pcl::keypoints::brisk::ScaleSpace::getKeypoints (
96     const int threshold,
97     std::vector<pcl::PointWithScale, Eigen::aligned_allocator<pcl::PointWithScale> >& keypoints)
98 {
99   // make sure keypoints is empty
100   //keypoints.resize (0);
101   keypoints.clear ();
102   keypoints.reserve (2000);
103 
104   // assign thresholds
105   threshold_ = std::uint8_t (threshold);
106   safe_threshold_ = std::uint8_t (threshold_ * safety_factor_);
107   std::vector<std::vector<pcl::PointUV, Eigen::aligned_allocator<pcl::PointUV> > > agast_points;
108   agast_points.resize (layers_);
109 
110   // go through the octaves and intra layers and calculate fast corner scores:
111   for (std::uint8_t i = 0; i < layers_; i++)
112   {
113     // call OAST16_9 without nms
114     pcl::keypoints::brisk::Layer& l = pyramid_[i];
115     l.getAgastPoints (safe_threshold_, agast_points[i]);
116   }
117 
118   if (layers_ == 1)
119   {
120     // just do a simple 2d subpixel refinement...
121     const int num = int (agast_points[0].size ());
122     for (int n = 0; n < num; n++)
123     {
124       const pcl::PointUV& point = agast_points.at (0)[n];
125       // first check if it is a maximum:
126       if (!isMax2D (0, int (point.u), int (point.v)))
127         continue;
128 
129       // let's do the subpixel and float scale refinement:
130       pcl::keypoints::brisk::Layer& l = pyramid_[0];
131       int s_0_0 = l.getAgastScore (point.u-1, point.v-1, 1);
132       int s_1_0 = l.getAgastScore (point.u,   point.v-1, 1);
133       int s_2_0 = l.getAgastScore (point.u+1, point.v-1, 1);
134       int s_2_1 = l.getAgastScore (point.u+1, point.v,   1);
135       int s_1_1 = l.getAgastScore (point.u,   point.v,   1);
136       int s_0_1 = l.getAgastScore (point.u-1, point.v,   1);
137       int s_0_2 = l.getAgastScore (point.u-1, point.v+1, 1);
138       int s_1_2 = l.getAgastScore (point.u,   point.v+1, 1);
139       int s_2_2 = l.getAgastScore (point.u+1, point.v+1, 1);
140       float delta_x, delta_y;
141       float max = subpixel2D (s_0_0, s_0_1, s_0_2,
142                               s_1_0, s_1_1, s_1_2,
143                               s_2_0, s_2_1, s_2_2,
144                               delta_x, delta_y);
145 
146       // store:
147       keypoints.emplace_back(point.u + delta_x, point.v + delta_y, 0.0f, basic_size_, -1, max, 0);
148     }
149     return;
150   }
151 
152   float x, y, scale, score;
153   for (std::uint8_t i = 0; i < layers_; i++)
154   {
155     pcl::keypoints::brisk::Layer& l = pyramid_[i];
156     const int num = int (agast_points[i].size ());
157 
158     if (i == layers_ - 1)
159     {
160       for (int n = 0; n < num; n++)
161       {
162         const pcl::PointUV& point = agast_points.at (i)[n];
163 
164         // consider only 2D maxima...
165         if (!isMax2D (i, int (point.u), int (point.v)))
166           continue;
167 
168         bool ismax;
169         float dx, dy;
170         getScoreMaxBelow (i, int (point.u), int (point.v),
171                           l.getAgastScore (point.u, point.v, safe_threshold_), ismax,
172                           dx, dy);
173         if (!ismax)
174           continue;
175 
176         // get the patch on this layer:
177         int s_0_0 = l.getAgastScore (point.u-1, point.v-1, 1);
178         int s_1_0 = l.getAgastScore (point.u,   point.v-1, 1);
179         int s_2_0 = l.getAgastScore (point.u+1, point.v-1, 1);
180         int s_2_1 = l.getAgastScore (point.u+1, point.v,   1);
181         int s_1_1 = l.getAgastScore (point.u,   point.v,   1);
182         int s_0_1 = l.getAgastScore (point.u-1, point.v,   1);
183         int s_0_2 = l.getAgastScore (point.u-1, point.v+1, 1);
184         int s_1_2 = l.getAgastScore (point.u,   point.v+1, 1);
185         int s_2_2 = l.getAgastScore (point.u+1, point.v+1, 1);
186         float delta_x, delta_y;
187         float max = subpixel2D (s_0_0, s_0_1, s_0_2,
188                                 s_1_0, s_1_1, s_1_2,
189                                 s_2_0, s_2_1, s_2_2,
190                                 delta_x, delta_y);
191 
192         // store:
193         keypoints.emplace_back((point.u + delta_x) * l.getScale () + l.getOffset (),  // x
194                                (point.v + delta_y) * l.getScale () + l.getOffset (),  // y
195                                0.0f,                                                  // z
196                                basic_size_ * l.getScale (),                           // size
197                                -1,                                                    // angle
198                                max,                                                   // response
199                                i);                                                    // octave
200       }
201     }
202     else
203     {
204       // not the last layer:
205       for (int n = 0; n < num; n++)
206       {
207         const pcl::PointUV& point = agast_points.at (i)[n];
208 
209         // first check if it is a maximum:
210         if (!isMax2D (i, int (point.u), int (point.v)))
211         {
212           continue;
213         }
214 
215         // let's do the subpixel and float scale refinement:
216         bool ismax;
217         score = refine3D (i, int (point.u), int (point.v), x, y, scale, ismax);
218 
219         if (!ismax)
220           continue;
221 
222         // finally store the detected keypoint:
223         if (score > float (threshold_))
224         {
225           keypoints.emplace_back(x, y, 0.0f, basic_size_ * scale, -1, score, i);
226         }
227       }
228     }
229   }
230 }
231 
232 /////////////////////////////////////////////////////////////////////////////////////////
233 // interpolated score access with recalculation when needed:
234 int
getScoreAbove(const std::uint8_t layer,const int x_layer,const int y_layer)235 pcl::keypoints::brisk::ScaleSpace::getScoreAbove (
236     const std::uint8_t layer, const int x_layer, const int y_layer)
237 {
238   assert (layer < layers_ - 1);
239   pcl::keypoints::brisk::Layer& l = pyramid_[layer+1];
240   if (layer % 2 == 0)
241   { // octave
242     const int sixths_x = 4 * x_layer - 1;
243     const int x_above  = sixths_x / 6;
244     const int sixths_y = 4 * y_layer - 1;
245     const int y_above = sixths_y / 6;
246     const int r_x = (sixths_x % 6);
247     const int r_x_1 =6 - r_x;
248     const int r_y = (sixths_y % 6);
249     const int r_y_1 = 6 - r_y;
250     std::uint8_t score = static_cast<std::uint8_t> (
251                     0xFF & ((r_x_1 * r_y_1 * l.getAgastScore (x_above,     y_above,     1) +
252                              r_x   * r_y_1 * l.getAgastScore (x_above + 1, y_above,     1) +
253                              r_x_1 * r_y   * l.getAgastScore (x_above,     y_above + 1, 1) +
254                              r_x   * r_y   * l.getAgastScore (x_above + 1, y_above + 1, 1) + 18) / 36));
255 
256     return (score);
257   }
258 
259   // intra
260   const int eighths_x = 6 * x_layer - 1;
261   const int x_above = eighths_x / 8;
262   const int eighths_y = 6 * y_layer - 1;
263   const int y_above = eighths_y / 8;
264   const int r_x = (eighths_x % 8);
265   const int r_x_1 = 8 - r_x;
266   const int r_y = (eighths_y % 8);
267   const int r_y_1 = 8 - r_y;
268   std::uint8_t score = static_cast<std::uint8_t> (
269                   0xFF & ((r_x_1 * r_y_1 * l.getAgastScore (x_above,     y_above,     1) +
270                            r_x   * r_y_1  * l.getAgastScore (x_above + 1, y_above,     1) +
271                            r_x_1 * r_y    * l.getAgastScore (x_above ,    y_above + 1, 1) +
272                            r_x   * r_y    * l.getAgastScore (x_above + 1, y_above + 1, 1) + 32) / 64));
273   return (score);
274 }
275 
276 /////////////////////////////////////////////////////////////////////////////////////////
277 int
getScoreBelow(const std::uint8_t layer,const int x_layer,const int y_layer)278 pcl::keypoints::brisk::ScaleSpace::getScoreBelow (
279     const std::uint8_t layer, const int x_layer, const int y_layer)
280 {
281   assert (layer);
282   pcl::keypoints::brisk::Layer& l = pyramid_[layer-1];
283   float xf;
284   float yf;
285 
286   // scaling:
287   float offs;
288   float area;
289   int scaling;
290   int scaling2;
291 
292   if (layer % 2 == 0)
293   { // octave
294     int sixth_x = 8 * x_layer + 1;
295     xf = float (sixth_x) / 6.0f;
296     int sixth_y = 8 * y_layer + 1;
297     yf = float (sixth_y) / 6.0f;
298 
299     // scaling:
300     offs = 2.0f / 3.0f;
301     area = 4.0f * offs * offs;
302     scaling  = static_cast<int> (4194304.0f / area);
303     scaling2 = static_cast<int> (float (scaling) * area);
304   }
305   else
306   {
307     int quarter_x = 6 * x_layer + 1;
308     xf = float (quarter_x) / 4.0f;
309     int quarter_y = 6 * y_layer + 1;
310     yf = float (quarter_y) / 4.0f;
311 
312     // scaling:
313     offs = 3.0f / 4.0f;
314     area = 4.0f * offs * offs;
315     scaling  = static_cast<int> (4194304.0f / area);
316     scaling2 = static_cast<int> (float (scaling) * area);
317   }
318 
319   // calculate borders
320   const float x_1 = xf - offs;
321   const float x1  = xf + offs;
322   const float y_1 = yf - offs;
323   const float y1  = yf + offs;
324 
325   const int x_left   = int (x_1 + 0.5);
326   const int y_top    = int (y_1 + 0.5);
327   const int x_right  = int (x1  + 0.5);
328   const int y_bottom = int (y1  + 0.5);
329 
330   // overlap area - multiplication factors:
331   const float r_x_1 = float (x_left) - x_1 + 0.5f;
332   const float r_y_1 = float (y_top) - y_1  + 0.5f;
333   const float r_x1  = x1 - float (x_right) + 0.5f;
334   const float r_y1  = y1 - float (y_bottom) + 0.5f;
335   const int dx  = x_right - x_left - 1;
336   const int dy = y_bottom - y_top - 1;
337   const int A = static_cast<int> ((r_x_1 * r_y_1) * float (scaling));
338   const int B = static_cast<int> ((r_x1  * r_y_1) * float (scaling));
339   const int C = static_cast<int> ((r_x1  * r_y1)  * float (scaling));
340   const int D = static_cast<int> ((r_x_1 * r_y1)  * float (scaling));
341   const int r_x_1_i = static_cast<int> (r_x_1 * float (scaling));
342   const int r_y_1_i = static_cast<int> (r_y_1 * float (scaling));
343   const int r_x1_i  = static_cast<int> (r_x1  * float (scaling));
344   const int r_y1_i  = static_cast<int> (r_y1  * float (scaling));
345 
346   // first row:
347   int ret_val = A * int (l.getAgastScore (x_left, y_top, 1));
348   for (int X = 1; X <= dx; X++)
349     ret_val += r_y_1_i * int (l.getAgastScore (x_left + X, y_top, 1));
350 
351   ret_val += B * int (l.getAgastScore (x_left + dx + 1, y_top, 1));
352   // middle ones:
353   for (int Y = 1; Y <= dy; Y++)
354   {
355     ret_val += r_x_1_i * int (l.getAgastScore (x_left, y_top + Y, 1));
356 
357     for (int X = 1; X <= dx; X++)
358       ret_val += int (l.getAgastScore (x_left + X, y_top + Y, 1)) * scaling;
359 
360     ret_val += r_x1_i * int (l.getAgastScore (x_left + dx + 1, y_top + Y, 1));
361   }
362   // last row:
363   ret_val += D * int (l.getAgastScore (x_left, y_top + dy + 1, 1));
364   for (int X = 1; X <= dx; X++)
365     ret_val += r_y1_i * int (l.getAgastScore (x_left + X, y_top + dy + 1, 1));
366 
367   ret_val += C * int (l.getAgastScore (x_left + dx + 1, y_top + dy + 1, 1));
368 
369   return ((ret_val + scaling2 / 2) / scaling2);
370 }
371 
372 /////////////////////////////////////////////////////////////////////////////////////////
373 bool
isMax2D(const std::uint8_t layer,const int x_layer,const int y_layer)374 pcl::keypoints::brisk::ScaleSpace::isMax2D (
375     const std::uint8_t layer, const int x_layer, const int y_layer)
376 {
377   const std::vector<unsigned char>& scores = pyramid_[layer].getScores ();
378   const int scorescols = pyramid_[layer].getImageWidth ();
379   const unsigned char* data = &scores[0] + y_layer * scorescols + x_layer;
380 
381   // decision tree:
382   const unsigned char center = (*data);
383   data--;
384   const unsigned char s_10 = *data;
385   if (center < s_10) return (false);
386   data += 2;
387   const unsigned char s10 = *data;
388   if (center < s10) return (false);
389   data -= (scorescols + 1);
390   const unsigned char s0_1 = *data;
391   if (center < s0_1) return (false);
392   data += 2 * scorescols;
393   const unsigned char s01 = *data;
394   if (center < s01) return (false);
395   data--;
396   const unsigned char s_11 =* data;
397   if (center < s_11) return (false);
398   data += 2;
399   const unsigned char s11 =* data;
400   if (center < s11) return (false);
401   data -= 2 * scorescols;
402   const unsigned char s1_1 =* data;
403   if (center < s1_1) return (false);
404   data -= 2;
405   const unsigned char s_1_1 =* data;
406   if (center < s_1_1) return (false);
407 
408   // reject neighbor maxima
409   std::vector<int> delta;
410   // put together a list of 2d-offsets to where the maximum is also reached
411   if (center == s_1_1)
412   {
413     delta.push_back (-1);
414     delta.push_back (-1);
415   }
416   if (center == s0_1)
417   {
418     delta.push_back (0);
419     delta.push_back (-1);
420   }
421   if (center == s1_1)
422   {
423     delta.push_back (1);
424     delta.push_back (-1);
425   }
426   if (center == s_10)
427   {
428     delta.push_back (-1);
429     delta.push_back (0);
430   }
431   if (center == s10)
432   {
433     delta.push_back (1);
434     delta.push_back (0);
435   }
436   if (center == s_11)
437   {
438     delta.push_back (-1);
439     delta.push_back (1);
440   }
441   if (center == s01)
442   {
443     delta.push_back (0);
444     delta.push_back (1);
445   }
446   if (center == s11)
447   {
448     delta.push_back (1);
449     delta.push_back (1);
450   }
451 
452   unsigned int deltasize = static_cast<unsigned int> (delta.size ());
453   if (deltasize != 0)
454   {
455     // in this case, we have to analyze the situation more carefully:
456     // the values are gaussian blurred and then we really decide
457     int smoothedcenter = 4 * center + 2 * (s_10 + s10 + s0_1 + s01) + s_1_1 + s1_1 + s_11 + s11;
458 
459     for (unsigned int i = 0; i < deltasize; i+= 2)
460     {
461       data = &scores[0] + (y_layer - 1 + delta[i+1]) * scorescols + x_layer + delta[i] - 1;
462 
463       int othercenter = *data;
464       data++;
465       othercenter += 2 * (*data);
466       data++;
467       othercenter += *data;
468       data += scorescols;
469       othercenter += 2 * (*data);
470       data--;
471       othercenter += 4 * (*data);
472       data--;
473       othercenter += 2 * (*data);
474       data += scorescols;
475       othercenter += *data;
476       data++;
477       othercenter += 2 * (*data);
478       data++;
479       othercenter += *data;
480       if (othercenter > smoothedcenter) return (false);
481     }
482   }
483   return (true);
484 }
485 
486 /////////////////////////////////////////////////////////////////////////////////////////
487 // 3D maximum refinement centered around (x_layer,y_layer)
488 float
refine3D(const std::uint8_t layer,const int x_layer,const int y_layer,float & x,float & y,float & scale,bool & ismax)489 pcl::keypoints::brisk::ScaleSpace::refine3D (
490     const std::uint8_t layer, const int x_layer, const int y_layer,
491     float& x, float& y, float& scale, bool& ismax)
492 {
493   ismax = true;
494   pcl::keypoints::brisk::Layer& this_layer = pyramid_[layer];
495   const int center = this_layer.getAgastScore (x_layer, y_layer, 1);
496 
497   // check and get above maximum:
498   float delta_x_above = 0, delta_y_above = 0;
499   float max_above = getScoreMaxAbove (layer,x_layer, y_layer,
500                                       center, ismax,
501                                       delta_x_above, delta_y_above);
502 
503   if (!ismax) return (0.0);
504 
505   float max; // to be returned
506 
507   if (layer % 2 == 0)
508   { // on octave
509     // treat the patch below:
510     float delta_x_below, delta_y_below;
511     float max_below_float;
512     if (layer == 0)
513     {
514       // guess the lower intra octave...
515       pcl::keypoints::brisk::Layer& l = pyramid_[0];
516       int s_0_0 = l.getAgastScore_5_8 (x_layer - 1, y_layer - 1, 1);
517       unsigned char max_below_uchar = static_cast<unsigned char> (s_0_0);
518       int s_1_0 = l.getAgastScore_5_8 (x_layer, y_layer - 1, 1);
519 
520       if (s_1_0 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_1_0);
521       int s_2_0 = l.getAgastScore_5_8 (x_layer + 1, y_layer - 1, 1);
522       if (s_2_0 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_2_0);
523       int s_2_1 = l.getAgastScore_5_8 (x_layer + 1, y_layer,   1);
524       if (s_2_1 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_2_1);
525       int s_1_1 = l.getAgastScore_5_8 (x_layer,   y_layer,   1);
526       if (s_1_1 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_1_1);
527       int s_0_1 = l.getAgastScore_5_8 (x_layer - 1, y_layer,   1);
528       if (s_0_1 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_0_1);
529       int s_0_2 = l.getAgastScore_5_8 (x_layer - 1, y_layer + 1, 1);
530       if (s_0_2 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_0_2);
531       int s_1_2 = l.getAgastScore_5_8 (x_layer,   y_layer + 1, 1);
532       if (s_1_2 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_1_2);
533       int s_2_2 = l.getAgastScore_5_8 (x_layer + 1, y_layer +1 , 1);
534       if (s_2_2 > max_below_uchar) max_below_uchar = static_cast<unsigned char> (s_2_2);
535 
536       subpixel2D (s_0_0, s_0_1, s_0_2,
537                   s_1_0, s_1_1, s_1_2,
538                   s_2_0, s_2_1, s_2_2,
539                   delta_x_below, delta_y_below);
540       max_below_float = max_below_uchar;
541     }
542     else
543     {
544       max_below_float = getScoreMaxBelow (layer,x_layer, y_layer,
545                                           center, ismax,
546                                           delta_x_below, delta_y_below);
547       if (!ismax) return (0);
548     }
549 
550     // get the patch on this layer:
551     int s_0_0 = this_layer.getAgastScore (x_layer - 1, y_layer - 1, 1);
552     int s_1_0 = this_layer.getAgastScore (x_layer,     y_layer - 1, 1);
553     int s_2_0 = this_layer.getAgastScore (x_layer + 1, y_layer - 1, 1);
554     int s_2_1 = this_layer.getAgastScore (x_layer + 1, y_layer,     1);
555     int s_1_1 = this_layer.getAgastScore (x_layer,     y_layer,     1);
556     int s_0_1 = this_layer.getAgastScore (x_layer - 1, y_layer,     1);
557     int s_0_2 = this_layer.getAgastScore (x_layer - 1, y_layer + 1, 1);
558     int s_1_2 = this_layer.getAgastScore (x_layer,     y_layer + 1, 1);
559     int s_2_2 = this_layer.getAgastScore (x_layer + 1, y_layer + 1, 1);
560     float delta_x_layer, delta_y_layer;
561     float max_layer = subpixel2D (s_0_0, s_0_1, s_0_2,
562                                   s_1_0, s_1_1, s_1_2,
563                                   s_2_0, s_2_1, s_2_2,
564                                   delta_x_layer, delta_y_layer);
565 
566     // calculate the relative scale (1D maximum):
567     if (layer == 0)
568       scale = refine1D_2 (max_below_float, std::max (float (center), max_layer), max_above,max);
569     else
570       scale = refine1D (max_below_float, std::max (float (center), max_layer), max_above,max);
571 
572     if (scale > 1.0)
573     {
574       // interpolate the position:
575       const float r0 = (1.5f - scale) / .5f;
576       const float r1 = 1.0f - r0;
577       x = (r0 * delta_x_layer + r1 * delta_x_above + float (x_layer))
578           * this_layer.getScale () + this_layer.getOffset ();
579       y = (r0 * delta_y_layer + r1 * delta_y_above + float (y_layer))
580           * this_layer.getScale () + this_layer.getOffset ();
581     }
582     else
583     {
584       if (layer == 0)
585       {
586         // interpolate the position:
587         const float r0 = (scale - 0.5f) / 0.5f;
588         const float r_1 = 1.0f - r0;
589         x = r0 * delta_x_layer + r_1 * delta_x_below + float (x_layer);
590         y = r0 * delta_y_layer + r_1 * delta_y_below + float (y_layer);
591       }
592       else
593       {
594         // interpolate the position:
595         const float r0 = (scale - 0.75f) / 0.25f;
596         const float r_1 = 1.0f -r0;
597         x = (r0 * delta_x_layer + r_1 * delta_x_below + float (x_layer))
598             * this_layer.getScale () +this_layer.getOffset ();
599         y = (r0 * delta_y_layer + r_1 * delta_y_below + float (y_layer))
600             * this_layer.getScale () + this_layer.getOffset ();
601       }
602     }
603   }
604   else
605   {
606     // on intra
607     // check the patch below:
608     float delta_x_below, delta_y_below;
609     float max_below = getScoreMaxBelow (layer, x_layer, y_layer,
610                                         center, ismax,
611                                         delta_x_below, delta_y_below);
612     if (!ismax) return (0.0);
613 
614     // get the patch on this layer:
615     int s_0_0 = this_layer.getAgastScore (x_layer - 1, y_layer - 1, 1);
616     int s_1_0 = this_layer.getAgastScore (x_layer,     y_layer - 1, 1);
617     int s_2_0 = this_layer.getAgastScore (x_layer + 1, y_layer - 1, 1);
618     int s_2_1 = this_layer.getAgastScore (x_layer + 1, y_layer,     1);
619     int s_1_1 = this_layer.getAgastScore (x_layer,     y_layer,     1);
620     int s_0_1 = this_layer.getAgastScore (x_layer - 1, y_layer,     1);
621     int s_0_2 = this_layer.getAgastScore (x_layer - 1, y_layer + 1, 1);
622     int s_1_2 = this_layer.getAgastScore (x_layer,     y_layer + 1, 1);
623     int s_2_2 = this_layer.getAgastScore (x_layer + 1, y_layer + 1, 1);
624     float delta_x_layer, delta_y_layer;
625     float max_layer = subpixel2D (s_0_0, s_0_1, s_0_2,
626                                   s_1_0, s_1_1, s_1_2,
627                                   s_2_0, s_2_1, s_2_2,
628                                   delta_x_layer, delta_y_layer);
629 
630     // calculate the relative scale (1D maximum):
631     scale = refine1D_1 (max_below, std::max (float (center),max_layer), max_above,max);
632     if (scale > 1.0)
633     {
634       // interpolate the position:
635       const float r0 = 4.0f - scale * 3.0f;
636       const float r1 = 1.0f - r0;
637       x = (r0 * delta_x_layer + r1 * delta_x_above + float (x_layer))
638            * this_layer.getScale () + this_layer.getOffset ();
639       y = (r0 * delta_y_layer + r1 * delta_y_above + float (y_layer))
640           * this_layer.getScale () + this_layer.getOffset ();
641     }
642     else
643     {
644       // interpolate the position:
645       const float r0 = scale * 3.0f - 2.0f;
646       const float r_1 = 1.0f - r0;
647       x = (r0 * delta_x_layer + r_1 * delta_x_below + float (x_layer))
648            * this_layer.getScale () + this_layer.getOffset ();
649       y = (r0 * delta_y_layer + r_1 * delta_y_below + float (y_layer))
650            * this_layer.getScale () + this_layer.getOffset ();
651     }
652   }
653 
654   // calculate the absolute scale:
655   scale *= this_layer.getScale ();
656 
657   // that's it, return the refined maximum:
658   return (max);
659 }
660 
661 /////////////////////////////////////////////////////////////////////////////////////////
662 // return the maximum of score patches above or below
663 float
getScoreMaxAbove(const std::uint8_t layer,const int x_layer,const int y_layer,const int threshold,bool & ismax,float & dx,float & dy)664 pcl::keypoints::brisk::ScaleSpace::getScoreMaxAbove (
665     const std::uint8_t layer, const int x_layer, const int y_layer,
666     const int threshold, bool& ismax, float& dx, float& dy)
667 {
668   ismax = false;
669   // relevant floating point coordinates
670   float x_1;
671   float x1;
672   float y_1;
673   float y1;
674 
675   // the layer above
676   assert (layer + 1 < layers_);
677   pcl::keypoints::brisk::Layer& layer_above = pyramid_[layer+1];
678 
679   if (layer % 2 == 0)
680   {
681     // octave
682     x_1  = float (4 * (x_layer) - 1 - 2) / 6.0f;
683     x1   = float (4 * (x_layer) - 1 + 2) / 6.0f;
684     y_1  = float (4 * (y_layer) - 1 - 2) / 6.0f;
685     y1   = float (4 * (y_layer) - 1 + 2) / 6.0f;
686   }
687   else
688   {
689     // intra
690     x_1 = float (6 * (x_layer) - 1 - 3) / 8.0f;
691     x1  = float (6 * (x_layer) - 1 + 3) / 8.0f;
692     y_1 = float (6 * (y_layer) - 1 - 3) / 8.0f;
693     y1  = float (6 * (y_layer) - 1 + 3) / 8.0f;
694   }
695 
696   // check the first row
697   //int max_x = int (x_1) + 1;
698   //int max_y = int (y_1) + 1;
699   int max_x = int (x_1 + 1.0f);
700   int max_y = int (y_1 + 1.0f);
701   float tmp_max = 0;
702   float max = layer_above.getAgastScore (x_1, y_1, 1,1.0f);
703 
704   if (max > threshold) return (0);
705   //for (int x = int (x_1) + 1; x <= int (x1); x++)
706   for (int x = int (x_1 + 1.0f); x <= int (x1); x++)
707   {
708     tmp_max = layer_above.getAgastScore (float (x), y_1, 1,1.0f);
709 
710     if (tmp_max > threshold) return (0);
711     if (tmp_max > max)
712     {
713       max = tmp_max;
714       max_x = x;
715     }
716   }
717   tmp_max = layer_above.getAgastScore (x1, y_1, 1,1.0f);
718 
719   if (tmp_max > threshold) return (0);
720   if (tmp_max > max)
721   {
722     max = tmp_max;
723     max_x = int (x1);
724   }
725 
726   // middle rows
727   for (int y = int (y_1) + 1; y <= int (y1); y++)
728   {
729     tmp_max = layer_above.getAgastScore (x_1, float (y), 1);
730 
731     if (tmp_max > threshold) return (0);
732     if (tmp_max > max)
733     {
734       max   = tmp_max;
735       max_x = int (x_1 + 1);
736       max_y = y;
737     }
738     for (int x = int (x_1) + 1; x <= int (x1); x++)
739     {
740       tmp_max = layer_above.getAgastScore (x, y, 1);
741 
742       if (tmp_max > threshold) return (0);
743       if (tmp_max > max)
744       {
745         max   = tmp_max;
746         max_x = x;
747         max_y = y;
748       }
749     }
750     tmp_max = layer_above.getAgastScore(x1,float(y),1);
751 
752     if (tmp_max > threshold) return 0;
753     if (tmp_max > max)
754     {
755       max   = tmp_max;
756       max_x = int (x1);
757       max_y = y;
758     }
759   }
760 
761   // bottom row
762   tmp_max = layer_above.getAgastScore (x_1, y1, 1);
763 
764   if (tmp_max > max)
765   {
766     max   = tmp_max;
767     max_x = int (x_1 + 1);
768     max_y = int (y1);
769   }
770   for (int x = int (x_1) + 1; x <= int (x1); x++)
771   {
772     tmp_max = layer_above.getAgastScore (float (x), y1, 1);
773 
774     if (tmp_max > max)
775     {
776       max   = tmp_max;
777       max_x = x;
778       max_y = int (y1);
779     }
780   }
781   tmp_max = layer_above.getAgastScore (x1, y1, 1);
782 
783   if (tmp_max > max)
784   {
785     max   = tmp_max;
786     max_x = int (x1);
787     max_y = int (y1);
788   }
789 
790   //find dx/dy:
791   int s_0_0 = layer_above.getAgastScore (max_x - 1, max_y - 1, 1);
792   int s_1_0 = layer_above.getAgastScore (max_x,     max_y - 1, 1);
793   int s_2_0 = layer_above.getAgastScore (max_x + 1, max_y - 1, 1);
794   int s_2_1 = layer_above.getAgastScore (max_x + 1, max_y,     1);
795   int s_1_1 = layer_above.getAgastScore (max_x,     max_y,     1);
796   int s_0_1 = layer_above.getAgastScore (max_x - 1, max_y,     1);
797   int s_0_2 = layer_above.getAgastScore (max_x - 1, max_y + 1, 1);
798   int s_1_2 = layer_above.getAgastScore (max_x,     max_y + 1, 1);
799   int s_2_2 = layer_above.getAgastScore (max_x + 1, max_y + 1, 1);
800   float dx_1, dy_1;
801   float refined_max = subpixel2D (s_0_0, s_0_1, s_0_2,
802                                   s_1_0, s_1_1, s_1_2,
803                                   s_2_0, s_2_1, s_2_2,
804                                   dx_1, dy_1);
805 
806   // calculate dx/dy in above coordinates
807   float real_x = float (max_x) + dx_1;
808   float real_y = float (max_y) + dy_1;
809   bool returnrefined = true;
810   if (layer % 2 == 0)
811   {
812     dx = (real_x * 6.0f + 1.0f) / 4.0f - float (x_layer);
813     dy = (real_y * 6.0f + 1.0f) / 4.0f - float (y_layer);
814   }
815   else
816   {
817     dx = (real_x * 8.0f + 1.0f) / 6.0f - float (x_layer);
818     dy = (real_y * 8.0f + 1.0f) / 6.0f - float (y_layer);
819   }
820 
821   // saturate
822   if (dx > 1.0f)  { dx = 1.0f;  returnrefined = false; }
823   if (dx < -1.0f) { dx = -1.0f; returnrefined = false; }
824   if (dy > 1.0f)  { dy = 1.0f;  returnrefined = false; }
825   if (dy < -1.0f) { dy = -1.0f; returnrefined = false; }
826 
827   // done and ok.
828   ismax = true;
829   if (returnrefined)
830     return (std::max (refined_max,max));
831   return (max);
832 }
833 
834 /////////////////////////////////////////////////////////////////////////////////////////
835 float
getScoreMaxBelow(const std::uint8_t layer,const int x_layer,const int y_layer,const int threshold,bool & ismax,float & dx,float & dy)836 pcl::keypoints::brisk::ScaleSpace::getScoreMaxBelow (
837     const std::uint8_t layer, const int x_layer, const int y_layer,
838     const int threshold, bool& ismax, float& dx, float& dy)
839 {
840   ismax = false;
841 
842   // relevant floating point coordinates
843   float x_1;
844   float x1;
845   float y_1;
846   float y1;
847 
848   if (layer % 2 == 0)
849   {
850     // octave
851     x_1 = float (8 * (x_layer) + 1 - 4) / 6.0f;
852     x1  = float (8 * (x_layer) + 1 + 4) / 6.0f;
853     y_1 = float (8 * (y_layer) + 1 - 4) / 6.0f;
854     y1  = float (8 * (y_layer) + 1 + 4) / 6.0f;
855   }
856   else
857   {
858     x_1 = float (6 * (x_layer) + 1 - 3) / 4.0f;
859     x1  = float (6 * (x_layer) + 1 + 3) / 4.0f;
860     y_1 = float (6 * (y_layer) + 1 - 3) / 4.0f;
861     y1  = float (6 * (y_layer) + 1 + 3) / 4.0f;
862   }
863 
864   // the layer below
865   assert (layer > 0);
866   pcl::keypoints::brisk::Layer& layer_below = pyramid_[layer-1];
867 
868   // check the first row
869   int max_x = int (x_1) + 1;
870   int max_y = int (y_1) + 1;
871   float tmp_max;
872   float max = layer_below.getAgastScore (x_1, y_1, 1);
873   if (max > threshold) return (0);
874   for (int x = int (x_1) + 1; x <= int (x1); x++)
875   {
876     tmp_max = layer_below.getAgastScore (float (x), y_1, 1);
877     if (tmp_max > threshold) return (0);
878     if (tmp_max > max)
879     {
880       max   = tmp_max;
881       max_x = x;
882     }
883   }
884   tmp_max = layer_below.getAgastScore (x1, y_1, 1);
885   if (tmp_max > threshold) return (0);
886   if (tmp_max > max)
887   {
888     max   = tmp_max;
889     max_x = int (x1);
890   }
891 
892   // middle rows
893   for (int y = int (y_1) + 1; y <= int (y1); y++)
894   {
895     tmp_max = layer_below.getAgastScore (x_1, float (y), 1);
896     if (tmp_max > threshold) return (0);
897     if (tmp_max > max)
898     {
899       max   = tmp_max;
900       max_x = int (x_1 + 1);
901       max_y = y;
902     }
903     for (int x = int (x_1) + 1; x <= int (x1); x++)
904     {
905       tmp_max = layer_below.getAgastScore (x, y, 1);
906       if (tmp_max > threshold) return (0);
907       if (tmp_max == max)
908       {
909         const int t1 = 2 * (
910                             layer_below.getAgastScore    (x - 1, y,     1)
911                             + layer_below.getAgastScore  (x + 1, y,     1)
912                             + layer_below.getAgastScore  (x,     y + 1, 1)
913                             + layer_below.getAgastScore  (x,     y - 1, 1))
914                             + (layer_below.getAgastScore (x + 1, y + 1, 1)
915                             + layer_below.getAgastScore  (x - 1, y + 1, 1)
916                             + layer_below.getAgastScore  (x + 1, y - 1, 1)
917                             + layer_below.getAgastScore  (x - 1, y - 1, 1));
918         const int t2 = 2 * (
919                             layer_below.getAgastScore    (max_x - 1, max_y,     1)
920                             + layer_below.getAgastScore  (max_x + 1, max_y,     1)
921                             + layer_below.getAgastScore  (max_x,     max_y + 1, 1)
922                             + layer_below.getAgastScore  (max_x,     max_y - 1, 1))
923                             + (layer_below.getAgastScore (max_x + 1, max_y + 1, 1)
924                             + layer_below.getAgastScore  (max_x - 1, max_y + 1, 1)
925                             + layer_below.getAgastScore  (max_x + 1, max_y - 1, 1)
926                             + layer_below.getAgastScore  (max_x - 1, max_y - 1, 1));
927         if (t1 > t2)
928         {
929           max_x = x;
930           max_y = y;
931         }
932       }
933       if (tmp_max > max)
934       {
935         max   = tmp_max;
936         max_x = x;
937         max_y = y;
938       }
939     }
940     tmp_max = layer_below.getAgastScore (x1, float (y), 1);
941     if (tmp_max > threshold) return (0);
942     if (tmp_max > max)
943     {
944       max   = tmp_max;
945       max_x = int (x1);
946       max_y = y;
947     }
948   }
949 
950   // bottom row
951   tmp_max = layer_below.getAgastScore (x_1, y1, 1);
952   if (tmp_max > max)
953   {
954     max   = tmp_max;
955     max_x = int (x_1 + 1);
956     max_y = int (y1);
957   }
958   for (int x = int (x_1) + 1; x <= int (x1); x++)
959   {
960     tmp_max = layer_below.getAgastScore (float (x), y1, 1);
961     if (tmp_max>max)
962     {
963       max   = tmp_max;
964       max_x = x;
965       max_y = int (y1);
966     }
967   }
968   tmp_max = layer_below.getAgastScore (x1, y1, 1);
969   if (tmp_max > max)
970   {
971     max   = tmp_max;
972     max_x = int (x1);
973     max_y = int (y1);
974   }
975 
976   //find dx/dy:
977   int s_0_0 = layer_below.getAgastScore (max_x - 1, max_y - 1, 1);
978   int s_1_0 = layer_below.getAgastScore (max_x,     max_y - 1, 1);
979   int s_2_0 = layer_below.getAgastScore (max_x + 1, max_y - 1, 1);
980   int s_2_1 = layer_below.getAgastScore (max_x + 1, max_y,     1);
981   int s_1_1 = layer_below.getAgastScore (max_x,     max_y,     1);
982   int s_0_1 = layer_below.getAgastScore (max_x - 1, max_y,     1);
983   int s_0_2 = layer_below.getAgastScore (max_x - 1, max_y + 1, 1);
984   int s_1_2 = layer_below.getAgastScore (max_x,     max_y + 1, 1);
985   int s_2_2 = layer_below.getAgastScore (max_x + 1, max_y + 1, 1);
986   float dx_1, dy_1;
987   float refined_max = subpixel2D (s_0_0, s_0_1, s_0_2,
988                                   s_1_0, s_1_1, s_1_2,
989                                   s_2_0, s_2_1, s_2_2,
990                                   dx_1, dy_1);
991 
992   // calculate dx/dy in above coordinates
993   float real_x = float (max_x) + dx_1;
994   float real_y = float (max_y) + dy_1;
995   bool returnrefined = true;
996   if (layer % 2 == 0)
997   {
998     dx = (real_x * 6.0f + 1.0f) / 8.0f - float (x_layer);
999     dy = (real_y * 6.0f + 1.0f) / 8.0f - float (y_layer);
1000   }
1001   else
1002   {
1003     dx = (real_x * 4.0f - 1.0f) / 6.0f - float (x_layer);
1004     dy = (real_y * 4.0f - 1.0f) / 6.0f - float (y_layer);
1005   }
1006 
1007   // saturate
1008   if (dx > 1.0f)  { dx = 1.0f;  returnrefined = false; }
1009   if (dx < -1.0f) { dx = -1.0f; returnrefined = false; }
1010   if (dy > 1.0f)  { dy = 1.0f;  returnrefined = false; }
1011   if (dy < -1.0f) { dy = -1.0f; returnrefined = false; }
1012 
1013   // done and ok.
1014   ismax = true;
1015   if (returnrefined)
1016     return (std::max (refined_max, max));
1017 
1018   return (max);
1019 }
1020 
1021 /////////////////////////////////////////////////////////////////////////////////////////
1022 float
refine1D(const float s_05,const float s0,const float s05,float & max)1023 pcl::keypoints::brisk::ScaleSpace::refine1D (
1024     const float s_05, const float s0, const float s05, float& max)
1025 {
1026   int i_05 = int (1024.0 * s_05 + 0.5);
1027   int i0   = int (1024.0 * s0   + 0.5);
1028   int i05  = int (1024.0 * s05  + 0.5);
1029 
1030   //   16.0000  -24.0000    8.0000
1031   //  -40.0000   54.0000  -14.0000
1032   //   24.0000  -27.0000    6.0000
1033 
1034   int three_a = 16 * i_05 - 24 * i0 + 8 * i05;
1035   // second derivative must be negative:
1036   if (three_a >= 0)
1037   {
1038     if (s0 >= s_05 && s0 >= s05)
1039     {
1040       max = s0;
1041       return (1.0f);
1042     }
1043     if (s_05 >= s0 && s_05 >= s05)
1044     {
1045       max = s_05;
1046       return (0.75f);
1047     }
1048     if (s05 >= s0 && s05 >= s_05)
1049     {
1050       max = s05;
1051       return (1.5f);
1052     }
1053   }
1054 
1055   int three_b = -40 * i_05 + 54 * i0 - 14 * i05;
1056   // calculate max location:
1057   float ret_val = -float (three_b) / float (2 * three_a);
1058   // saturate and return
1059   if (ret_val < 0.75f)
1060     ret_val= 0.75f;
1061   else
1062     if (ret_val > 1.5f)
1063       ret_val= 1.5f; // allow to be slightly off bounds ...?
1064   int three_c = +24 * i_05  -27 * i0    +6 * i05;
1065   max = float (three_c) + float (three_a) * ret_val * ret_val + float (three_b) * ret_val;
1066   max /= 3072.0f;
1067   return (ret_val);
1068 }
1069 
1070 /////////////////////////////////////////////////////////////////////////////////////////
1071 float
refine1D_1(const float s_05,const float s0,const float s05,float & max)1072 pcl::keypoints::brisk::ScaleSpace::refine1D_1 (
1073     const float s_05, const float s0, const float s05, float& max)
1074 {
1075   int i_05 = int (1024.0 *s_05 + 0.5);
1076   int i0   = int (1024.0 *s0   + 0.5);
1077   int i05  = int (1024.0 *s05  + 0.5);
1078 
1079     //  4.5000   -9.0000    4.5000
1080     //-10.5000   18.0000   -7.5000
1081     //  6.0000   -8.0000    3.0000
1082 
1083   int two_a = 9 * i_05 - 18 * i0 + 9 * i05;
1084   // second derivative must be negative:
1085   if (two_a >= 0)
1086   {
1087     if (s0 >= s_05 && s0 >= s05)
1088     {
1089       max = s0;
1090       return (1.0f);
1091     }
1092     if(s_05>=s0 && s_05>=s05)
1093     {
1094       max = s_05;
1095       return (0.6666666666666666666666666667f);
1096     }
1097     if (s05 >= s0 && s05 >= s_05)
1098     {
1099       max = s05;
1100       return (1.3333333333333333333333333333f);
1101     }
1102   }
1103 
1104   int two_b = -21 * i_05 + 36 * i0 - 15 * i05;
1105   // calculate max location:
1106   float ret_val = -float (two_b) / float (2 * two_a);
1107   // saturate and return
1108   if (ret_val < 0.6666666666666666666666666667f)
1109     ret_val = 0.666666666666666666666666667f;
1110   else
1111     if (ret_val > 1.33333333333333333333333333f)
1112       ret_val = 1.333333333333333333333333333f;
1113   int two_c = +12 * i_05  -16 * i0    +6 * i05;
1114   max = float (two_c) + float (two_a) * ret_val * ret_val + float (two_b) * ret_val;
1115   max /= 2048.0f;
1116   return (ret_val);
1117 }
1118 
1119 /////////////////////////////////////////////////////////////////////////////////////////
1120 float
refine1D_2(const float s_05,const float s0,const float s05,float & max)1121 pcl::keypoints::brisk::ScaleSpace::refine1D_2 (
1122     const float s_05, const float s0, const float s05, float& max)
1123 {
1124   int i_05 = int (1024.0 * s_05 + 0.5);
1125   int i0   = int (1024.0 * s0   + 0.5);
1126   int i05  = int (1024.0 * s05  + 0.5);
1127 
1128   //   18.0000  -30.0000   12.0000
1129   //  -45.0000   65.0000  -20.0000
1130   //   27.0000  -30.0000    8.0000
1131 
1132   int a = 2 * i_05- 4 * i0 + 2 * i05;
1133   // second derivative must be negative:
1134   if (a >= 0)
1135   {
1136     if (s0 >= s_05 && s0 >= s05)
1137     {
1138       max = s0;
1139       return (1.0f);
1140     }
1141     if (s_05 >= s0 && s_05 >= s05)
1142     {
1143       max = s_05;
1144       return (0.7f);
1145     }
1146     if (s05 >= s0 && s05 >= s_05)
1147     {
1148       max = s05;
1149       return (1.5f);
1150     }
1151   }
1152 
1153   int b = -5 * i_05 + 8 * i0 - 3 * i05;
1154   // calculate max location:
1155   float ret_val = -float (b) / float (2 * a);
1156   // saturate and return
1157   if (ret_val < 0.7f)
1158     ret_val = 0.7f;
1159   else
1160     if (ret_val > 1.5f)
1161       ret_val = 1.5f; // allow to be slightly off bounds ...?
1162   int c = +3 * i_05  -3 * i0    +1 * i05;
1163   max = float (c) + float(a) * ret_val * ret_val + float (b) * ret_val;
1164   max /= 1024.0f;
1165   return (ret_val);
1166 }
1167 
1168 /////////////////////////////////////////////////////////////////////////////////////////
1169 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)1170 pcl::keypoints::brisk::ScaleSpace::subpixel2D (
1171     const int s_0_0, const int s_0_1, const int s_0_2,
1172     const int s_1_0, const int s_1_1, const int s_1_2,
1173     const int s_2_0, const int s_2_1, const int s_2_2,
1174     float& delta_x, float& delta_y)
1175 {
1176   // the coefficients of the 2d quadratic function least-squares fit:
1177   int tmp1 =        s_0_0 + s_0_2 - 2*s_1_1 + s_2_0 + s_2_2;
1178   int coeff1 = 3 * (tmp1 + s_0_1 - ((s_1_0 + s_1_2) << 1) + s_2_1);
1179   int coeff2 = 3 * (tmp1 - ((s_0_1 + s_2_1) << 1) + s_1_0 + s_1_2);
1180   int tmp2 =                                  s_0_2 - s_2_0;
1181   int tmp3 =                         (s_0_0 + tmp2 - s_2_2);
1182   int tmp4 =                                   tmp3 -2 * tmp2;
1183   int coeff3 =                    -3 * (tmp3 + s_0_1 - s_2_1);
1184   int coeff4 =                    -3 * (tmp4 + s_1_0 - s_1_2);
1185   int coeff5 =            (s_0_0 - s_0_2 - s_2_0 + s_2_2) << 2;
1186   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;
1187 
1188 
1189   // 2nd derivative test:
1190   int H_det = 4 * coeff1 * coeff2 - coeff5 * coeff5;
1191 
1192   if (H_det == 0)
1193   {
1194     delta_x = 0.0f;
1195     delta_y = 0.0f;
1196     return (float (coeff6) / 18.0f);
1197   }
1198 
1199   if (!(H_det > 0 && coeff1 < 0))
1200   {
1201     // The maximum must be at the one of the 4 patch corners.
1202     int tmp_max = coeff3 + coeff4 + coeff5;
1203     delta_x = 1.0f; delta_y = 1.0f;
1204 
1205     int tmp = -coeff3 + coeff4 - coeff5;
1206     if (tmp > tmp_max)
1207     {
1208       tmp_max = tmp;
1209       delta_x = -1.0f; delta_y = 1.0f;
1210     }
1211     tmp = coeff3 - coeff4 - coeff5;
1212     if (tmp > tmp_max)
1213     {
1214       tmp_max = tmp;
1215       delta_x = 1.0f; delta_y = -1.0f;
1216     }
1217     tmp = -coeff3 - coeff4 + coeff5;
1218     if (tmp > tmp_max)
1219     {
1220       tmp_max = tmp;
1221       delta_x = -1.0f; delta_y = -1.0f;
1222     }
1223     return (float (tmp_max + coeff1 + coeff2 + coeff6) / 18.0f);
1224   }
1225 
1226   // this is hopefully the normal outcome of the Hessian test
1227   delta_x = float (2 * coeff2 * coeff3 - coeff4 * coeff5) / float (-H_det);
1228   delta_y = float (2 * coeff1 * coeff4 - coeff3 * coeff5) / float (-H_det);
1229   // TODO: this is not correct, but easy, so perform a real boundary maximum search:
1230   bool tx = false; bool tx_ = false; bool ty = false; bool ty_ = false;
1231   if (delta_x > 1.0f) tx = true;
1232   else if (delta_x < -1.0f) tx_=true;
1233   if (delta_y > 1.0f) ty = true;
1234   if (delta_y < -1.0f) ty_ = true;
1235 
1236   if (tx || tx_ || ty || ty_)
1237   {
1238     // get two candidates:
1239     float delta_x1 = 0.0f, delta_x2 = 0.0f, delta_y1 = 0.0f, delta_y2 = 0.0f;
1240     if (tx)
1241     {
1242       delta_x1 = 1.0f;
1243       delta_y1 = -float (coeff4 + coeff5) / float (2.0 * coeff2);
1244       if (delta_y1 > 1.0f) delta_y1 = 1.0f; else if (delta_y1 < -1.0f) delta_y1 = -1.0f;
1245     }
1246     else if (tx_)
1247     {
1248       delta_x1 = -1.0f;
1249       delta_y1 = -float (coeff4 - coeff5) / float (2.0 * coeff2);
1250       if (delta_y1 > 1.0f) delta_y1 = 1.0f; else if (delta_y1 < -1.0f) delta_y1 = -1.0f;
1251     }
1252     if (ty)
1253     {
1254       delta_y2 = 1.0f;
1255       delta_x2 = -float (coeff3 + coeff5) / float (2.0 * coeff1);
1256       if (delta_x2 > 1.0f) delta_x2 = 1.0f; else if (delta_x2 < -1.0f) delta_x2 = -1.0f;
1257     }
1258     else if (ty_)
1259     {
1260       delta_y2 = -1.0f;
1261       delta_x2 = -float (coeff3 - coeff5) / float (2.0 * coeff1);
1262       if (delta_x2 > 1.0f) delta_x2 = 1.0f; else if (delta_x2 < -1.0f) delta_x2 = -1.0f;
1263     }
1264     // insert both options for evaluation which to pick
1265     float max1 = (float (coeff1) * delta_x1 * delta_x1 + float (coeff2) * delta_y1 * delta_y1
1266                  +float (coeff3) * delta_x1 + float (coeff4) * delta_y1
1267                  +float (coeff5) * delta_x1 * delta_y1
1268                  +float (coeff6)) / 18.0f;
1269     float max2 = (float (coeff1) * delta_x2 * delta_x2 + float (coeff2) * delta_y2 * delta_y2
1270                  +float (coeff3) * delta_x2 + float (coeff4) * delta_y2
1271                  +float (coeff5) * delta_x2 * delta_y2
1272                  +float (coeff6)) / 18.0f;
1273     if (max1 > max2)
1274     {
1275       delta_x = delta_x1;
1276       delta_y = delta_x1;
1277       return (max1);
1278     }
1279     delta_x = delta_x2;
1280     delta_y = delta_x2;
1281     return (max2);
1282   }
1283 
1284   // this is the case of the maximum inside the boundaries:
1285   return ((float (coeff1) * delta_x * delta_x + float (coeff2) * delta_y * delta_y
1286           +float (coeff3) * delta_x + float (coeff4) * delta_y
1287           +float (coeff5) * delta_x * delta_y
1288           +float (coeff6)) / 18.0f);
1289 }
1290 
1291 /////////////////////////////////////////////////////////////////////////////////////////
1292 // construct a layer
Layer(const std::vector<unsigned char> & img,int width,int height,float scale,float offset)1293 pcl::keypoints::brisk::Layer::Layer (
1294     const std::vector<unsigned char>& img,
1295     int width, int height,
1296     float scale, float offset)
1297 {
1298   img_width_ = width;
1299   img_height_ = height;
1300   img_ = img;
1301   scores_ = std::vector<unsigned char> (img_width_ * img_height_, 0);
1302 
1303   // attention: this means that the passed image reference must point to persistent memory
1304   scale_  = scale;
1305   offset_ = offset;
1306 
1307   // create an agast detector
1308   oast_detector_.reset (new pcl::keypoints::agast::OastDetector9_16 (img_width_, img_height_, 0));
1309   agast_detector_5_8_.reset (new pcl::keypoints::agast::AgastDetector5_8 (img_width_, img_height_, 0));
1310 }
1311 
1312 /////////////////////////////////////////////////////////////////////////////////////////
1313 // derive a layer
Layer(const pcl::keypoints::brisk::Layer & layer,int mode)1314 pcl::keypoints::brisk::Layer::Layer (const pcl::keypoints::brisk::Layer& layer, int mode)
1315 {
1316   if (mode == CommonParams::HALFSAMPLE)
1317   {
1318     img_width_ = layer.img_width_ / 2;
1319     img_height_ = layer.img_height_ / 2;
1320     img_.resize (img_width_ * img_height_);
1321 
1322     halfsample (layer.img_, layer.img_width_, layer.img_height_, img_, img_width_, img_height_);
1323     scale_  = layer.scale_ * 2.0f;
1324     offset_ = 0.5f * scale_ - 0.5f;
1325   }
1326   else
1327   {
1328     img_width_ = 2 * layer.img_width_ / 3;
1329     img_height_ = 2 * layer.img_height_ / 3;
1330     img_.resize (img_width_ * img_height_);
1331 
1332     twothirdsample (layer.img_, layer.img_width_, layer.img_height_, img_, img_width_, img_height_);
1333     scale_  = layer.scale_ * 1.5f;
1334     offset_ = 0.5f * scale_ - 0.5f;
1335   }
1336 
1337   scores_ = std::vector<unsigned char> (img_width_ * img_height_, 0);
1338 
1339   // create an agast detector
1340   oast_detector_.reset (new pcl::keypoints::agast::OastDetector9_16 (img_width_, img_height_, 0));
1341   agast_detector_5_8_.reset (new pcl::keypoints::agast::AgastDetector5_8 (img_width_, img_height_, 0));
1342 }
1343 
1344 /////////////////////////////////////////////////////////////////////////////////////////
1345 // Fast/Agast
1346 // wraps the agast class
1347 void
getAgastPoints(std::uint8_t threshold,std::vector<pcl::PointUV,Eigen::aligned_allocator<pcl::PointUV>> & keypoints)1348 pcl::keypoints::brisk::Layer::getAgastPoints (
1349     std::uint8_t threshold, std::vector<pcl::PointUV, Eigen::aligned_allocator<pcl::PointUV> > &keypoints)
1350 {
1351   oast_detector_->setThreshold (threshold);
1352   oast_detector_->detect (&img_[0], keypoints);
1353 
1354   // also write scores
1355   const int num = int (keypoints.size ());
1356   const int imcols = img_width_;
1357 
1358   for (int i = 0; i < num; i++)
1359   {
1360     const int offs = int (keypoints[i].u + keypoints[i].v * float (imcols));
1361     *(&scores_[0] + offs) = static_cast<unsigned char> (oast_detector_->computeCornerScore (&img_[0] + offs));
1362   }
1363 }
1364 
1365 /////////////////////////////////////////////////////////////////////////////////////////
1366 std::uint8_t
getAgastScore(int x,int y,std::uint8_t threshold)1367 pcl::keypoints::brisk::Layer::getAgastScore (int x, int y, std::uint8_t threshold)
1368 {
1369   if (x < 3 || y < 3)
1370   {
1371     return (0);
1372   }
1373   if (x >= img_width_ - 3 || y >= img_height_ - 3)
1374   {
1375     return (0);
1376   }
1377   std::uint8_t& score = *(&scores_[0] + x + y * img_width_);
1378   if (score > 2)
1379   {
1380     return (score);
1381   }
1382   oast_detector_->setThreshold (threshold - 1);
1383   score = std::uint8_t (oast_detector_->computeCornerScore (&img_[0] + x + y * img_width_));
1384   if (score < threshold) score = 0;
1385   return (score);
1386 }
1387 
1388 /////////////////////////////////////////////////////////////////////////////////////////
1389 std::uint8_t
getAgastScore_5_8(int x,int y,std::uint8_t threshold)1390 pcl::keypoints::brisk::Layer::getAgastScore_5_8 (int x, int y, std::uint8_t threshold)
1391 {
1392   if (x < 2 || y < 2)
1393   {
1394     return 0;
1395   }
1396 
1397   if (x >= img_width_ - 2 || y >= img_height_ - 2)
1398   {
1399     return 0;
1400   }
1401 
1402   agast_detector_5_8_->setThreshold (threshold - 1);
1403   std::uint8_t score = std::uint8_t (agast_detector_5_8_->computeCornerScore (&img_[0] + x + y * img_width_));
1404   if (score < threshold) score = 0;
1405   return (score);
1406 }
1407 
1408 /////////////////////////////////////////////////////////////////////////////////////////
1409 std::uint8_t
getAgastScore(float xf,float yf,std::uint8_t threshold,float scale)1410 pcl::keypoints::brisk::Layer::getAgastScore (float xf, float yf, std::uint8_t threshold, float scale)
1411 {
1412   if (scale <= 1.0f)
1413   {
1414     // just do an interpolation inside the layer
1415     const int x = int (xf);
1416     const float rx1 = xf - float (x);
1417     const float rx = 1.0f - rx1;
1418     const int y = int (yf);
1419     const float ry1 = yf -float (y);
1420     const float ry  = 1.0f -ry1;
1421 
1422     const float value = rx  * ry  * getAgastScore (x,     y,     threshold)+
1423             rx1 * ry  * getAgastScore (x + 1, y,     threshold)+
1424             rx  * ry1 * getAgastScore (x,     y + 1, threshold)+
1425             rx1 * ry1 * getAgastScore (x + 1, y + 1, threshold);
1426 
1427 
1428     return (static_cast<std::uint8_t> (value));
1429   }
1430 
1431   // this means we overlap area smoothing
1432   const float halfscale = scale / 2.0f;
1433   // get the scores first:
1434   for (int x = int (xf - halfscale); x <= int (xf + halfscale + 1.0f); x++)
1435     for (int y = int (yf - halfscale); y <= int (yf + halfscale + 1.0f); y++)
1436       getAgastScore (x, y, threshold);
1437   // get the smoothed value
1438   return (getValue (scores_, img_width_, img_height_, xf, yf, scale));
1439 }
1440 
1441 /////////////////////////////////////////////////////////////////////////////////////////
1442 // access gray values (smoothed/interpolated)
1443 std::uint8_t
getValue(const std::vector<unsigned char> & mat,int width,int height,float xf,float yf,float scale)1444 pcl::keypoints::brisk::Layer::getValue (
1445     const std::vector<unsigned char>& mat,
1446     int width, int height,
1447     float xf, float yf, float scale)
1448 {
1449   pcl::utils::ignore(height);
1450   assert (!mat.empty ());
1451   // get the position
1452   const int x = int (std::floor (xf));
1453   const int y = int (std::floor (yf));
1454   const std::vector<unsigned char>& image = mat;
1455   const int& imagecols = width;
1456 
1457   // get the sigma_half:
1458   const float sigma_half = scale / 2.0f;
1459   const float area = 4.0f * sigma_half * sigma_half;
1460 
1461   // calculate output:
1462   int ret_val;
1463   if (sigma_half < 0.5)
1464   {
1465     // interpolation multipliers:
1466 		const int r_x   = static_cast<int> ((xf - float (x)) * 1024);
1467 		const int r_y   = static_cast<int> ((yf - float (y)) * 1024);
1468     const int r_x_1 = (1024 - r_x);
1469     const int r_y_1 = (1024 - r_y);
1470     const unsigned char* ptr = &image[0] + x + y * imagecols;
1471 
1472     // just interpolate:
1473     ret_val = (r_x_1 * r_y_1 * int (*ptr));
1474     ptr++;
1475     ret_val += (r_x * r_y_1 * int (*ptr));
1476     ptr += imagecols;
1477     ret_val += (r_x * r_y * int (*ptr));
1478     ptr--;
1479     ret_val += (r_x_1 * r_y * int (*ptr));
1480     return (static_cast<std::uint8_t> (0xFF & ((ret_val + 512) / 1024 / 1024)));
1481   }
1482 
1483   // this is the standard case (simple, not speed optimized yet):
1484 
1485   // scaling:
1486   const int scaling  = static_cast<int> (4194304.0f / area);
1487   const int scaling2 = static_cast<int> (float (scaling) * area / 1024.0f);
1488 
1489   // calculate borders
1490   const float x_1 = xf - sigma_half;
1491   const float x1  = xf + sigma_half;
1492   const float y_1 = yf - sigma_half;
1493   const float y1  = yf + sigma_half;
1494 
1495   const int x_left   = int (x_1 + 0.5f);
1496   const int y_top    = int (y_1 + 0.5f);
1497   const int x_right  = int (x1 + 0.5f);
1498   const int y_bottom = int (y1 + 0.5f);
1499 
1500   // overlap area - multiplication factors:
1501   const float r_x_1 = float (x_left) - x_1 + 0.5f;
1502   const float r_y_1 = float (y_top)  - y_1 + 0.5f;
1503   const float r_x1  = x1 - float (x_right) + 0.5f;
1504   const float r_y1  = y1 - float (y_bottom) + 0.5f;
1505   const int dx = x_right  - x_left - 1;
1506   const int dy = y_bottom - y_top  - 1;
1507   const int A = static_cast<int> ((r_x_1 * r_y_1) * float (scaling));
1508   const int B = static_cast<int> ((r_x1  * r_y_1) * float (scaling));
1509   const int C = static_cast<int> ((r_x1  * r_y1)  * float (scaling));
1510   const int D = static_cast<int> ((r_x_1 * r_y1)  * float (scaling));
1511   const int r_x_1_i = static_cast<int> (r_x_1 * float (scaling));
1512   const int r_y_1_i = static_cast<int> (r_y_1 * float (scaling));
1513   const int r_x1_i  = static_cast<int> (r_x1  * float (scaling));
1514   const int r_y1_i  = static_cast<int> (r_y1  * float (scaling));
1515 
1516   // now the calculation:
1517   const unsigned char* ptr = &image[0] + x_left + imagecols * y_top;
1518   // first row:
1519   ret_val = A * int (*ptr);
1520   ptr++;
1521   const unsigned char* end1 = ptr + dx;
1522   for (; ptr < end1; ptr++)
1523     ret_val += r_y_1_i * int (*ptr);
1524 
1525   ret_val += B * int (*ptr);
1526 
1527   // middle ones:
1528   ptr += imagecols - dx - 1;
1529   const unsigned char* end_j = ptr + dy * imagecols;
1530 
1531   for (; ptr < end_j; ptr += imagecols - dx - 1)
1532   {
1533     ret_val += r_x_1_i * int (*ptr);
1534     ptr++;
1535     const unsigned char* end2 = ptr + dx;
1536     for (; ptr < end2; ptr++)
1537       ret_val += int (*ptr) * scaling;
1538 
1539     ret_val += r_x1_i * int (*ptr);
1540   }
1541 
1542   // last row:
1543   ret_val += D * int (*ptr);
1544   ptr++;
1545   const unsigned char* end3 = ptr + dx;
1546   for (; ptr < end3; ptr++)
1547     ret_val += r_y1_i * int (*ptr);
1548 
1549   ret_val += C * int (*ptr);
1550 
1551   return (static_cast<std::uint8_t> (0xFF & ((ret_val + scaling2 / 2) / scaling2 / 1024)));
1552 }
1553 
1554 /////////////////////////////////////////////////////////////////////////////////////////
1555 // half sampling
1556 inline void
halfsample(const std::vector<unsigned char> & srcimg,int srcwidth,int srcheight,std::vector<unsigned char> & dstimg,int dstwidth,int dstheight)1557 pcl::keypoints::brisk::Layer::halfsample (
1558     const std::vector<unsigned char>& srcimg,
1559     int srcwidth, int srcheight,
1560     std::vector<unsigned char>& dstimg,
1561     int dstwidth, int dstheight)
1562 {
1563   pcl::utils::ignore(dstheight);
1564 #if defined(__SSSE3__) && !defined(__i386__)
1565   const unsigned short leftoverCols = static_cast<unsigned short> ((srcwidth % 16) / 2); // take care with border...
1566   const bool noleftover = (srcwidth % 16) == 0; // note: leftoverCols can be zero but this still false...
1567 
1568   // make sure the destination image is of the right size:
1569   assert (std::floor (double (srcwidth) / 2.0) == dstwidth);
1570   assert (std::floor (double (srcheight) / 2.0) == dstheight);
1571 
1572   // mask needed later:
1573   __m128i mask = _mm_set_epi32 (0x00FF00FF, 0x00FF00FF, 0x00FF00FF, 0x00FF00FF);
1574 
1575   // data pointers:
1576   const __m128i* p1 = reinterpret_cast<const __m128i*> (&srcimg[0]);
1577   const __m128i* p2 = reinterpret_cast<const __m128i*> (&srcimg[0] + srcwidth);
1578   __m128i* p_dest = reinterpret_cast<__m128i*> (&dstimg[0]);
1579   unsigned char* p_dest_char;//=(unsigned char*)p_dest;
1580 
1581   // size:
1582   const unsigned int size = (srcwidth * srcheight) / 16;
1583   const unsigned int hsize = srcwidth / 16;
1584   const __m128i* p_end = p1 + size;
1585   unsigned int row = 0;
1586   const unsigned int end = hsize / 2;
1587   bool half_end;
1588   half_end = hsize % 2 != 0;
1589   while (p2 < p_end)
1590   {
1591     for (unsigned int i = 0; i < end; i++)
1592     {
1593       // load the two blocks of memory:
1594       __m128i upper;
1595       __m128i lower;
1596       if (noleftover)
1597       {
1598         upper = _mm_load_si128 (p1);
1599         lower = _mm_load_si128 (p2);
1600       }
1601       else
1602       {
1603         upper = _mm_loadu_si128 (p1);
1604         lower = _mm_loadu_si128 (p2);
1605       }
1606 
1607       __m128i result1 = _mm_avg_epu8 (upper, lower);
1608 
1609       // increment the pointers:
1610       p1++;
1611       p2++;
1612 
1613       // load the two blocks of memory:
1614       upper = _mm_loadu_si128 (p1);
1615       lower = _mm_loadu_si128 (p2);
1616       __m128i result2 = _mm_avg_epu8 (upper, lower);
1617       // calculate the shifted versions:
1618       __m128i result1_shifted = _mm_srli_si128 (result1, 1);
1619       __m128i result2_shifted = _mm_srli_si128 (result2, 1);
1620       // pack:
1621       __m128i result = _mm_packus_epi16 (_mm_and_si128 (result1, mask), _mm_and_si128 (result2, mask));
1622       __m128i result_shifted = _mm_packus_epi16 (_mm_and_si128 (result1_shifted, mask),_mm_and_si128 (result2_shifted, mask));
1623       // average for the second time:
1624       result = _mm_avg_epu8 (result, result_shifted);
1625 
1626       // store to memory
1627       _mm_storeu_si128 (p_dest, result);
1628 
1629       // increment the pointers:
1630       p1++;
1631       p2++;
1632       p_dest++;
1633       //p_dest_char=(unsigned char*)p_dest;
1634     }
1635     // if we are not at the end of the row, do the rest:
1636     if (half_end)
1637     {
1638       // load the two blocks of memory:
1639       __m128i upper;
1640       __m128i lower;
1641       if (noleftover)
1642       {
1643         upper = _mm_load_si128 (p1);
1644         lower = _mm_load_si128 (p2);
1645       }
1646       else
1647       {
1648         upper = _mm_loadu_si128 (p1);
1649         lower = _mm_loadu_si128 (p2);
1650       }
1651 
1652 	  __m128i result1 = _mm_avg_epu8 (upper, lower);
1653 
1654       // increment the pointers:
1655       p1++;
1656       p2++;
1657 
1658       // compute horizontal pairwise average and store
1659       p_dest_char = reinterpret_cast<unsigned char*> (p_dest);
1660 #ifdef __GNUC__
1661       using UCHAR_ALIAS __attribute__ ((__may_alias__)) = unsigned char;
1662 #endif
1663 #ifdef _MSC_VER
1664       // Todo: find the equivalent to may_alias
1665       #define UCHAR_ALIAS unsigned char //__declspec(noalias)
1666 #endif
1667       const UCHAR_ALIAS* result = reinterpret_cast<const UCHAR_ALIAS*> (&result1);
1668       for (unsigned int j = 0; j < 8; j++)
1669       {
1670         *(p_dest_char++) = static_cast<unsigned char> ((*(result + 2 * j) + *(result + 2 * j + 1)) / 2);
1671       }
1672       //p_dest_char=(unsigned char*)p_dest;
1673     }
1674     else
1675       p_dest_char = reinterpret_cast<unsigned char*> (p_dest);
1676 
1677     if (noleftover)
1678     {
1679       row++;
1680       p_dest = reinterpret_cast<__m128i*> (&dstimg[0] + row * dstwidth);
1681       p1 = reinterpret_cast<const __m128i*> (&srcimg[0] + 2 * row * srcwidth);
1682       //p2=(__m128i*)(srcimg.data+(2*row+1)*srcwidth);
1683       //p1+=hsize;
1684       p2 = p1 + hsize;
1685     }
1686     else
1687     {
1688       const unsigned char* p1_src_char = reinterpret_cast<const unsigned char*> (p1);
1689       const unsigned char* p2_src_char = reinterpret_cast<const unsigned char*> (p2);
1690       for (unsigned int k = 0; k < leftoverCols; k++)
1691       {
1692         unsigned short tmp = static_cast<unsigned short> (p1_src_char[k] + p1_src_char[k+1]+ p2_src_char[k] + p2_src_char[k+1]);
1693         *(p_dest_char++) = static_cast<unsigned char>(tmp / 4);
1694       }
1695       // done with the two rows:
1696       row++;
1697       p_dest = reinterpret_cast<__m128i*> (&dstimg[0] + row * dstwidth);
1698       p1 = reinterpret_cast<const __m128i*> (&srcimg[0] + 2 * row * srcwidth);
1699       p2 = reinterpret_cast<const __m128i*> (&srcimg[0] + (2 * row + 1) * srcwidth);
1700     }
1701   }
1702 #else
1703   pcl::utils::ignore(srcimg, srcwidth, srcheight, dstimg, dstwidth);
1704   PCL_ERROR("brisk without SSSE3 support not implemented\n");
1705 #endif
1706 }
1707 
1708 /////////////////////////////////////////////////////////////////////////////////////////
1709 void
twothirdsample(const std::vector<unsigned char> & srcimg,int srcwidth,int srcheight,std::vector<unsigned char> & dstimg,int dstwidth,int dstheight)1710 pcl::keypoints::brisk::Layer::twothirdsample (
1711     const std::vector<unsigned char>& srcimg,
1712     int srcwidth, int srcheight,
1713     std::vector<unsigned char>& dstimg,
1714     int dstwidth, int dstheight)
1715 {
1716   pcl::utils::ignore(dstheight);
1717 #if defined(__SSSE3__) && !defined(__i386__)
1718   const unsigned short leftoverCols = static_cast<unsigned short> (((srcwidth / 3) * 3) % 15);// take care with border...
1719 
1720   // make sure the destination image is of the right size:
1721   assert (std::floor (double (srcwidth) / 3.0 * 2.0) == dstwidth);
1722   assert (std::floor (double (srcheight) / 3.0 * 2.0) == dstheight);
1723 
1724   // masks:
1725   __m128i mask1 = _mm_set_epi8 (char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),12,char(0x80),10,char(0x80),7,char(0x80),4,char(0x80),1);
1726   __m128i mask2 = _mm_set_epi8 (char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),12,char(0x80),10,char(0x80),7,char(0x80),4,char(0x80),1,char(0x80));
1727   __m128i mask = _mm_set_epi8 (char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),14,12,11,9,8,6,5,3,2,0);
1728   __m128i store_mask = _mm_set_epi8 (0x0,0x0,0x0,0x0,0x0,0x0,char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80),char(0x80));
1729 
1730   // data pointers:
1731   const unsigned char* p1 = &srcimg[0];
1732   const unsigned char* p2 = p1 + srcwidth;
1733   const unsigned char* p3 = p2 + srcwidth;
1734   unsigned char* p_dest1 = &dstimg[0];
1735   unsigned char* p_dest2 = p_dest1 + dstwidth;
1736   const unsigned char* p_end = p1 + (srcwidth * srcheight);
1737 
1738   unsigned int row = 0;
1739   unsigned int row_dest = 0;
1740   int hsize = srcwidth / 15;
1741   while (p3 < p_end)
1742   {
1743     for (int i = 0; i < hsize; i++)
1744     {
1745       // load three rows
1746       const __m128i first = _mm_loadu_si128  (reinterpret_cast<const __m128i*> (p1));
1747       const __m128i second = _mm_loadu_si128 (reinterpret_cast<const __m128i*> (p2));
1748       const __m128i third = _mm_loadu_si128  (reinterpret_cast<const __m128i*> (p3));
1749 
1750       // upper row:
1751       __m128i upper = _mm_avg_epu8 (_mm_avg_epu8 (first,second),first);
1752       __m128i temp1_upper = _mm_or_si128 (_mm_shuffle_epi8 (upper,mask1), _mm_shuffle_epi8 (upper,mask2));
1753       __m128i temp2_upper  = _mm_shuffle_epi8 (upper,mask);
1754       __m128i result_upper = _mm_avg_epu8 (_mm_avg_epu8 (temp2_upper, temp1_upper), temp2_upper);
1755 
1756       // lower row:
1757       __m128i lower = _mm_avg_epu8 (_mm_avg_epu8 (third, second), third);
1758       __m128i temp1_lower  = _mm_or_si128 (_mm_shuffle_epi8 (lower, mask1), _mm_shuffle_epi8 (lower, mask2));
1759       __m128i temp2_lower  = _mm_shuffle_epi8 (lower,mask);
1760       __m128i result_lower = _mm_avg_epu8 (_mm_avg_epu8 (temp2_lower, temp1_lower), temp2_lower);
1761 
1762       // store:
1763       if (i * 10 + 16 > dstwidth)
1764       {
1765         _mm_maskmoveu_si128 (result_upper, store_mask, reinterpret_cast<char*> (p_dest1));
1766         _mm_maskmoveu_si128 (result_lower, store_mask, reinterpret_cast<char*> (p_dest2));
1767       }
1768       else
1769       {
1770         _mm_storeu_si128 (reinterpret_cast<__m128i*> (p_dest1), result_upper);
1771         _mm_storeu_si128 (reinterpret_cast<__m128i*> (p_dest2), result_lower);
1772       }
1773 
1774       // shift pointers:
1775       p1 += 15;
1776       p2 += 15;
1777       p3 += 15;
1778       p_dest1 += 10;
1779       p_dest2 += 10;
1780     }
1781 
1782     // fill the remainder:
1783     for (unsigned int j = 0; j < leftoverCols; j+= 3)
1784     {
1785       const unsigned short A1 = *(p1++);
1786       const unsigned short A2 = *(p1++);
1787       const unsigned short A3 = *(p1++);
1788       const unsigned short B1 = *(p2++);
1789       const unsigned short B2 = *(p2++);
1790       const unsigned short B3 = *(p2++);
1791       const unsigned short C1 = *(p3++);
1792       const unsigned short C2 = *(p3++);
1793       const unsigned short C3 = *(p3++);
1794 
1795       *(p_dest1++) = static_cast<unsigned char> (((4 * A1 + 2 * (A2 + B1) + B2) / 9) & 0x00FF);
1796       *(p_dest1++) = static_cast<unsigned char> (((4 * A3 + 2 * (A2 + B3) + B2) / 9) & 0x00FF);
1797       *(p_dest2++) = static_cast<unsigned char> (((4 * C1 + 2 * (C2 + B1) + B2) / 9) & 0x00FF);
1798       *(p_dest2++) = static_cast<unsigned char> (((4 * C3 + 2 * (C2 + B3) + B2) / 9) & 0x00FF);
1799     }
1800 
1801     // increment row counter:
1802     row += 3;
1803     row_dest += 2;
1804 
1805     // reset pointers
1806     p1 = &srcimg[0] + row * srcwidth;
1807     p2 = p1 + srcwidth;
1808     p3 = p2 + srcwidth;
1809     p_dest1 = &dstimg[0] + row_dest * dstwidth;
1810     p_dest2 = p_dest1 + dstwidth;
1811   }
1812 #else
1813   pcl::utils::ignore(srcimg, srcwidth, srcheight, dstimg, dstwidth);
1814   PCL_ERROR("brisk without SSSE3 support not implemented\n");
1815 #endif
1816 }
1817 
1818