Point Cloud Library (PCL) 1.12.0
Loading...
Searching...
No Matches
brisk_2d.hpp
1/*
2 * Software License Agreement (BSD License)
3 *
4 * Point Cloud Library (PCL) - www.pointclouds.org
5 * Copyright (c) 2012-, Open Perception , Inc.
6 * Copyright (C) 2011 The Autonomous Systems Lab (ASL), ETH Zurich,
7 * Stefan Leutenegger, Simon Lynen and Margarita Chli.
8 *
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary 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 binary 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 be 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
41#ifndef PCL_FEATURES_IMPL_BRISK_2D_HPP_
42#define PCL_FEATURES_IMPL_BRISK_2D_HPP_
43
44
45namespace pcl
46{
47
48template <typename PointInT, typename PointOutT, typename KeypointT, typename IntensityT>
50 : rotation_invariance_enabled_ (true)
51 , scale_invariance_enabled_ (true)
52 , pattern_scale_ (1.0f)
53 , input_cloud_ (), keypoints_ (), scale_range_ (), pattern_points_ (), points_ ()
54 , n_rot_ (1024), scale_list_ (nullptr), size_list_ (nullptr)
55 , scales_ (64)
56 , scalerange_ (30)
57 , basic_size_ (12.0)
58 , strings_ (0), d_max_ (0.0f), d_min_ (0.0f), short_pairs_ (), long_pairs_ ()
59 , no_short_pairs_ (0), no_long_pairs_ (0)
60 , intensity_ ()
61 , name_ ("BRISK2Destimation")
62{
63 // Since we do not assume pattern_scale_ should be changed by the user, we
64 // can initialize the kernel in the constructor
65 std::vector<float> r_list;
66 std::vector<int> n_list;
67
68 // this is the standard pattern found to be suitable also
69 r_list.resize (5);
70 n_list.resize (5);
71 const float f = 0.85f * pattern_scale_;
72
73 r_list[0] = f * 0.0f;
74 r_list[1] = f * 2.9f;
75 r_list[2] = f * 4.9f;
76 r_list[3] = f * 7.4f;
77 r_list[4] = f * 10.8f;
78
79 n_list[0] = 1;
80 n_list[1] = 10;
81 n_list[2] = 14;
82 n_list[3] = 15;
83 n_list[4] = 20;
84
85 generateKernel (r_list, n_list, 5.85f * pattern_scale_, 8.2f * pattern_scale_);
86}
87
88
89template <typename PointInT, typename PointOutT, typename KeypointT, typename IntensityT>
91{
92 delete [] pattern_points_;
93 delete [] short_pairs_;
94 delete [] long_pairs_;
95 delete [] scale_list_;
96 delete [] size_list_;
97}
98
99
100template <typename PointInT, typename PointOutT, typename KeypointT, typename IntensityT> void
102 std::vector<float> &radius_list,
103 std::vector<int> &number_list, float d_max, float d_min,
104 std::vector<int> index_change)
105{
106 d_max_ = d_max;
107 d_min_ = d_min;
108
109 // get the total number of points
110 const auto rings = radius_list.size ();
111 assert (radius_list.size () != 0 && radius_list.size () == number_list.size ());
112 points_ = 0; // remember the total number of points
113 for (const auto number: number_list)
114 points_ += number;
115
116 // set up the patterns
117 pattern_points_ = new BriskPatternPoint[points_*scales_*n_rot_];
118 BriskPatternPoint* pattern_iterator = pattern_points_;
119
120 // define the scale discretization:
121 static const float lb_scale = std::log (scalerange_) / std::log (2.0);
122 static const float lb_scale_step = lb_scale / (float (scales_));
123
124 scale_list_ = new float[scales_];
125 size_list_ = new unsigned int[scales_];
126
127 const float sigma_scale = 1.3f;
128
129 for (unsigned int scale = 0; scale < scales_; ++scale)
130 {
131 scale_list_[scale] = static_cast<float> (pow (double (2.0), static_cast<double> (float (scale) * lb_scale_step)));
132 size_list_[scale] = 0;
133
134 // generate the pattern points look-up
135 for (std::size_t rot = 0; rot < n_rot_; ++rot)
136 {
137 // this is the rotation of the feature
138 double theta = double (rot) * 2 * M_PI / double (n_rot_);
139 for (int ring = 0; ring < static_cast<int>(rings); ++ring)
140 {
141 for (int num = 0; num < number_list[ring]; ++num)
142 {
143 // the actual coordinates on the circle
144 double alpha = double (num) * 2 * M_PI / double (number_list[ring]);
145
146 // feature rotation plus angle of the point
147 pattern_iterator->x = scale_list_[scale] * radius_list[ring] * static_cast<float> (std::cos (alpha + theta));
148 pattern_iterator->y = scale_list_[scale] * radius_list[ring] * static_cast<float> (sin (alpha + theta));
149 // and the gaussian kernel sigma
150 if (ring == 0)
151 pattern_iterator->sigma = sigma_scale * scale_list_[scale] * 0.5f;
152 else
153 pattern_iterator->sigma = static_cast<float> (sigma_scale * scale_list_[scale] * (double (radius_list[ring])) * sin (M_PI / double (number_list[ring])));
154
155 // adapt the sizeList if necessary
156 const unsigned int size = static_cast<unsigned int> (std::ceil (((scale_list_[scale] * radius_list[ring]) + pattern_iterator->sigma)) + 1);
157
158 if (size_list_[scale] < size)
159 size_list_[scale] = size;
160
161 // increment the iterator
162 ++pattern_iterator;
163 }
164 }
165 }
166 }
167
168 // now also generate pairings
169 short_pairs_ = new BriskShortPair[points_ * (points_ - 1) / 2];
170 long_pairs_ = new BriskLongPair[points_ * (points_ - 1) / 2];
171 no_short_pairs_ = 0;
172 no_long_pairs_ = 0;
173
174 // fill index_change with 0..n if empty
175 if (index_change.empty ())
176 {
177 index_change.resize (points_ * (points_ - 1) / 2);
178 }
179 std::iota(index_change.begin (), index_change.end (), 0);
180
181 const float d_min_sq = d_min_ * d_min_;
182 const float d_max_sq = d_max_ * d_max_;
183 for (unsigned int i = 1; i < points_; i++)
184 {
185 for (unsigned int j = 0; j < i; j++)
186 { //(find all the pairs)
187 // point pair distance:
188 const float dx = pattern_points_[j].x - pattern_points_[i].x;
189 const float dy = pattern_points_[j].y - pattern_points_[i].y;
190 const float norm_sq = (dx*dx+dy*dy);
191 if (norm_sq > d_min_sq)
192 {
193 // save to long pairs
194 BriskLongPair& longPair = long_pairs_[no_long_pairs_];
195 longPair.weighted_dx = int ((dx / (norm_sq)) * 2048.0 + 0.5);
196 longPair.weighted_dy = int ((dy / (norm_sq)) * 2048.0 + 0.5);
197 longPair.i = i;
198 longPair.j = j;
199 ++no_long_pairs_;
200 }
201 else if (norm_sq < d_max_sq)
202 {
203 // save to short pairs
204 assert (no_short_pairs_ < index_change.size ()); // make sure the user passes something sensible
205 BriskShortPair& shortPair = short_pairs_[index_change[no_short_pairs_]];
206 shortPair.j = j;
207 shortPair.i = i;
208 ++no_short_pairs_;
209 }
210 }
211 }
212
213 // no bits:
214 strings_ = int (std::ceil ((float (no_short_pairs_)) / 128.0)) * 4 * 4;
215}
216
217
218template <typename PointInT, typename PointOutT, typename KeypointT, typename IntensityT> inline int
220 const std::vector<unsigned char> &image,
221 int image_width, int,
222 //const Stefan& integral,
223 const std::vector<int> &integral_image,
224 const float key_x, const float key_y, const unsigned int scale,
225 const unsigned int rot, const unsigned int point) const
226{
227 // get the float position
228 const BriskPatternPoint& brisk_point = pattern_points_[scale * n_rot_*points_ + rot * points_ + point];
229 const float xf = brisk_point.x + key_x;
230 const float yf = brisk_point.y + key_y;
231 const int x = int (xf);
232 const int y = int (yf);
233 const int& imagecols = image_width;
234
235 // get the sigma:
236 const float sigma_half = brisk_point.sigma;
237 const float area = 4.0f * sigma_half * sigma_half;
238
239 // Get the point step
240
241 // calculate output:
242 int ret_val;
243 if (sigma_half < 0.5)
244 {
245 // interpolation multipliers:
246 const int r_x = static_cast<int> ((xf - float (x)) * 1024);
247 const int r_y = static_cast<int> ((yf - float (y)) * 1024);
248 const int r_x_1 = (1024 - r_x);
249 const int r_y_1 = (1024 - r_y);
250
251 //+const unsigned char* ptr = static_cast<const unsigned char*> (&image[0].r) + x + y * imagecols;
252 const unsigned char* ptr = static_cast<const unsigned char*>(&image[0]) + x + y * imagecols;
253
254 // just interpolate:
255 ret_val = (r_x_1 * r_y_1 * int (*ptr));
256
257 //+ptr += sizeof (PointInT);
258 ptr++;
259
260 ret_val += (r_x * r_y_1 * int (*ptr));
261
262 //+ptr += (imagecols * sizeof (PointInT));
263 ptr += imagecols;
264
265 ret_val += (r_x * r_y * int (*ptr));
266
267 //+ptr -= sizeof (PointInT);
268 ptr--;
269
270 ret_val += (r_x_1 * r_y * int (*ptr));
271 return (ret_val + 512) / 1024;
272 }
273
274 // this is the standard case (simple, not speed optimized yet):
275
276 // scaling:
277 const int scaling = static_cast<int> (4194304.0f / area);
278 const int scaling2 = static_cast<int> (float (scaling) * area / 1024.0f);
279
280 // the integral image is larger:
281 const int integralcols = imagecols + 1;
282
283 // calculate borders
284 const float x_1 = xf - sigma_half;
285 const float x1 = xf + sigma_half;
286 const float y_1 = yf - sigma_half;
287 const float y1 = yf + sigma_half;
288
289 const int x_left = int (x_1 + 0.5);
290 const int y_top = int (y_1 + 0.5);
291 const int x_right = int (x1 + 0.5);
292 const int y_bottom = int (y1 + 0.5);
293
294 // overlap area - multiplication factors:
295 const float r_x_1 = float (x_left) - x_1 + 0.5f;
296 const float r_y_1 = float (y_top) - y_1 + 0.5f;
297 const float r_x1 = x1 - float (x_right) + 0.5f;
298 const float r_y1 = y1 - float (y_bottom) + 0.5f;
299 const int dx = x_right - x_left - 1;
300 const int dy = y_bottom - y_top - 1;
301 const int A = static_cast<int> ((r_x_1 * r_y_1) * float (scaling));
302 const int B = static_cast<int> ((r_x1 * r_y_1) * float (scaling));
303 const int C = static_cast<int> ((r_x1 * r_y1) * float (scaling));
304 const int D = static_cast<int> ((r_x_1 * r_y1) * float (scaling));
305 const int r_x_1_i = static_cast<int> (r_x_1 * float (scaling));
306 const int r_y_1_i = static_cast<int> (r_y_1 * float (scaling));
307 const int r_x1_i = static_cast<int> (r_x1 * float (scaling));
308 const int r_y1_i = static_cast<int> (r_y1 * float (scaling));
309
310 if (dx + dy > 2)
311 {
312 // now the calculation:
313
314 //+const unsigned char* ptr = static_cast<const unsigned char*> (&image[0].r) + x_left + imagecols * y_top;
315 const unsigned char* ptr = static_cast<const unsigned char*>(&image[0]) + x_left + imagecols * y_top;
316
317 // first the corners:
318 ret_val = A * int (*ptr);
319
320 //+ptr += (dx + 1) * sizeof (PointInT);
321 ptr += dx + 1;
322
323 ret_val += B * int (*ptr);
324
325 //+ptr += (dy * imagecols + 1) * sizeof (PointInT);
326 ptr += dy * imagecols + 1;
327
328 ret_val += C * int (*ptr);
329
330 //+ptr -= (dx + 1) * sizeof (PointInT);
331 ptr -= dx + 1;
332
333 ret_val += D * int (*ptr);
334
335 // next the edges:
336 //+int* ptr_integral;// = static_cast<int*> (integral.data) + x_left + integralcols * y_top + 1;
337 const int* ptr_integral = static_cast<const int*> (&integral_image[0]) + x_left + integralcols * y_top + 1;
338
339 // find a simple path through the different surface corners
340 const int tmp1 = (*ptr_integral);
341 ptr_integral += dx;
342 const int tmp2 = (*ptr_integral);
343 ptr_integral += integralcols;
344 const int tmp3 = (*ptr_integral);
345 ptr_integral++;
346 const int tmp4 = (*ptr_integral);
347 ptr_integral += dy * integralcols;
348 const int tmp5 = (*ptr_integral);
349 ptr_integral--;
350 const int tmp6 = (*ptr_integral);
351 ptr_integral += integralcols;
352 const int tmp7 = (*ptr_integral);
353 ptr_integral -= dx;
354 const int tmp8 = (*ptr_integral);
355 ptr_integral -= integralcols;
356 const int tmp9 = (*ptr_integral);
357 ptr_integral--;
358 const int tmp10 = (*ptr_integral);
359 ptr_integral -= dy * integralcols;
360 const int tmp11 = (*ptr_integral);
361 ptr_integral++;
362 const int tmp12 = (*ptr_integral);
363
364 // assign the weighted surface integrals:
365 const int upper = (tmp3 -tmp2 +tmp1 -tmp12) * r_y_1_i;
366 const int middle = (tmp6 -tmp3 +tmp12 -tmp9) * scaling;
367 const int left = (tmp9 -tmp12 +tmp11 -tmp10) * r_x_1_i;
368 const int right = (tmp5 -tmp4 +tmp3 -tmp6) * r_x1_i;
369 const int bottom = (tmp7 -tmp6 +tmp9 -tmp8) * r_y1_i;
370
371 return (ret_val + upper + middle + left + right + bottom + scaling2 / 2) / scaling2;
372 }
373
374 // now the calculation:
375
376 //const unsigned char* ptr = static_cast<const unsigned char*> (&image[0].r) + x_left + imagecols * y_top;
377 const unsigned char* ptr = static_cast<const unsigned char*>(&image[0]) + x_left + imagecols * y_top;
378
379 // first row:
380 ret_val = A * int (*ptr);
381
382 //+ptr += sizeof (PointInT);
383 ptr++;
384
385 //+const unsigned char* end1 = ptr + (dx * sizeof (PointInT));
386 const unsigned char* end1 = ptr + dx;
387
388 //+for (; ptr < end1; ptr += sizeof (PointInT))
389 for (; ptr < end1; ptr++)
390 ret_val += r_y_1_i * int (*ptr);
391 ret_val += B * int (*ptr);
392
393 // middle ones:
394 //+ptr += (imagecols - dx - 1) * sizeof (PointInT);
395 ptr += imagecols - dx - 1;
396
397 //+const unsigned char* end_j = ptr + (dy * imagecols) * sizeof (PointInT);
398 const unsigned char* end_j = ptr + dy * imagecols;
399
400 //+for (; ptr < end_j; ptr += (imagecols - dx - 1) * sizeof (PointInT))
401 for (; ptr < end_j; ptr += imagecols - dx - 1)
402 {
403 ret_val += r_x_1_i * int (*ptr);
404
405 //+ptr += sizeof (PointInT);
406 ptr++;
407
408 //+const unsigned char* end2 = ptr + (dx * sizeof (PointInT));
409 const unsigned char* end2 = ptr + dx;
410
411 //+for (; ptr < end2; ptr += sizeof (PointInT))
412 for (; ptr < end2; ptr++)
413 ret_val += int (*ptr) * scaling;
414
415 ret_val += r_x1_i * int (*ptr);
416 }
417 // last row:
418 ret_val += D * int (*ptr);
419
420 //+ptr += sizeof (PointInT);
421 ptr++;
422
423 //+const unsigned char* end3 = ptr + (dx * sizeof (PointInT));
424 const unsigned char* end3 = ptr + dx;
425
426 //+for (; ptr<end3; ptr += sizeof (PointInT))
427 for (; ptr<end3; ptr++)
428 ret_val += r_y1_i * int (*ptr);
429
430 ret_val += C * int (*ptr);
431
432 return (ret_val + scaling2 / 2) / scaling2;
433}
434
435
436template <typename PointInT, typename PointOutT, typename KeypointT, typename IntensityT> bool
438 const float min_x, const float min_y,
439 const float max_x, const float max_y, const KeypointT& pt)
440{
441 return ((pt.x < min_x) || (pt.x >= max_x) || (pt.y < min_y) || (pt.y >= max_y));
442}
443
444
445template <typename PointInT, typename PointOutT, typename KeypointT, typename IntensityT> void
447 PointCloudOutT &output)
448{
449 if (!input_cloud_->isOrganized ())
450 {
451 PCL_ERROR ("[pcl::%s::initCompute] %s doesn't support non organized clouds!\n", name_.c_str ());
452 return;
453 }
454
455 // image size
456 const index_t width = static_cast<index_t>(input_cloud_->width);
457 const index_t height = static_cast<index_t>(input_cloud_->height);
458
459 // destination for intensity data; will be forwarded to BRISK
460 std::vector<unsigned char> image_data (width*height);
461
462 for (std::size_t i = 0; i < image_data.size (); ++i)
463 image_data[i] = static_cast<unsigned char> (intensity_ ((*input_cloud_)[i]));
464
465 // Remove keypoints very close to the border
466 auto ksize = keypoints_->size ();
467 std::vector<int> kscales; // remember the scale per keypoint
468 kscales.resize (ksize);
469
470 // initialize constants
471 static const float lb_scalerange = std::log2 (scalerange_);
472
473 typename std::vector<KeypointT, Eigen::aligned_allocator<KeypointT> >::iterator beginning = keypoints_->points.begin ();
474 std::vector<int>::iterator beginningkscales = kscales.begin ();
475
476 static const float basic_size_06 = basic_size_ * 0.6f;
477 unsigned int basicscale = 0;
478
479 if (!scale_invariance_enabled_)
480 basicscale = std::max (static_cast<int> (float (scales_) / lb_scalerange * (std::log2 (1.45f * basic_size_ / (basic_size_06))) + 0.5f), 0);
481
482 for (std::size_t k = 0; k < ksize; k++)
483 {
484 unsigned int scale;
485 if (scale_invariance_enabled_)
486 {
487 scale = std::max (static_cast<int> (float (scales_) / lb_scalerange * (std::log2 ((*keypoints_)[k].size / (basic_size_06))) + 0.5f), 0);
488 // saturate
489 if (scale >= scales_) scale = scales_ - 1;
490 kscales[k] = scale;
491 }
492 else
493 {
494 scale = basicscale;
495 kscales[k] = scale;
496 }
497
498 const int border = size_list_[scale];
499 const int border_x = width - border;
500 const int border_y = height - border;
501
502 if (RoiPredicate (float (border), float (border), float (border_x), float (border_y), (*keypoints_)[k]))
503 {
504 //std::cerr << "remove keypoint" << std::endl;
505 keypoints_->points.erase (beginning + k);
506 kscales.erase (beginningkscales + k);
507 if (k == 0)
508 {
509 beginning = keypoints_->points.begin ();
510 beginningkscales = kscales.begin ();
511 }
512 ksize--;
513 k--;
514 }
515 }
516
517 keypoints_->width = keypoints_->size ();
518 keypoints_->height = 1;
519
520 // first, calculate the integral image over the whole image:
521 // current integral image
522 std::vector<int> integral ((width+1)*(height+1), 0); // the integral image
523
524 for (index_t row_index = 1; row_index < height; ++row_index)
525 {
526 for (index_t col_index = 1; col_index < width; ++col_index)
527 {
528 const std::size_t index = row_index*width+col_index;
529 const std::size_t index2 = (row_index)*(width+1)+(col_index);
530
531 integral[index2] = static_cast<int> (image_data[index])
532 - integral[index2-1-(width+1)]
533 + integral[index2-(width+1)]
534 + integral[index2-1];
535 }
536 }
537
538 int* values = new int[points_]; // for temporary use
539
540 // resize the descriptors:
541 //output = zeros (ksize, strings_);
542
543 // now do the extraction for all keypoints:
544
545 // temporary variables containing gray values at sample points:
546 int t1;
547 int t2;
548
549 // the feature orientation
550 int direction0;
551 int direction1;
552
553 output.resize (ksize);
554 //output.width = ksize;
555 //output.height = 1;
556 for (std::size_t k = 0; k < ksize; k++)
557 {
558 unsigned char* ptr = &output[k].descriptor[0];
559
560 int theta;
561 KeypointT &kp = (*keypoints_)[k];
562 const int& scale = kscales[k];
563 int shifter = 0;
564 int* pvalues = values;
565 const float& x = float (kp.x);
566 const float& y = float (kp.y);
567 if (true) // kp.angle==-1
568 {
569 if (!rotation_invariance_enabled_)
570 // don't compute the gradient direction, just assign a rotation of 0 degree
571 theta = 0;
572 else
573 {
574 // get the gray values in the unrotated pattern
575 for (unsigned int i = 0; i < points_; i++)
576 *(pvalues++) = smoothedIntensity (image_data, width, height, integral, x, y, scale, 0, i);
577
578 direction0 = 0;
579 direction1 = 0;
580 // now iterate through the long pairings
581 const BriskLongPair* max = long_pairs_ + no_long_pairs_;
582
583 for (BriskLongPair* iter = long_pairs_; iter < max; ++iter)
584 {
585 t1 = *(values + iter->i);
586 t2 = *(values + iter->j);
587 const int delta_t = (t1 - t2);
588
589 // update the direction:
590 const int tmp0 = delta_t * (iter->weighted_dx) / 1024;
591 const int tmp1 = delta_t * (iter->weighted_dy) / 1024;
592 direction0 += tmp0;
593 direction1 += tmp1;
594 }
595 kp.angle = std::atan2 (float (direction1), float (direction0)) / float (M_PI) * 180.0f;
596 theta = static_cast<int> ((float (n_rot_) * kp.angle) / (360.0f) + 0.5f);
597 if (theta < 0)
598 theta += n_rot_;
599 if (theta >= int (n_rot_))
600 theta -= n_rot_;
601 }
602 }
603 else
604 {
605 // figure out the direction:
606 //int theta=rotationInvariance*round((_n_rot*std::atan2(direction.at<int>(0,0),direction.at<int>(1,0)))/(2*M_PI));
607 if (!rotation_invariance_enabled_)
608 theta = 0;
609 else
610 {
611 theta = static_cast<int> (n_rot_ * (kp.angle / (360.0)) + 0.5);
612 if (theta < 0)
613 theta += n_rot_;
614 if (theta >= int (n_rot_))
615 theta -= n_rot_;
616 }
617 }
618
619 // now also extract the stuff for the actual direction:
620 // let us compute the smoothed values
621 shifter = 0;
622
623 //unsigned int mean=0;
624 pvalues = values;
625 // get the gray values in the rotated pattern
626 for (unsigned int i = 0; i < points_; i++)
627 *(pvalues++) = smoothedIntensity (image_data, width, height, integral, x, y, scale, theta, i);
628
629#ifdef __GNUC__
630 using UINT32_ALIAS = std::uint32_t;
631#endif
632#ifdef _MSC_VER
633 // Todo: find the equivalent to may_alias
634 #define UCHAR_ALIAS std::uint32_t //__declspec(noalias)
635 #define UINT32_ALIAS std::uint32_t //__declspec(noalias)
636#endif
637
638 // now iterate through all the pairings
639 UINT32_ALIAS* ptr2 = reinterpret_cast<UINT32_ALIAS*> (ptr);
640 const BriskShortPair* max = short_pairs_ + no_short_pairs_;
641
642 for (BriskShortPair* iter = short_pairs_; iter < max; ++iter)
643 {
644 t1 = *(values + iter->i);
645 t2 = *(values + iter->j);
646
647 if (t1 > t2)
648 *ptr2 |= ((1) << shifter);
649
650 // else already initialized with zero
651 // take care of the iterators:
652 ++shifter;
653
654 if (shifter == 32)
655 {
656 shifter = 0;
657 ++ptr2;
658 }
659 }
660
661 //ptr += strings_;
662
663 //// Account for the scale + orientation;
664 //ptr += sizeof (output[0].scale);
665 //ptr += sizeof (output[0].orientation);
666 }
667
668 // we do not change the denseness
669 output.width = output.size ();
670 output.height = 1;
671 output.is_dense = true;
672
673 // clean-up
674 delete [] values;
675}
676
677} // namespace pcl
678
679#endif //#ifndef PCL_FEATURES_IMPL_BRISK_2D_HPP_
680
Implementation of the BRISK-descriptor, based on the original code and paper reference by.
Definition brisk_2d.h:67
BRISK2DEstimation()
Constructor.
Definition brisk_2d.hpp:49
virtual ~BRISK2DEstimation()
Destructor.
Definition brisk_2d.hpp:90
void generateKernel(std::vector< float > &radius_list, std::vector< int > &number_list, float d_max=5.85f, float d_min=8.2f, std::vector< int > index_change=std::vector< int >())
Call this to generate the kernel: circle of radius r (pixels), with n points; short pairings with dMa...
Definition brisk_2d.hpp:101
void compute(PointCloudOutT &output)
Computes the descriptors for the previously specified points and input data.
Definition brisk_2d.hpp:446
int smoothedIntensity(const std::vector< unsigned char > &image, int image_width, int image_height, const std::vector< int > &integral_image, const float key_x, const float key_y, const unsigned int scale, const unsigned int rot, const unsigned int point) const
Compute the smoothed intensity for a given x/y position in the image.
Definition brisk_2d.hpp:219
void resize(std::size_t count)
Resizes the container to contain count elements.
std::size_t size() const
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
std::uint32_t width
The point cloud width (if organized as an image-structure).
std::uint32_t height
The point cloud height (if organized as an image-structure).
@ B
Definition norms.h:54
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.
Definition types.h:112
#define M_PI
Definition pcl_macros.h:201