41 #ifndef PCL_FEATURES_IMPL_BRISK_2D_HPP_
42 #define PCL_FEATURES_IMPL_BRISK_2D_HPP_
48 template <
typename Po
intInT,
typename Po
intOutT,
typename Keypo
intT,
typename IntensityT>
51 input_cloud_ (), keypoints_ (), pattern_points_ (),
52 short_pairs_ (), long_pairs_ ()
54 , name_ (
"BRISK2Destimation")
58 std::vector<float> r_list;
59 std::vector<int> n_list;
64 const float f = 0.85f * pattern_scale_;
70 r_list[4] = f * 10.8f;
78 generateKernel (r_list, n_list, 5.85f * pattern_scale_, 8.2f * pattern_scale_);
82 template <
typename Po
intInT,
typename Po
intOutT,
typename Keypo
intT,
typename IntensityT>
85 delete [] pattern_points_;
86 delete [] short_pairs_;
87 delete [] long_pairs_;
88 delete [] scale_list_;
93 template <
typename Po
intInT,
typename Po
intOutT,
typename Keypo
intT,
typename IntensityT>
void
95 std::vector<float> &radius_list,
96 std::vector<int> &number_list,
float d_max,
float d_min,
97 std::vector<int> index_change)
103 const auto rings = radius_list.size ();
104 assert (radius_list.size () != 0 && radius_list.size () == number_list.size ());
106 for (
const auto number: number_list)
110 pattern_points_ =
new BriskPatternPoint[
static_cast<std::size_t
>(points_)*
static_cast<std::size_t
>(scales_)*
static_cast<std::size_t
>(n_rot_)];
111 BriskPatternPoint* pattern_iterator = pattern_points_;
114 static const float lb_scale = std::log (scalerange_) / std::log (2.0);
115 static const float lb_scale_step = lb_scale / (
static_cast<float>(scales_));
117 scale_list_ =
new float[scales_];
118 size_list_ =
new unsigned int[scales_];
120 constexpr
float sigma_scale = 1.3f;
122 for (
unsigned int scale = 0; scale < scales_; ++scale)
124 scale_list_[scale] =
static_cast<float> (pow ((2.0),
static_cast<double> (
static_cast<float>(scale) * lb_scale_step)));
125 size_list_[scale] = 0;
128 for (std::size_t rot = 0; rot < n_rot_; ++rot)
131 double theta =
static_cast<double>(rot) * 2 *
M_PI /
static_cast<double>(n_rot_);
132 for (
int ring = 0; ring < static_cast<int>(rings); ++ring)
134 for (
int num = 0; num < number_list[ring]; ++num)
137 double alpha =
static_cast<double>(num) * 2 *
M_PI /
static_cast<double>(number_list[ring]);
140 pattern_iterator->x = scale_list_[scale] * radius_list[ring] *
static_cast<float> (std::cos (alpha + theta));
141 pattern_iterator->y = scale_list_[scale] * radius_list[ring] *
static_cast<float> (sin (alpha + theta));
144 pattern_iterator->sigma = sigma_scale * scale_list_[scale] * 0.5f;
146 pattern_iterator->sigma =
static_cast<float> (sigma_scale * scale_list_[scale] * (
static_cast<double>(radius_list[ring])) * sin (
M_PI /
static_cast<double>(number_list[ring])));
149 const auto size =
static_cast<unsigned int> (std::ceil (((scale_list_[scale] * radius_list[ring]) + pattern_iterator->sigma)) + 1);
151 if (size_list_[scale] < size)
152 size_list_[scale] = size;
162 short_pairs_ =
new BriskShortPair[points_ * (points_ - 1) / 2];
163 long_pairs_ =
new BriskLongPair[points_ * (points_ - 1) / 2];
168 if (index_change.empty ())
170 index_change.resize (points_ * (points_ - 1) / 2);
172 std::iota(index_change.begin (), index_change.end (), 0);
174 const float d_min_sq = d_min_ * d_min_;
175 const float d_max_sq = d_max_ * d_max_;
176 for (
unsigned int i = 1; i < points_; i++)
178 for (
unsigned int j = 0; j < i; j++)
181 const float dx = pattern_points_[j].x - pattern_points_[i].x;
182 const float dy = pattern_points_[j].y - pattern_points_[i].y;
183 const float norm_sq = (dx*dx+dy*dy);
184 if (norm_sq > d_min_sq)
187 BriskLongPair& longPair = long_pairs_[no_long_pairs_];
188 longPair.weighted_dx =
static_cast<int>((dx / (norm_sq)) * 2048.0 + 0.5);
189 longPair.weighted_dy =
static_cast<int>((dy / (norm_sq)) * 2048.0 + 0.5);
194 else if (norm_sq < d_max_sq)
197 assert (no_short_pairs_ < index_change.size ());
198 BriskShortPair& shortPair = short_pairs_[index_change[no_short_pairs_]];
207 strings_ =
static_cast<int>(std::ceil ((
static_cast<float>(no_short_pairs_)) / 128.0)) * 4 * 4;
211 template <
typename Po
intInT,
typename Po
intOutT,
typename Keypo
intT,
typename IntensityT>
inline int
213 const std::vector<unsigned char> &image,
214 int image_width,
int,
216 const std::vector<int> &integral_image,
217 const float key_x,
const float key_y,
const unsigned int scale,
218 const unsigned int rot,
const unsigned int point)
const
221 const BriskPatternPoint& brisk_point = pattern_points_[scale * n_rot_*points_ + rot * points_ + point];
222 const float xf = brisk_point.x + key_x;
223 const float yf = brisk_point.y + key_y;
224 const int x =
static_cast<int>(xf);
225 const int y =
static_cast<int>(yf);
226 const std::ptrdiff_t imagecols = image_width;
229 const float sigma_half = brisk_point.sigma;
230 const float area = 4.0f * sigma_half * sigma_half;
236 if (sigma_half < 0.5)
239 const int r_x =
static_cast<int> ((xf -
static_cast<float>(x)) * 1024);
240 const int r_y =
static_cast<int> ((yf -
static_cast<float>(y)) * 1024);
241 const int r_x_1 = (1024 - r_x);
242 const int r_y_1 = (1024 - r_y);
245 const unsigned char* ptr =
static_cast<const unsigned char*
>(image.data()) + x + y * imagecols;
248 ret_val = (r_x_1 * r_y_1 *
static_cast<int>(*ptr));
253 ret_val += (r_x * r_y_1 *
static_cast<int>(*ptr));
258 ret_val += (r_x * r_y *
static_cast<int>(*ptr));
263 ret_val += (r_x_1 * r_y *
static_cast<int>(*ptr));
264 return (ret_val + 512) / 1024;
270 const int scaling =
static_cast<int> (4194304.0f / area);
271 const int scaling2 =
static_cast<int> (
static_cast<float>(scaling) * area / 1024.0f);
274 const std::ptrdiff_t integralcols = image_width + 1;
277 const float x_1 = xf - sigma_half;
278 const float x1 = xf + sigma_half;
279 const float y_1 = yf - sigma_half;
280 const float y1 = yf + sigma_half;
282 const int x_left =
static_cast<int>(x_1 + 0.5);
283 const int y_top =
static_cast<int>(y_1 + 0.5);
284 const int x_right =
static_cast<int>(x1 + 0.5);
285 const int y_bottom =
static_cast<int>(y1 + 0.5);
288 const float r_x_1 =
static_cast<float>(x_left) - x_1 + 0.5f;
289 const float r_y_1 =
static_cast<float>(y_top) - y_1 + 0.5f;
290 const float r_x1 = x1 -
static_cast<float>(x_right) + 0.5f;
291 const float r_y1 = y1 -
static_cast<float>(y_bottom) + 0.5f;
292 const int dx = x_right - x_left - 1;
293 const int dy = y_bottom - y_top - 1;
294 const int A =
static_cast<int> ((r_x_1 * r_y_1) *
static_cast<float>(scaling));
295 const int B =
static_cast<int> ((r_x1 * r_y_1) *
static_cast<float>(scaling));
296 const int C =
static_cast<int> ((r_x1 * r_y1) *
static_cast<float>(scaling));
297 const int D =
static_cast<int> ((r_x_1 * r_y1) *
static_cast<float>(scaling));
298 const int r_x_1_i =
static_cast<int> (r_x_1 *
static_cast<float>(scaling));
299 const int r_y_1_i =
static_cast<int> (r_y_1 *
static_cast<float>(scaling));
300 const int r_x1_i =
static_cast<int> (r_x1 *
static_cast<float>(scaling));
301 const int r_y1_i =
static_cast<int> (r_y1 *
static_cast<float>(scaling));
308 const unsigned char* ptr =
static_cast<const unsigned char*
>(image.data()) + x_left + imagecols * y_top;
311 ret_val = A *
static_cast<int>(*ptr);
316 ret_val +=
B *
static_cast<int>(*ptr);
319 ptr += dy * imagecols + 1;
321 ret_val += C *
static_cast<int>(*ptr);
326 ret_val += D *
static_cast<int>(*ptr);
330 const int* ptr_integral =
static_cast<const int*
> (integral_image.data()) + x_left + integralcols * y_top + 1;
333 const int tmp1 = (*ptr_integral);
335 const int tmp2 = (*ptr_integral);
336 ptr_integral += integralcols;
337 const int tmp3 = (*ptr_integral);
339 const int tmp4 = (*ptr_integral);
340 ptr_integral += dy * integralcols;
341 const int tmp5 = (*ptr_integral);
343 const int tmp6 = (*ptr_integral);
344 ptr_integral += integralcols;
345 const int tmp7 = (*ptr_integral);
347 const int tmp8 = (*ptr_integral);
348 ptr_integral -= integralcols;
349 const int tmp9 = (*ptr_integral);
351 const int tmp10 = (*ptr_integral);
352 ptr_integral -= dy * integralcols;
353 const int tmp11 = (*ptr_integral);
355 const int tmp12 = (*ptr_integral);
358 const int upper = (tmp3 -tmp2 +tmp1 -tmp12) * r_y_1_i;
359 const int middle = (tmp6 -tmp3 +tmp12 -tmp9) * scaling;
360 const int left = (tmp9 -tmp12 +tmp11 -tmp10) * r_x_1_i;
361 const int right = (tmp5 -tmp4 +tmp3 -tmp6) * r_x1_i;
362 const int bottom = (tmp7 -tmp6 +tmp9 -tmp8) * r_y1_i;
364 return (ret_val + upper + middle + left + right + bottom + scaling2 / 2) / scaling2;
370 const unsigned char* ptr =
static_cast<const unsigned char*
>(image.data()) + x_left + imagecols * y_top;
373 ret_val = A *
static_cast<int>(*ptr);
379 const unsigned char* end1 = ptr + dx;
382 for (; ptr < end1; ptr++)
383 ret_val += r_y_1_i *
static_cast<int>(*ptr);
384 ret_val +=
B *
static_cast<int>(*ptr);
388 ptr += imagecols - dx - 1;
391 const unsigned char* end_j = ptr + dy * imagecols;
394 for (; ptr < end_j; ptr += imagecols - dx - 1)
396 ret_val += r_x_1_i *
static_cast<int>(*ptr);
402 const unsigned char* end2 = ptr + dx;
405 for (; ptr < end2; ptr++)
406 ret_val +=
static_cast<int>(*ptr) * scaling;
408 ret_val += r_x1_i *
static_cast<int>(*ptr);
411 ret_val += D *
static_cast<int>(*ptr);
417 const unsigned char* end3 = ptr + dx;
420 for (; ptr<end3; ptr++)
421 ret_val += r_y1_i *
static_cast<int>(*ptr);
423 ret_val += C *
static_cast<int>(*ptr);
425 return (ret_val + scaling2 / 2) / scaling2;
429 template <
typename Po
intInT,
typename Po
intOutT,
typename Keypo
intT,
typename IntensityT>
bool
431 const float min_x,
const float min_y,
432 const float max_x,
const float max_y,
const KeypointT& pt)
434 return ((pt.x < min_x) || (pt.x >= max_x) || (pt.y < min_y) || (pt.y >= max_y));
438 template <
typename Po
intInT,
typename Po
intOutT,
typename Keypo
intT,
typename IntensityT>
void
442 if (!input_cloud_->isOrganized ())
444 PCL_ERROR (
"[pcl::%s::initCompute] %s doesn't support non organized clouds!\n", name_.c_str ());
449 const auto width =
static_cast<index_t>(input_cloud_->width);
450 const auto height =
static_cast<index_t>(input_cloud_->height);
453 std::vector<unsigned char> image_data (
static_cast<std::size_t
>(width)*
static_cast<std::size_t
>(height));
455 for (std::size_t i = 0; i < image_data.size (); ++i)
456 image_data[i] =
static_cast<unsigned char> (intensity_ ((*input_cloud_)[i]));
459 auto ksize = keypoints_->size ();
460 std::vector<int> kscales;
461 kscales.resize (ksize);
464 static const float lb_scalerange = std::log2 (scalerange_);
466 auto beginning = keypoints_->points.begin ();
467 auto beginningkscales = kscales.begin ();
469 static const float basic_size_06 = basic_size_ * 0.6f;
470 unsigned int basicscale = 0;
472 if (!scale_invariance_enabled_)
473 basicscale = std::max (
static_cast<int> (
static_cast<float>(scales_) / lb_scalerange * (std::log2 (1.45f * basic_size_ / (basic_size_06))) + 0.5f), 0);
475 for (std::size_t k = 0; k < ksize; k++)
478 if (scale_invariance_enabled_)
480 scale = std::max (
static_cast<int> (
static_cast<float>(scales_) / lb_scalerange * (std::log2 ((*keypoints_)[k].size / (basic_size_06))) + 0.5f), 0);
482 if (scale >= scales_) scale = scales_ - 1;
491 const int border = size_list_[scale];
492 const int border_x = width - border;
493 const int border_y = height - border;
495 if (RoiPredicate (
static_cast<float>(border),
static_cast<float>(border),
static_cast<float>(border_x),
static_cast<float>(border_y), (*keypoints_)[k]))
498 keypoints_->points.erase (beginning + k);
499 kscales.erase (beginningkscales + k);
502 beginning = keypoints_->points.begin ();
503 beginningkscales = kscales.begin ();
510 keypoints_->width = keypoints_->size ();
511 keypoints_->height = 1;
515 std::vector<int> integral (
static_cast<std::size_t
>(width+1)*
static_cast<std::size_t
>(height+1), 0);
517 for (
index_t row_index = 1; row_index < height; ++row_index)
519 for (
index_t col_index = 1; col_index < width; ++col_index)
521 const std::size_t index = row_index*width+col_index;
522 const std::size_t index2 = (row_index)*(width+1)+(col_index);
524 integral[index2] =
static_cast<int> (image_data[index])
525 - integral[index2-1-(width+1)]
526 + integral[index2-(width+1)]
527 + integral[index2-1];
531 int* values =
new int[points_];
549 for (std::size_t k = 0; k < ksize; k++)
551 unsigned char* ptr = &output[k].descriptor[0];
554 KeypointT &kp = (*keypoints_)[k];
555 const int& scale = kscales[k];
557 int* pvalues = values;
558 const float& x = (kp.x);
559 const float& y = (kp.y);
563 if (!rotation_invariance_enabled_)
569 for (
unsigned int i = 0; i < points_; i++)
570 *(pvalues++) = smoothedIntensity (image_data, width, height, integral, x, y, scale, 0, i);
575 const BriskLongPair* max = long_pairs_ + no_long_pairs_;
577 for (BriskLongPair* iter = long_pairs_; iter < max; ++iter)
579 t1 = *(values + iter->i);
580 t2 = *(values + iter->j);
581 const int delta_t = (t1 - t2);
584 const int tmp0 = delta_t * (iter->weighted_dx) / 1024;
585 const int tmp1 = delta_t * (iter->weighted_dy) / 1024;
589 kp.angle = std::atan2 (
static_cast<float>(direction1),
static_cast<float>(direction0)) /
static_cast<float>(
M_PI) * 180.0f;
590 theta =
static_cast<int> ((
static_cast<float>(n_rot_) * kp.angle) / (360.0f) + 0.5f);
593 if (theta >=
static_cast<int>(n_rot_))
601 if (!rotation_invariance_enabled_)
605 theta =
static_cast<int> (n_rot_ * (kp.angle / (360.0)) + 0.5);
608 if (theta >=
static_cast<int>(n_rot_))
620 for (
unsigned int i = 0; i < points_; i++)
621 *(pvalues++) = smoothedIntensity (image_data, width, height, integral, x, y, scale, theta, i);
624 using UINT32_ALIAS = std::uint32_t;
628 #define UCHAR_ALIAS std::uint32_t
629 #define UINT32_ALIAS std::uint32_t
633 auto* ptr2 =
reinterpret_cast<UINT32_ALIAS*
> (ptr);
634 const BriskShortPair* max = short_pairs_ + no_short_pairs_;
636 for (BriskShortPair* iter = short_pairs_; iter < max; ++iter)
638 t1 = *(values + iter->i);
639 t2 = *(values + iter->j);
642 *ptr2 |= ((1) << shifter);
Implementation of the BRISK-descriptor, based on the original code and paper reference by.
BRISK2DEstimation()
Constructor.
virtual ~BRISK2DEstimation()
Destructor.
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...
void compute(PointCloudOutT &output)
Computes the descriptors for the previously specified points and input data.
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.
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
void resize(std::size_t count)
Resizes the container to contain count elements.
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).
detail::int_type_t< detail::index_type_size, detail::index_type_signed > index_t
Type used for an index in PCL.