39 #include <pcl/common/eigen.h>
40 #include <pcl/features/integral_image_normal.h>
45 template <
typename Po
intInT,
typename Po
intOutT>
51 delete[] distance_map_;
55 template <
typename Po
intInT,
typename Po
intOutT>
void
58 if (border_policy_ != BORDER_POLICY_IGNORE &&
59 border_policy_ != BORDER_POLICY_MIRROR)
61 "[pcl::IntegralImageNormalEstimation::initData] unknown border policy.");
63 if (normal_estimation_method_ != COVARIANCE_MATRIX &&
64 normal_estimation_method_ != AVERAGE_3D_GRADIENT &&
65 normal_estimation_method_ != AVERAGE_DEPTH_CHANGE &&
66 normal_estimation_method_ != SIMPLE_3D_GRADIENT)
68 "[pcl::IntegralImageNormalEstimation::initData] unknown normal estimation method.");
74 delete[] distance_map_;
77 depth_data_ =
nullptr;
78 distance_map_ =
nullptr;
80 if (normal_estimation_method_ == COVARIANCE_MATRIX)
81 initCovarianceMatrixMethod ();
82 else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
83 initAverage3DGradientMethod ();
84 else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
85 initAverageDepthChangeMethod ();
86 else if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
87 initSimple3DGradientMethod ();
92 template <
typename Po
intInT,
typename Po
intOutT>
void
96 rect_width_2_ = width/2;
97 rect_width_4_ = width/4;
98 rect_height_ = height;
99 rect_height_2_ = height/2;
100 rect_height_4_ = height/4;
104 template <
typename Po
intInT,
typename Po
intOutT>
void
108 int element_stride =
sizeof (PointInT) /
sizeof (
float);
110 int row_stride = element_stride * input_->width;
112 const float *data_ =
reinterpret_cast<const float*
> (&(*input_)[0]);
114 integral_image_XYZ_.setSecondOrderComputation (
false);
115 integral_image_XYZ_.setInput (data_, input_->width, input_->height, element_stride, row_stride);
117 init_simple_3d_gradient_ =
true;
118 init_covariance_matrix_ = init_average_3d_gradient_ = init_depth_change_ =
false;
122 template <
typename Po
intInT,
typename Po
intOutT>
void
126 int element_stride =
sizeof (PointInT) /
sizeof (
float);
128 int row_stride = element_stride * input_->width;
130 const float *data_ =
reinterpret_cast<const float*
> (&(*input_)[0]);
132 integral_image_XYZ_.setSecondOrderComputation (
true);
133 integral_image_XYZ_.setInput (data_, input_->width, input_->height, element_stride, row_stride);
135 init_covariance_matrix_ =
true;
136 init_average_3d_gradient_ = init_depth_change_ = init_simple_3d_gradient_ =
false;
140 template <
typename Po
intInT,
typename Po
intOutT>
void
145 std::size_t data_size = (input_->size () << 2);
146 diff_x_ =
new float[data_size]{};
147 diff_y_ =
new float[data_size]{};
152 const PointInT* point_up = &(input_->points [1]);
153 const PointInT* point_dn = point_up + (input_->width << 1);
154 const PointInT* point_lf = &(input_->points [input_->width]);
155 const PointInT* point_rg = point_lf + 2;
156 float* diff_x_ptr = diff_x_ + ((input_->width + 1) << 2);
157 float* diff_y_ptr = diff_y_ + ((input_->width + 1) << 2);
158 unsigned diff_skip = 8;
160 for (std::size_t ri = 1; ri < input_->height - 1; ++ri
161 , point_up += input_->width
162 , point_dn += input_->width
163 , point_lf += input_->width
164 , point_rg += input_->width
165 , diff_x_ptr += diff_skip
166 , diff_y_ptr += diff_skip)
168 for (std::size_t ci = 0; ci < input_->width - 2; ++ci, diff_x_ptr += 4, diff_y_ptr += 4)
170 diff_x_ptr[0] = point_rg[ci].x - point_lf[ci].x;
171 diff_x_ptr[1] = point_rg[ci].y - point_lf[ci].y;
172 diff_x_ptr[2] = point_rg[ci].z - point_lf[ci].z;
174 diff_y_ptr[0] = point_dn[ci].x - point_up[ci].x;
175 diff_y_ptr[1] = point_dn[ci].y - point_up[ci].y;
176 diff_y_ptr[2] = point_dn[ci].z - point_up[ci].z;
181 integral_image_DX_.setInput (diff_x_, input_->width, input_->height, 4, input_->width << 2);
182 integral_image_DY_.setInput (diff_y_, input_->width, input_->height, 4, input_->width << 2);
183 init_covariance_matrix_ = init_depth_change_ = init_simple_3d_gradient_ =
false;
184 init_average_3d_gradient_ =
true;
188 template <
typename Po
intInT,
typename Po
intOutT>
void
192 int element_stride =
sizeof (PointInT) /
sizeof (
float);
194 int row_stride = element_stride * input_->width;
196 const float *data_ =
reinterpret_cast<const float*
> (&(*input_)[0]);
199 integral_image_depth_.setInput (&(data_[2]), input_->width, input_->height, element_stride, row_stride);
200 init_depth_change_ =
true;
201 init_covariance_matrix_ = init_average_3d_gradient_ = init_simple_3d_gradient_ =
false;
205 template <
typename Po
intInT,
typename Po
intOutT>
void
207 const int pos_x,
const int pos_y,
const unsigned point_index, PointOutT &normal)
209 float bad_point = std::numeric_limits<float>::quiet_NaN ();
211 if (normal_estimation_method_ == COVARIANCE_MATRIX)
213 if (!init_covariance_matrix_)
214 initCovarianceMatrixMethod ();
216 unsigned count = integral_image_XYZ_.getFiniteElementsCount (pos_x - (rect_width_2_), pos_y - (rect_height_2_), rect_width_, rect_height_);
221 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point;
225 EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
226 Eigen::Vector3f center;
228 center = integral_image_XYZ_.
getFirstOrderSum(pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_).template cast<float> ();
229 so_elements = integral_image_XYZ_.
getSecondOrderSum(pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
231 covariance_matrix.coeffRef (0) =
static_cast<float> (so_elements [0]);
232 covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) =
static_cast<float> (so_elements [1]);
233 covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) =
static_cast<float> (so_elements [2]);
234 covariance_matrix.coeffRef (4) =
static_cast<float> (so_elements [3]);
235 covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) =
static_cast<float> (so_elements [4]);
236 covariance_matrix.coeffRef (8) =
static_cast<float> (so_elements [5]);
237 covariance_matrix -= (center * center.transpose ()) /
static_cast<float> (count);
239 Eigen::Vector3f eigen_vector;
240 pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
242 normal.getNormalVector3fMap () = eigen_vector;
245 if (eigen_value > 0.0)
246 normal.curvature = std::abs (eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8)));
248 normal.curvature = 0;
252 if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
254 if (!init_average_3d_gradient_)
255 initAverage3DGradientMethod ();
257 unsigned count_x = integral_image_DX_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
258 unsigned count_y = integral_image_DY_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
259 if (count_x == 0 || count_y == 0)
261 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point;
264 Eigen::Vector3d gradient_x = integral_image_DX_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
265 Eigen::Vector3d gradient_y = integral_image_DY_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
267 Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
268 double normal_length = normal_vector.squaredNorm ();
269 if (normal_length == 0.0f)
271 normal.getNormalVector3fMap ().setConstant (bad_point);
272 normal.curvature = bad_point;
276 normal_vector /= sqrt (normal_length);
278 float nx =
static_cast<float> (normal_vector [0]);
279 float ny =
static_cast<float> (normal_vector [1]);
280 float nz =
static_cast<float> (normal_vector [2]);
284 normal.normal_x = nx;
285 normal.normal_y = ny;
286 normal.normal_z = nz;
287 normal.curvature = bad_point;
290 if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
292 if (!init_depth_change_)
293 initAverageDepthChangeMethod ();
296 unsigned count_L_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_4_, rect_width_2_, rect_height_2_);
297 unsigned count_R_z = integral_image_depth_.getFiniteElementsCount (pos_x + 1 , pos_y - rect_height_4_, rect_width_2_, rect_height_2_);
298 unsigned count_U_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_4_, pos_y - rect_height_2_, rect_width_2_, rect_height_2_);
299 unsigned count_D_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_4_, pos_y + 1 , rect_width_2_, rect_height_2_);
301 if (count_L_z == 0 || count_R_z == 0 || count_U_z == 0 || count_D_z == 0)
303 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point;
307 float mean_L_z =
static_cast<float> (integral_image_depth_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_4_, rect_width_2_, rect_height_2_) / count_L_z);
308 float mean_R_z =
static_cast<float> (integral_image_depth_.getFirstOrderSum (pos_x + 1 , pos_y - rect_height_4_, rect_width_2_, rect_height_2_) / count_R_z);
309 float mean_U_z =
static_cast<float> (integral_image_depth_.getFirstOrderSum (pos_x - rect_width_4_, pos_y - rect_height_2_, rect_width_2_, rect_height_2_) / count_U_z);
310 float mean_D_z =
static_cast<float> (integral_image_depth_.getFirstOrderSum (pos_x - rect_width_4_, pos_y + 1 , rect_width_2_, rect_height_2_) / count_D_z);
312 PointInT pointL = (*input_)[point_index - rect_width_4_ - 1];
313 PointInT pointR = (*input_)[point_index + rect_width_4_ + 1];
314 PointInT pointU = (*input_)[point_index - rect_height_4_ * input_->width - 1];
315 PointInT pointD = (*input_)[point_index + rect_height_4_ * input_->width + 1];
317 const float mean_x_z = mean_R_z - mean_L_z;
318 const float mean_y_z = mean_D_z - mean_U_z;
320 const float mean_x_x = pointR.x - pointL.x;
321 const float mean_x_y = pointR.y - pointL.y;
322 const float mean_y_x = pointD.x - pointU.x;
323 const float mean_y_y = pointD.y - pointU.y;
325 float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y;
326 float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z;
327 float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x;
329 const float normal_length = (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
331 if (normal_length == 0.0f)
333 normal.getNormalVector3fMap ().setConstant (bad_point);
334 normal.curvature = bad_point;
340 const float scale = 1.0f / std::sqrt (normal_length);
342 normal.normal_x = normal_x * scale;
343 normal.normal_y = normal_y * scale;
344 normal.normal_z = normal_z * scale;
345 normal.curvature = bad_point;
349 if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
351 if (!init_simple_3d_gradient_)
352 initSimple3DGradientMethod ();
355 Eigen::Vector3d gradient_x = integral_image_XYZ_.getFirstOrderSum (pos_x + rect_width_2_, pos_y - rect_height_2_, 1, rect_height_) -
356 integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, 1, rect_height_);
358 Eigen::Vector3d gradient_y = integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y + rect_height_2_, rect_width_, 1) -
359 integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, 1);
360 Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
361 double normal_length = normal_vector.squaredNorm ();
362 if (normal_length == 0.0f)
364 normal.getNormalVector3fMap ().setConstant (bad_point);
365 normal.curvature = bad_point;
369 normal_vector /= sqrt (normal_length);
371 float nx =
static_cast<float> (normal_vector [0]);
372 float ny =
static_cast<float> (normal_vector [1]);
373 float nz =
static_cast<float> (normal_vector [2]);
377 normal.normal_x = nx;
378 normal.normal_y = ny;
379 normal.normal_z = nz;
380 normal.curvature = bad_point;
384 normal.getNormalVector3fMap ().setConstant (bad_point);
385 normal.curvature = bad_point;
390 template <
typename T>
392 sumArea (
int start_x,
int start_y,
int end_x,
int end_y,
const int width,
const int height,
393 const std::function<T(
unsigned,
unsigned,
unsigned,
unsigned)> &f,
400 result += f (0, 0, end_x, end_y);
401 result += f (0, 0, -start_x, -start_y);
402 result += f (0, 0, -start_x, end_y);
403 result += f (0, 0, end_x, -start_y);
405 else if (end_y >= height)
407 result += f (0, start_y, end_x, height-1);
408 result += f (0, start_y, -start_x, height-1);
409 result += f (0, height-(end_y-(height-1)), end_x, height-1);
410 result += f (0, height-(end_y-(height-1)), -start_x, height-1);
414 result += f (0, start_y, end_x, end_y);
415 result += f (0, start_y, -start_x, end_y);
418 else if (start_y < 0)
422 result += f (start_x, 0, width-1, end_y);
423 result += f (start_x, 0, width-1, -start_y);
424 result += f (width-(end_x-(width-1)), 0, width-1, end_y);
425 result += f (width-(end_x-(width-1)), 0, width-1, -start_y);
429 result += f (start_x, 0, end_x, end_y);
430 result += f (start_x, 0, end_x, -start_y);
433 else if (end_x >= width)
437 result += f (start_x, start_y, width-1, height-1);
438 result += f (start_x, height-(end_y-(height-1)), width-1, height-1);
439 result += f (width-(end_x-(width-1)), start_y, width-1, height-1);
440 result += f (width-(end_x-(width-1)), height-(end_y-(height-1)), width-1, height-1);
444 result += f (start_x, start_y, width-1, end_y);
445 result += f (width-(end_x-(width-1)), start_y, width-1, end_y);
448 else if (end_y >= height)
450 result += f (start_x, start_y, end_x, height-1);
451 result += f (start_x, height-(end_y-(height-1)), end_x, height-1);
455 result += f (start_x, start_y, end_x, end_y);
460 template <
typename Po
intInT,
typename Po
intOutT>
void
462 const int pos_x,
const int pos_y,
const unsigned point_index, PointOutT &normal)
464 float bad_point = std::numeric_limits<float>::quiet_NaN ();
466 const int width = input_->width;
467 const int height = input_->height;
470 if (normal_estimation_method_ == COVARIANCE_MATRIX)
472 if (!init_covariance_matrix_)
473 initCovarianceMatrixMethod ();
475 const int start_x = pos_x - rect_width_2_;
476 const int start_y = pos_y - rect_height_2_;
477 const int end_x = start_x + rect_width_;
478 const int end_y = start_y + rect_height_;
481 auto cb_xyz_fecse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_XYZ_.getFiniteElementsCountSE (p1, p2, p3, p4); };
482 sumArea<unsigned> (start_x, start_y, end_x, end_y, width, height, cb_xyz_fecse, count);
487 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point;
491 EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
492 Eigen::Vector3f center;
509 auto cb_xyz_fosse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_XYZ_.
getFirstOrderSumSE (p1, p2, p3, p4); };
510 sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, cb_xyz_fosse, tmp_center);
511 auto cb_xyz_sosse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_XYZ_.getSecondOrderSumSE (p1, p2, p3, p4); };
512 sumArea<typename IntegralImage2D<float, 3>::SecondOrderType>(start_x, start_y, end_x, end_y, width, height, cb_xyz_sosse, so_elements);
514 center[0] =
static_cast<float>(tmp_center[0]);
515 center[1] =
static_cast<float>(tmp_center[1]);
516 center[2] =
static_cast<float>(tmp_center[2]);
518 covariance_matrix.coeffRef (0) =
static_cast<float> (so_elements [0]);
519 covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) =
static_cast<float> (so_elements [1]);
520 covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) =
static_cast<float> (so_elements [2]);
521 covariance_matrix.coeffRef (4) =
static_cast<float> (so_elements [3]);
522 covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) =
static_cast<float> (so_elements [4]);
523 covariance_matrix.coeffRef (8) =
static_cast<float> (so_elements [5]);
524 covariance_matrix -= (center * center.transpose ()) /
static_cast<float> (count);
526 Eigen::Vector3f eigen_vector;
527 pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
529 normal.getNormalVector3fMap () = eigen_vector;
532 if (eigen_value > 0.0)
533 normal.curvature = std::abs (eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8)));
535 normal.curvature = 0;
540 if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
542 if (!init_average_3d_gradient_)
543 initAverage3DGradientMethod ();
545 const int start_x = pos_x - rect_width_2_;
546 const int start_y = pos_y - rect_height_2_;
547 const int end_x = start_x + rect_width_;
548 const int end_y = start_y + rect_height_;
550 unsigned count_x = 0;
551 unsigned count_y = 0;
553 auto cb_dx_fecse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_DX_.getFiniteElementsCountSE (p1, p2, p3, p4); };
554 sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, cb_dx_fecse, count_x);
555 auto cb_dy_fecse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_DY_.getFiniteElementsCountSE (p1, p2, p3, p4); };
556 sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, cb_dy_fecse, count_y);
559 if (count_x == 0 || count_y == 0)
561 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point;
564 Eigen::Vector3d gradient_x (0, 0, 0);
565 Eigen::Vector3d gradient_y (0, 0, 0);
567 auto cb_dx_fosse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_DX_.getFirstOrderSumSE (p1, p2, p3, p4); };
568 sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, cb_dx_fosse, gradient_x);
569 auto cb_dy_fosse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_DY_.getFirstOrderSumSE (p1, p2, p3, p4); };
570 sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, cb_dy_fosse, gradient_y);
573 Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
574 double normal_length = normal_vector.squaredNorm ();
575 if (normal_length == 0.0f)
577 normal.getNormalVector3fMap ().setConstant (bad_point);
578 normal.curvature = bad_point;
582 normal_vector /= sqrt (normal_length);
584 float nx =
static_cast<float> (normal_vector [0]);
585 float ny =
static_cast<float> (normal_vector [1]);
586 float nz =
static_cast<float> (normal_vector [2]);
590 normal.normal_x = nx;
591 normal.normal_y = ny;
592 normal.normal_z = nz;
593 normal.curvature = bad_point;
597 if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
599 if (!init_depth_change_)
600 initAverageDepthChangeMethod ();
602 int point_index_L_x = pos_x - rect_width_4_ - 1;
603 int point_index_L_y = pos_y;
604 int point_index_R_x = pos_x + rect_width_4_ + 1;
605 int point_index_R_y = pos_y;
606 int point_index_U_x = pos_x - 1;
607 int point_index_U_y = pos_y - rect_height_4_;
608 int point_index_D_x = pos_x + 1;
609 int point_index_D_y = pos_y + rect_height_4_;
611 if (point_index_L_x < 0)
612 point_index_L_x = -point_index_L_x;
613 if (point_index_U_x < 0)
614 point_index_U_x = -point_index_U_x;
615 if (point_index_U_y < 0)
616 point_index_U_y = -point_index_U_y;
618 if (point_index_R_x >= width)
619 point_index_R_x = width-(point_index_R_x-(width-1));
620 if (point_index_D_x >= width)
621 point_index_D_x = width-(point_index_D_x-(width-1));
622 if (point_index_D_y >= height)
623 point_index_D_y = height-(point_index_D_y-(height-1));
625 const int start_x_L = pos_x - rect_width_2_;
626 const int start_y_L = pos_y - rect_height_4_;
627 const int end_x_L = start_x_L + rect_width_2_;
628 const int end_y_L = start_y_L + rect_height_2_;
630 const int start_x_R = pos_x + 1;
631 const int start_y_R = pos_y - rect_height_4_;
632 const int end_x_R = start_x_R + rect_width_2_;
633 const int end_y_R = start_y_R + rect_height_2_;
635 const int start_x_U = pos_x - rect_width_4_;
636 const int start_y_U = pos_y - rect_height_2_;
637 const int end_x_U = start_x_U + rect_width_2_;
638 const int end_y_U = start_y_U + rect_height_2_;
640 const int start_x_D = pos_x - rect_width_4_;
641 const int start_y_D = pos_y + 1;
642 const int end_x_D = start_x_D + rect_width_2_;
643 const int end_y_D = start_y_D + rect_height_2_;
645 unsigned count_L_z = 0;
646 unsigned count_R_z = 0;
647 unsigned count_U_z = 0;
648 unsigned count_D_z = 0;
650 auto cb_fecse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_depth_.getFiniteElementsCountSE (p1, p2, p3, p4); };
651 sumArea<unsigned>(start_x_L, start_y_L, end_x_L, end_y_L, width, height, cb_fecse, count_L_z);
652 sumArea<unsigned>(start_x_R, start_y_R, end_x_R, end_y_R, width, height, cb_fecse, count_R_z);
653 sumArea<unsigned>(start_x_U, start_y_U, end_x_U, end_y_U, width, height, cb_fecse, count_U_z);
654 sumArea<unsigned>(start_x_D, start_y_D, end_x_D, end_y_D, width, height, cb_fecse, count_D_z);
656 if (count_L_z == 0 || count_R_z == 0 || count_U_z == 0 || count_D_z == 0)
658 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = bad_point;
667 auto cb_fosse = [
this] (
unsigned p1,
unsigned p2,
unsigned p3,
unsigned p4) {
return integral_image_depth_.getFirstOrderSumSE (p1, p2, p3, p4); };
668 sumArea<float>(start_x_L, start_y_L, end_x_L, end_y_L, width, height, cb_fosse, mean_L_z);
669 sumArea<float>(start_x_R, start_y_R, end_x_R, end_y_R, width, height, cb_fosse, mean_R_z);
670 sumArea<float>(start_x_U, start_y_U, end_x_U, end_y_U, width, height, cb_fosse, mean_U_z);
671 sumArea<float>(start_x_D, start_y_D, end_x_D, end_y_D, width, height, cb_fosse, mean_D_z);
673 mean_L_z /=
static_cast<float>(count_L_z);
674 mean_R_z /=
static_cast<float>(count_R_z);
675 mean_U_z /=
static_cast<float>(count_U_z);
676 mean_D_z /=
static_cast<float>(count_D_z);
679 PointInT pointL = (*input_)[point_index_L_y*width + point_index_L_x];
680 PointInT pointR = (*input_)[point_index_R_y*width + point_index_R_x];
681 PointInT pointU = (*input_)[point_index_U_y*width + point_index_U_x];
682 PointInT pointD = (*input_)[point_index_D_y*width + point_index_D_x];
684 const float mean_x_z = mean_R_z - mean_L_z;
685 const float mean_y_z = mean_D_z - mean_U_z;
687 const float mean_x_x = pointR.x - pointL.x;
688 const float mean_x_y = pointR.y - pointL.y;
689 const float mean_y_x = pointD.x - pointU.x;
690 const float mean_y_y = pointD.y - pointU.y;
692 float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y;
693 float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z;
694 float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x;
696 const float normal_length = (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
698 if (normal_length == 0.0f)
700 normal.getNormalVector3fMap ().setConstant (bad_point);
701 normal.curvature = bad_point;
707 const float scale = 1.0f / std::sqrt (normal_length);
709 normal.normal_x = normal_x * scale;
710 normal.normal_y = normal_y * scale;
711 normal.normal_z = normal_z * scale;
712 normal.curvature = bad_point;
717 if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
719 PCL_THROW_EXCEPTION (
PCLException,
"BORDER_POLICY_MIRROR not supported for normal estimation method SIMPLE_3D_GRADIENT");
722 normal.getNormalVector3fMap ().setConstant (bad_point);
723 normal.curvature = bad_point;
728 template <
typename Po
intInT,
typename Po
intOutT>
void
734 float bad_point = std::numeric_limits<float>::quiet_NaN ();
737 auto depthChangeMap =
new unsigned char[input_->size ()];
738 std::fill_n(depthChangeMap, input_->size(), 255);
741 for (
unsigned int ri = 0; ri < input_->height-1; ++ri)
743 for (
unsigned int ci = 0; ci < input_->width-1; ++ci, ++index)
745 index = ri * input_->width + ci;
747 const float depth = input_->points [index].z;
748 const float depthR = input_->points [index + 1].z;
749 const float depthD = input_->points [index + input_->width].z;
752 const float depthDependendDepthChange = (max_depth_change_factor_ * (std::abs (depth) + 1.0f) * 2.0f);
754 if (std::fabs (depth - depthR) > depthDependendDepthChange
755 || !std::isfinite (depth) || !std::isfinite (depthR))
757 depthChangeMap[index] = 0;
758 depthChangeMap[index+1] = 0;
760 if (std::fabs (depth - depthD) > depthDependendDepthChange
761 || !std::isfinite (depth) || !std::isfinite (depthD))
763 depthChangeMap[index] = 0;
764 depthChangeMap[index + input_->width] = 0;
771 delete[] distance_map_;
772 distance_map_ =
new float[input_->size ()];
773 float *distanceMap = distance_map_;
774 for (std::size_t index = 0; index < input_->size (); ++index)
776 if (depthChangeMap[index] == 0)
777 distanceMap[index] = 0.0f;
779 distanceMap[index] =
static_cast<float> (input_->width + input_->height);
783 float* previous_row = distanceMap;
784 float* current_row = previous_row + input_->width;
785 for (std::size_t ri = 1; ri < input_->height; ++ri)
787 for (std::size_t ci = 1; ci < input_->width; ++ci)
789 const float upLeft = previous_row [ci - 1] + 1.4f;
790 const float up = previous_row [ci] + 1.0f;
791 const float upRight = previous_row [ci + 1] + 1.4f;
792 const float left = current_row [ci - 1] + 1.0f;
793 const float center = current_row [ci];
795 const float minValue = std::min (std::min (upLeft, up), std::min (left, upRight));
797 if (minValue < center)
798 current_row [ci] = minValue;
800 previous_row = current_row;
801 current_row += input_->width;
804 float* next_row = distanceMap + input_->width * (input_->height - 1);
805 current_row = next_row - input_->width;
807 for (
int ri = input_->height-2; ri >= 0; --ri)
809 for (
int ci = input_->width-2; ci >= 0; --ci)
811 const float lowerLeft = next_row [ci - 1] + 1.4f;
812 const float lower = next_row [ci] + 1.0f;
813 const float lowerRight = next_row [ci + 1] + 1.4f;
814 const float right = current_row [ci + 1] + 1.0f;
815 const float center = current_row [ci];
817 const float minValue = std::min (std::min (lowerLeft, lower), std::min (right, lowerRight));
819 if (minValue < center)
820 current_row [ci] = minValue;
822 next_row = current_row;
823 current_row -= input_->width;
826 if (indices_->size () < input_->size ())
827 computeFeaturePart (distanceMap, bad_point, output);
829 computeFeatureFull (distanceMap, bad_point, output);
831 delete[] depthChangeMap;
835 template <
typename Po
intInT,
typename Po
intOutT>
void
837 const float &bad_point,
842 if (border_policy_ == BORDER_POLICY_IGNORE)
848 const auto border =
static_cast<unsigned>(normal_smoothing_size_);
849 PointOutT* vec1 = &output [0];
850 PointOutT* vec2 = vec1 + input_->
width * (input_->height - border);
852 std::size_t count = border * input_->width;
853 for (std::size_t idx = 0; idx < count; ++idx)
855 vec1 [idx].getNormalVector3fMap ().setConstant (bad_point);
856 vec1 [idx].curvature = bad_point;
857 vec2 [idx].getNormalVector3fMap ().setConstant (bad_point);
858 vec2 [idx].curvature = bad_point;
862 vec1 = &output [border * input_->width];
863 vec2 = vec1 + input_->
width - border;
864 for (std::size_t ri = border; ri < input_->height - border; ++ri, vec1 += input_->width, vec2 += input_->width)
866 for (std::size_t ci = 0; ci < border; ++ci)
868 vec1 [ci].getNormalVector3fMap ().setConstant (bad_point);
869 vec1 [ci].curvature = bad_point;
870 vec2 [ci].getNormalVector3fMap ().setConstant (bad_point);
871 vec2 [ci].curvature = bad_point;
875 if (use_depth_dependent_smoothing_)
877 index = border + input_->width * border;
878 unsigned skip = (border << 1);
879 for (
unsigned ri = border; ri < input_->height - border; ++ri, index += skip)
881 for (
unsigned ci = border; ci < input_->width - border; ++ci, ++index)
883 index = ri * input_->width + ci;
885 const float depth = (*input_)[index].z;
886 if (!std::isfinite (depth))
888 output[index].getNormalVector3fMap ().setConstant (bad_point);
889 output[index].curvature = bad_point;
893 float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_ +
static_cast<float>(depth)/10.0f);
895 if (smoothing > 2.0f)
897 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
899 if(ci>
static_cast<unsigned>(rect_width_2_) && ri>
static_cast<unsigned>(rect_height_2_) && (ci+rect_width_2_)<input_->width && (ri+rect_height_2_)<input_->height) {
902 output[index].getNormalVector3fMap ().setConstant (bad_point);
903 output[index].curvature = bad_point;
908 output[index].getNormalVector3fMap ().setConstant (bad_point);
909 output[index].curvature = bad_point;
916 index = border + input_->
width * border;
917 unsigned skip = (border << 1);
918 for (
unsigned ri = border; ri < input_->height - border; ++ri, index += skip)
920 for (
unsigned ci = border; ci < input_->width - border; ++ci, ++index)
922 index = ri * input_->width + ci;
924 if (!std::isfinite ((*input_)[index].z))
926 output [index].getNormalVector3fMap ().setConstant (bad_point);
927 output [index].curvature = bad_point;
931 float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_);
933 if (smoothing > 2.0f)
935 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
940 output [index].getNormalVector3fMap ().setConstant (bad_point);
941 output [index].curvature = bad_point;
947 else if (border_policy_ == BORDER_POLICY_MIRROR)
951 if (use_depth_dependent_smoothing_)
956 for (
unsigned ri = 0; ri < input_->height; ++ri)
959 for (
unsigned ci = 0; ci < input_->width; ++ci)
961 index = ri * input_->width + ci;
963 const float depth = (*input_)[index].z;
964 if (!std::isfinite (depth))
966 output[index].getNormalVector3fMap ().setConstant (bad_point);
967 output[index].curvature = bad_point;
971 float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_ +
static_cast<float>(depth)/10.0f);
973 if (smoothing > 2.0f)
975 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
976 computePointNormalMirror (ci, ri, index, output [index]);
980 output[index].getNormalVector3fMap ().setConstant (bad_point);
981 output[index].curvature = bad_point;
991 for (
unsigned ri = 0; ri < input_->height; ++ri)
994 for (
unsigned ci = 0; ci < input_->width; ++ci)
996 index = ri * input_->
width + ci;
998 if (!std::isfinite ((*input_)[index].z))
1000 output [index].getNormalVector3fMap ().setConstant (bad_point);
1001 output [index].curvature = bad_point;
1005 float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_);
1007 if (smoothing > 2.0f)
1009 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
1010 computePointNormalMirror (ci, ri, index, output [index]);
1014 output [index].getNormalVector3fMap ().setConstant (bad_point);
1015 output [index].curvature = bad_point;
1024 template <
typename Po
intInT,
typename Po
intOutT>
void
1026 const float &bad_point,
1029 if (border_policy_ == BORDER_POLICY_IGNORE)
1032 const auto border =
static_cast<unsigned>(normal_smoothing_size_);
1033 const unsigned bottom = input_->height > border ? input_->height - border : 0;
1034 const unsigned right = input_->width > border ? input_->width - border : 0;
1035 if (use_depth_dependent_smoothing_)
1038 for (std::size_t idx = 0; idx < indices_->size (); ++idx)
1040 unsigned pt_index = (*indices_)[idx];
1041 unsigned u = pt_index % input_->width;
1042 unsigned v = pt_index / input_->width;
1043 if (v < border || v > bottom)
1045 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1046 output[idx].curvature = bad_point;
1050 if (u < border || u > right)
1052 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1053 output[idx].curvature = bad_point;
1057 const float depth = (*input_)[pt_index].z;
1058 if (!std::isfinite (depth))
1060 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1061 output[idx].curvature = bad_point;
1065 float smoothing = (std::min)(distanceMap[pt_index], normal_smoothing_size_ +
static_cast<float>(depth)/10.0f);
1066 if (smoothing > 2.0f)
1068 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
1073 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1074 output[idx].curvature = bad_point;
1081 for (std::size_t idx = 0; idx < indices_->size (); ++idx)
1083 unsigned pt_index = (*indices_)[idx];
1084 unsigned u = pt_index % input_->
width;
1085 unsigned v = pt_index / input_->width;
1086 if (v < border || v > bottom)
1088 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1089 output[idx].curvature = bad_point;
1093 if (u < border || u > right)
1095 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1096 output[idx].curvature = bad_point;
1100 if (!std::isfinite ((*input_)[pt_index].z))
1102 output [idx].getNormalVector3fMap ().setConstant (bad_point);
1103 output [idx].curvature = bad_point;
1107 float smoothing = (std::min)(distanceMap[pt_index], normal_smoothing_size_);
1109 if (smoothing > 2.0f)
1111 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
1116 output [idx].getNormalVector3fMap ().setConstant (bad_point);
1117 output [idx].curvature = bad_point;
1122 else if (border_policy_ == BORDER_POLICY_MIRROR)
1126 if (use_depth_dependent_smoothing_)
1128 for (std::size_t idx = 0; idx < indices_->size (); ++idx)
1130 unsigned pt_index = (*indices_)[idx];
1131 unsigned u = pt_index % input_->width;
1132 unsigned v = pt_index / input_->width;
1134 const float depth = (*input_)[pt_index].z;
1135 if (!std::isfinite (depth))
1137 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1138 output[idx].curvature = bad_point;
1142 float smoothing = (std::min)(distanceMap[pt_index], normal_smoothing_size_ +
static_cast<float>(depth)/10.0f);
1144 if (smoothing > 2.0f)
1146 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
1147 computePointNormalMirror (u, v, pt_index, output [idx]);
1151 output[idx].getNormalVector3fMap ().setConstant (bad_point);
1152 output[idx].curvature = bad_point;
1158 for (std::size_t idx = 0; idx < indices_->size (); ++idx)
1160 unsigned pt_index = (*indices_)[idx];
1161 unsigned u = pt_index % input_->
width;
1162 unsigned v = pt_index / input_->width;
1164 if (!std::isfinite ((*input_)[pt_index].z))
1166 output [idx].getNormalVector3fMap ().setConstant (bad_point);
1167 output [idx].curvature = bad_point;
1171 float smoothing = (std::min)(distanceMap[pt_index], normal_smoothing_size_);
1173 if (smoothing > 2.0f)
1175 setRectSize (
static_cast<int> (smoothing),
static_cast<int> (smoothing));
1176 computePointNormalMirror (u, v, pt_index, output [idx]);
1180 output [idx].getNormalVector3fMap ().setConstant (bad_point);
1181 output [idx].curvature = bad_point;
1189 template <
typename Po
intInT,
typename Po
intOutT>
bool
1192 if (!input_->isOrganized ())
1194 PCL_ERROR (
"[pcl::IntegralImageNormalEstimation::initCompute] Input dataset is not organized (height = 1).\n");
1197 return (Feature<PointInT, PointOutT>::initCompute ());
1200 #define PCL_INSTANTIATE_IntegralImageNormalEstimation(T,NT) template class PCL_EXPORTS pcl::IntegralImageNormalEstimation<T,NT>;
An exception thrown when init can not be performed should be used in all the PCLBase class inheritant...
Determines an integral image representation for a given organized data array.
ElementType getFirstOrderSumSE(unsigned start_x, unsigned start_y, unsigned end_x, unsigned end_y) const
Compute the first order sum within a given rectangle.
ElementType getFirstOrderSum(unsigned start_x, unsigned start_y, unsigned width, unsigned height) const
Compute the first order sum within a given rectangle.
SecondOrderType getSecondOrderSum(unsigned start_x, unsigned start_y, unsigned width, unsigned height) const
Compute the second order sum within a given rectangle.
Surface normal estimation on organized data using integral images.
void initData()
Initialize the data structures, based on the normal estimation method chosen.
void setRectSize(const int width, const int height)
Set the regions size which is considered for normal estimation.
~IntegralImageNormalEstimation() override
Destructor.
void computeFeatureFull(const float *distance_map, const float &bad_point, PointCloudOut &output)
Computes the normal for the complete cloud.
void computePointNormal(const int pos_x, const int pos_y, const unsigned point_index, PointOutT &normal)
Computes the normal at the specified position.
void computeFeature(PointCloudOut &output) override
Computes the normal for the complete cloud or only indices_ if provided.
void computeFeaturePart(const float *distance_map, const float &bad_point, PointCloudOut &output)
Computes the normal for part of the cloud specified by indices_.
void computePointNormalMirror(const int pos_x, const int pos_y, const unsigned point_index, PointOutT &normal)
Computes the normal at the specified position with mirroring for border handling.
A base class for all pcl exceptions which inherits from std::runtime_error.
bool is_dense
True if no points are invalid (e.g., have NaN or Inf values in any of their floating point fields).
Eigen::Quaternionf sensor_orientation_
Sensor acquisition pose (rotation).
std::uint32_t width
The point cloud width (if organized as an image-structure).
Eigen::Vector4f sensor_origin_
Sensor acquisition pose (origin/translation).
void eigen33(const Matrix &mat, typename Matrix::Scalar &eigenvalue, Vector &eigenvector)
determines the eigenvector and eigenvalue of the smallest eigenvalue of the symmetric positive semi d...
void flipNormalTowardsViewpoint(const PointT &point, float vp_x, float vp_y, float vp_z, Eigen::Matrix< Scalar, 4, 1 > &normal)
Flip (in place) the estimated normal of a point towards a given viewpoint.
bool computePointNormal(const pcl::PointCloud< PointT > &cloud, Eigen::Vector4f &plane_parameters, float &curvature)
Compute the Least-Squares plane fit for a given set of points, and return the estimated plane paramet...