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