36 #ifndef PCL_FEATURES_INTEGRALIMAGE_BASED_IMPL_NORMAL_ESTIMATOR_H_
37 #define PCL_FEATURES_INTEGRALIMAGE_BASED_IMPL_NORMAL_ESTIMATOR_H_
42 #include <boost/bind.hpp>
45 template <
typename Po
intInT,
typename Po
intOutT>
48 if (diff_x_ != NULL)
delete diff_x_;
49 if (diff_y_ != NULL)
delete diff_y_;
50 if (depth_data_ != NULL)
delete depth_data_;
51 if (distance_map_ != NULL)
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.");
71 if (diff_x_ != NULL)
delete diff_x_;
72 if (diff_y_ != NULL)
delete diff_y_;
73 if (depth_data_ != NULL)
delete depth_data_;
74 if (distance_map_ != NULL)
delete distance_map_;
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_->points[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_->points[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
143 size_t data_size = (input_->points.size () << 2);
144 diff_x_ =
new float[data_size];
145 diff_y_ =
new float[data_size];
147 memset (diff_x_, 0,
sizeof(
float) * data_size);
148 memset (diff_y_, 0,
sizeof(
float) * data_size);
153 const PointInT* point_up = &(input_->points [1]);
154 const PointInT* point_dn = point_up + (input_->width << 1);
155 const PointInT* point_lf = &(input_->points [input_->width]);
156 const PointInT* point_rg = point_lf + 2;
157 float* diff_x_ptr = diff_x_ + ((input_->width + 1) << 2);
158 float* diff_y_ptr = diff_y_ + ((input_->width + 1) << 2);
159 unsigned diff_skip = 8;
161 for (
size_t ri = 1; ri < input_->height - 1; ++ri
162 , point_up += input_->width
163 , point_dn += input_->width
164 , point_lf += input_->width
165 , point_rg += input_->width
166 , diff_x_ptr += diff_skip
167 , diff_y_ptr += diff_skip)
169 for (
size_t ci = 0; ci < input_->width - 2; ++ci, diff_x_ptr += 4, diff_y_ptr += 4)
171 diff_x_ptr[0] = point_rg[ci].x - point_lf[ci].x;
172 diff_x_ptr[1] = point_rg[ci].y - point_lf[ci].y;
173 diff_x_ptr[2] = point_rg[ci].z - point_lf[ci].z;
175 diff_y_ptr[0] = point_dn[ci].x - point_up[ci].x;
176 diff_y_ptr[1] = point_dn[ci].y - point_up[ci].y;
177 diff_y_ptr[2] = point_dn[ci].z - point_up[ci].z;
182 integral_image_DX_.setInput (diff_x_, input_->width, input_->height, 4, input_->width << 2);
183 integral_image_DY_.setInput (diff_y_, input_->width, input_->height, 4, input_->width << 2);
184 init_covariance_matrix_ = init_depth_change_ = init_simple_3d_gradient_ =
false;
185 init_average_3d_gradient_ =
true;
189 template <
typename Po
intInT,
typename Po
intOutT>
void
193 int element_stride =
sizeof (PointInT) /
sizeof (
float);
195 int row_stride = element_stride * input_->width;
197 const float *data_ =
reinterpret_cast<const float*
> (&input_->points[0]);
200 integral_image_depth_.setInput (&(data_[2]), input_->width, input_->height, element_stride, row_stride);
201 init_depth_change_ =
true;
202 init_covariance_matrix_ = init_average_3d_gradient_ = init_simple_3d_gradient_ =
false;
206 template <
typename Po
intInT,
typename Po
intOutT>
void
208 const int pos_x,
const int pos_y,
const unsigned point_index, PointOutT &normal)
210 float bad_point = std::numeric_limits<float>::quiet_NaN ();
212 if (normal_estimation_method_ == COVARIANCE_MATRIX)
214 if (!init_covariance_matrix_)
215 initCovarianceMatrixMethod ();
217 unsigned count = integral_image_XYZ_.getFiniteElementsCount (pos_x - (rect_width_2_), pos_y - (rect_height_2_), rect_width_, rect_height_);
222 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
227 Eigen::Vector3f center;
229 center = integral_image_XYZ_.
getFirstOrderSum(pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_).cast<
float> ();
230 so_elements = integral_image_XYZ_.
getSecondOrderSum(pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
232 covariance_matrix.coeffRef (0) =
static_cast<float> (so_elements [0]);
233 covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) =
static_cast<float> (so_elements [1]);
234 covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) =
static_cast<float> (so_elements [2]);
235 covariance_matrix.coeffRef (4) =
static_cast<float> (so_elements [3]);
236 covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) =
static_cast<float> (so_elements [4]);
237 covariance_matrix.coeffRef (8) =
static_cast<float> (so_elements [5]);
238 covariance_matrix -= (center * center.transpose ()) / static_cast<float> (count);
240 Eigen::Vector3f eigen_vector;
241 pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
244 normal.getNormalVector3fMap () = eigen_vector;
247 if (eigen_value > 0.0)
248 normal.curvature = fabsf (eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8)));
250 normal.curvature = 0;
254 else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
256 if (!init_average_3d_gradient_)
257 initAverage3DGradientMethod ();
259 unsigned count_x = integral_image_DX_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
260 unsigned count_y = integral_image_DY_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
261 if (count_x == 0 || count_y == 0)
263 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
266 Eigen::Vector3d gradient_x = integral_image_DX_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
267 Eigen::Vector3d gradient_y = integral_image_DY_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
269 Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
270 double normal_length = normal_vector.squaredNorm ();
271 if (normal_length == 0.0f)
273 normal.getNormalVector4fMap ().setConstant (bad_point);
274 normal.curvature = bad_point;
278 normal_vector /=
sqrt (normal_length);
280 float nx =
static_cast<float> (normal_vector [0]);
281 float ny =
static_cast<float> (normal_vector [1]);
282 float nz =
static_cast<float> (normal_vector [2]);
287 normal.normal_x = nx;
288 normal.normal_y = ny;
289 normal.normal_z = nz;
290 normal.curvature = bad_point;
293 else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
295 if (!init_depth_change_)
296 initAverageDepthChangeMethod ();
310 unsigned count_L_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_4_, rect_width_2_, rect_height_2_);
311 unsigned count_R_z = integral_image_depth_.getFiniteElementsCount (pos_x + 1 , pos_y - rect_height_4_, rect_width_2_, rect_height_2_);
312 unsigned count_U_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_4_, pos_y - rect_height_2_, rect_width_2_, rect_height_2_);
313 unsigned count_D_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_4_, pos_y + 1 , rect_width_2_, rect_height_2_);
315 if (count_L_z == 0 || count_R_z == 0 || count_U_z == 0 || count_D_z == 0)
317 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
321 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);
322 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);
323 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);
324 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);
326 PointInT pointL = input_->points[point_index - rect_width_4_ - 1];
327 PointInT pointR = input_->points[point_index + rect_width_4_ + 1];
328 PointInT pointU = input_->points[point_index - rect_height_4_ * input_->width - 1];
329 PointInT pointD = input_->points[point_index + rect_height_4_ * input_->width + 1];
331 const float mean_x_z = mean_R_z - mean_L_z;
332 const float mean_y_z = mean_D_z - mean_U_z;
334 const float mean_x_x = pointR.x - pointL.x;
335 const float mean_x_y = pointR.y - pointL.y;
336 const float mean_y_x = pointD.x - pointU.x;
337 const float mean_y_y = pointD.y - pointU.y;
339 float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y;
340 float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z;
341 float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x;
343 const float normal_length = (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
345 if (normal_length == 0.0f)
347 normal.getNormalVector4fMap ().setConstant (bad_point);
348 normal.curvature = bad_point;
354 const float scale = 1.0f /
sqrt (normal_length);
356 normal.normal_x = normal_x * scale;
357 normal.normal_y = normal_y * scale;
358 normal.normal_z = normal_z * scale;
359 normal.curvature = bad_point;
363 else if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
365 if (!init_simple_3d_gradient_)
366 initSimple3DGradientMethod ();
369 Eigen::Vector3d gradient_x = integral_image_XYZ_.getFirstOrderSum (pos_x + rect_width_2_, pos_y - rect_height_2_, 1, rect_height_) -
370 integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, 1, rect_height_);
372 Eigen::Vector3d gradient_y = integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y + rect_height_2_, rect_width_, 1) -
373 integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, 1);
374 Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
375 double normal_length = normal_vector.squaredNorm ();
376 if (normal_length == 0.0f)
378 normal.getNormalVector4fMap ().setConstant (bad_point);
379 normal.curvature = bad_point;
383 normal_vector /=
sqrt (normal_length);
385 float nx =
static_cast<float> (normal_vector [0]);
386 float ny =
static_cast<float> (normal_vector [1]);
387 float nz =
static_cast<float> (normal_vector [2]);
392 normal.normal_x = nx;
393 normal.normal_y = ny;
394 normal.normal_z = nz;
395 normal.curvature = bad_point;
399 normal.getNormalVector4fMap ().setConstant (bad_point);
400 normal.curvature = bad_point;
405 template <
typename T>
407 sumArea (
int start_x,
int start_y,
int end_x,
int end_y,
const int width,
const int height,
408 const boost::function<T(
unsigned,
unsigned,
unsigned,
unsigned)> &f,
443 result += f (0, 0, end_x, end_y);
444 result += f (0, 0, -start_x, -start_y);
445 result += f (0, 0, -start_x, end_y);
446 result += f (0, 0, end_x, -start_y);
448 else if (end_y >= height)
450 result += f (0, start_y, end_x, height-1);
451 result += f (0, start_y, -start_x, height-1);
452 result += f (0, height-(end_y-(height-1)), end_x, height-1);
453 result += f (0, height-(end_y-(height-1)), -start_x, height-1);
457 result += f (0, start_y, end_x, end_y);
458 result += f (0, start_y, -start_x, end_y);
461 else if (start_y < 0)
465 result += f (start_x, 0, width-1, end_y);
466 result += f (start_x, 0, width-1, -start_y);
467 result += f (width-(end_x-(width-1)), 0, width-1, end_y);
468 result += f (width-(end_x-(width-1)), 0, width-1, -start_y);
472 result += f (start_x, 0, end_x, end_y);
473 result += f (start_x, 0, end_x, -start_y);
476 else if (end_x >= width)
480 result += f (start_x, start_y, width-1, height-1);
481 result += f (start_x, height-(end_y-(height-1)), width-1, height-1);
482 result += f (width-(end_x-(width-1)), start_y, width-1, height-1);
483 result += f (width-(end_x-(width-1)), height-(end_y-(height-1)), width-1, height-1);
487 result += f (start_x, start_y, width-1, end_y);
488 result += f (width-(end_x-(width-1)), start_y, width-1, end_y);
491 else if (end_y >= height)
493 result += f (start_x, start_y, end_x, height-1);
494 result += f (start_x, height-(end_y-(height-1)), end_x, height-1);
498 result += f (start_x, start_y, end_x, end_y);
503 template <
typename Po
intInT,
typename Po
intOutT>
void
505 const int pos_x,
const int pos_y,
const unsigned point_index, PointOutT &normal)
507 float bad_point = std::numeric_limits<float>::quiet_NaN ();
509 const int width = input_->width;
510 const int height = input_->height;
512 if (normal_estimation_method_ == COVARIANCE_MATRIX)
514 if (!init_covariance_matrix_)
515 initCovarianceMatrixMethod ();
517 const int start_x = pos_x - rect_width_2_;
518 const int start_y = pos_y - rect_height_2_;
519 const int end_x = start_x + rect_width_;
520 const int end_y = start_y + rect_height_;
523 sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getFiniteElementsCountSE, &integral_image_XYZ_, _1, _2, _3, _4), count);
528 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
533 Eigen::Vector3f center;
551 sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getFirstOrderSumSE, &integral_image_XYZ_, _1, _2, _3, _4), tmp_center);
552 sumArea<typename IntegralImage2D<float, 3>::SecondOrderType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getSecondOrderSumSE, &integral_image_XYZ_, _1, _2, _3, _4), so_elements);
554 center[0] = tmp_center[0];
555 center[1] = tmp_center[1];
556 center[2] = tmp_center[2];
558 covariance_matrix.coeffRef (0) =
static_cast<float> (so_elements [0]);
559 covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) =
static_cast<float> (so_elements [1]);
560 covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) =
static_cast<float> (so_elements [2]);
561 covariance_matrix.coeffRef (4) =
static_cast<float> (so_elements [3]);
562 covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) =
static_cast<float> (so_elements [4]);
563 covariance_matrix.coeffRef (8) =
static_cast<float> (so_elements [5]);
564 covariance_matrix -= (center * center.transpose ()) / static_cast<float> (count);
566 Eigen::Vector3f eigen_vector;
567 pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
570 normal.getNormalVector3fMap () = eigen_vector;
573 if (eigen_value > 0.0)
574 normal.curvature = fabsf (eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8)));
576 normal.curvature = 0;
580 else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
582 if (!init_average_3d_gradient_)
583 initAverage3DGradientMethod ();
585 const int start_x = pos_x - rect_width_2_;
586 const int start_y = pos_y - rect_height_2_;
587 const int end_x = start_x + rect_width_;
588 const int end_y = start_y + rect_height_;
590 unsigned count_x = 0;
591 unsigned count_y = 0;
593 sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getFiniteElementsCountSE, &integral_image_DX_, _1, _2, _3, _4), count_x);
594 sumArea<unsigned>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getFiniteElementsCountSE, &integral_image_DY_, _1, _2, _3, _4), count_y);
597 if (count_x == 0 || count_y == 0)
599 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
605 Eigen::Vector3d gradient_x (0, 0, 0);
606 Eigen::Vector3d gradient_y (0, 0, 0);
608 sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getFirstOrderSumSE, &integral_image_DX_, _1, _2, _3, _4), gradient_x);
609 sumArea<typename IntegralImage2D<float, 3>::ElementType>(start_x, start_y, end_x, end_y, width, height, boost::bind(&
IntegralImage2D<float, 3>::getFirstOrderSumSE, &integral_image_DY_, _1, _2, _3, _4), gradient_y);
612 Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
613 double normal_length = normal_vector.squaredNorm ();
614 if (normal_length == 0.0f)
616 normal.getNormalVector4fMap ().setConstant (bad_point);
617 normal.curvature = bad_point;
621 normal_vector /=
sqrt (normal_length);
623 float nx =
static_cast<float> (normal_vector [0]);
624 float ny =
static_cast<float> (normal_vector [1]);
625 float nz =
static_cast<float> (normal_vector [2]);
630 normal.normal_x = nx;
631 normal.normal_y = ny;
632 normal.normal_z = nz;
633 normal.curvature = bad_point;
636 else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
638 if (!init_depth_change_)
639 initAverageDepthChangeMethod ();
646 int point_index_L_x = pos_x - rect_width_4_ - 1;
647 int point_index_L_y = pos_y;
648 int point_index_R_x = pos_x + rect_width_4_ + 1;
649 int point_index_R_y = pos_y;
650 int point_index_U_x = pos_x - 1;
651 int point_index_U_y = pos_y - rect_height_4_;
652 int point_index_D_x = pos_x + 1;
653 int point_index_D_y = pos_y + rect_height_4_;
655 if (point_index_L_x < 0)
656 point_index_L_x = -point_index_L_x;
657 if (point_index_U_x < 0)
658 point_index_U_x = -point_index_U_x;
659 if (point_index_U_y < 0)
660 point_index_U_y = -point_index_U_y;
662 if (point_index_R_x >= width)
663 point_index_R_x = width-(point_index_R_x-(width-1));
664 if (point_index_D_x >= width)
665 point_index_D_x = width-(point_index_D_x-(width-1));
666 if (point_index_D_y >= height)
667 point_index_D_y = height-(point_index_D_y-(height-1));
681 const int start_x_L = pos_x - rect_width_2_;
682 const int start_y_L = pos_y - rect_height_4_;
683 const int end_x_L = start_x_L + rect_width_2_;
684 const int end_y_L = start_y_L + rect_height_2_;
686 const int start_x_R = pos_x + 1;
687 const int start_y_R = pos_y - rect_height_4_;
688 const int end_x_R = start_x_R + rect_width_2_;
689 const int end_y_R = start_y_R + rect_height_2_;
691 const int start_x_U = pos_x - rect_width_4_;
692 const int start_y_U = pos_y - rect_height_2_;
693 const int end_x_U = start_x_U + rect_width_2_;
694 const int end_y_U = start_y_U + rect_height_2_;
696 const int start_x_D = pos_x - rect_width_4_;
697 const int start_y_D = pos_y + 1;
698 const int end_x_D = start_x_D + rect_width_2_;
699 const int end_y_D = start_y_D + rect_height_2_;
707 unsigned count_L_z = 0;
708 unsigned count_R_z = 0;
709 unsigned count_U_z = 0;
710 unsigned count_D_z = 0;
712 sumArea<unsigned>(start_x_L, start_y_L, end_x_L, end_y_L, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_L_z);
713 sumArea<unsigned>(start_x_R, start_y_R, end_x_R, end_y_R, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_R_z);
714 sumArea<unsigned>(start_x_U, start_y_U, end_x_U, end_y_U, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_U_z);
715 sumArea<unsigned>(start_x_D, start_y_D, end_x_D, end_y_D, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFiniteElementsCountSE, &integral_image_depth_, _1, _2, _3, _4), count_D_z);
717 if (count_L_z == 0 || count_R_z == 0 || count_U_z == 0 || count_D_z == 0)
719 normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
733 sumArea<float>(start_x_L, start_y_L, end_x_L, end_y_L, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_L_z);
734 sumArea<float>(start_x_R, start_y_R, end_x_R, end_y_R, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_R_z);
735 sumArea<float>(start_x_U, start_y_U, end_x_U, end_y_U, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_U_z);
736 sumArea<float>(start_x_D, start_y_D, end_x_D, end_y_D, width, height, boost::bind(&
IntegralImage2D<float, 1>::getFirstOrderSumSE, &integral_image_depth_, _1, _2, _3, _4), mean_D_z);
738 mean_L_z /= count_L_z;
739 mean_R_z /= count_R_z;
740 mean_U_z /= count_U_z;
741 mean_D_z /= count_D_z;
748 PointInT pointL = input_->points[point_index_L_y*width + point_index_L_x];
749 PointInT pointR = input_->points[point_index_R_y*width + point_index_R_x];
750 PointInT pointU = input_->points[point_index_U_y*width + point_index_U_x];
751 PointInT pointD = input_->points[point_index_D_y*width + point_index_D_x];
753 const float mean_x_z = mean_R_z - mean_L_z;
754 const float mean_y_z = mean_D_z - mean_U_z;
756 const float mean_x_x = pointR.x - pointL.x;
757 const float mean_x_y = pointR.y - pointL.y;
758 const float mean_y_x = pointD.x - pointU.x;
759 const float mean_y_y = pointD.y - pointU.y;
761 float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y;
762 float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z;
763 float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x;
765 const float normal_length = (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
767 if (normal_length == 0.0f)
769 normal.getNormalVector4fMap ().setConstant (bad_point);
770 normal.curvature = bad_point;
776 const float scale = 1.0f /
sqrt (normal_length);
778 normal.normal_x = normal_x * scale;
779 normal.normal_y = normal_y * scale;
780 normal.normal_z = normal_z * scale;
781 normal.curvature = bad_point;
785 else if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
842 normal.getNormalVector4fMap ().setConstant (bad_point);
843 normal.curvature = bad_point;
848 template <
typename Po
intInT,
typename Po
intOutT>
void
851 output.sensor_origin_ = input_->sensor_origin_;
852 output.sensor_orientation_ = input_->sensor_orientation_;
854 float bad_point = std::numeric_limits<float>::quiet_NaN ();
857 unsigned char * depthChangeMap =
new unsigned char[input_->points.size ()];
858 memset (depthChangeMap, 255, input_->points.size ());
861 for (
unsigned int ri = 0; ri < input_->height-1; ++ri)
863 for (
unsigned int ci = 0; ci < input_->width-1; ++ci, ++index)
865 index = ri * input_->width + ci;
867 const float depth = input_->points [index].z;
868 const float depthR = input_->points [index + 1].z;
869 const float depthD = input_->points [index + input_->width].z;
872 const float depthDependendDepthChange = (max_depth_change_factor_ * (fabsf (depth) + 1.0f) * 2.0f);
874 if (fabs (depth - depthR) > depthDependendDepthChange
877 depthChangeMap[index] = 0;
878 depthChangeMap[index+1] = 0;
880 if (fabs (depth - depthD) > depthDependendDepthChange
883 depthChangeMap[index] = 0;
884 depthChangeMap[index + input_->width] = 0;
891 if (distance_map_ != NULL)
delete distance_map_;
892 distance_map_ =
new float[input_->points.size ()];
893 float *distanceMap = distance_map_;
894 for (
size_t index = 0; index < input_->points.size (); ++index)
896 if (depthChangeMap[index] == 0)
897 distanceMap[index] = 0.0f;
899 distanceMap[index] =
static_cast<float> (input_->width + input_->height);
903 float* previous_row = distanceMap;
904 float* current_row = previous_row + input_->width;
905 for (
size_t ri = 1; ri < input_->height; ++ri)
907 for (
size_t ci = 1; ci < input_->width; ++ci)
909 const float upLeft = previous_row [ci - 1] + 1.4f;
910 const float up = previous_row [ci] + 1.0f;
911 const float upRight = previous_row [ci + 1] + 1.4f;
912 const float left = current_row [ci - 1] + 1.0f;
913 const float center = current_row [ci];
915 const float minValue = std::min (std::min (upLeft, up), std::min (left, upRight));
917 if (minValue < center)
918 current_row [ci] = minValue;
920 previous_row = current_row;
921 current_row += input_->width;
924 float* next_row = distanceMap + input_->width * (input_->height - 1);
925 current_row = next_row - input_->width;
927 for (
int ri = input_->height-2; ri >= 0; --ri)
929 for (
int ci = input_->width-2; ci >= 0; --ci)
931 const float lowerLeft = next_row [ci - 1] + 1.4f;
932 const float lower = next_row [ci] + 1.0f;
933 const float lowerRight = next_row [ci + 1] + 1.4f;
934 const float right = current_row [ci + 1] + 1.0f;
935 const float center = current_row [ci];
937 const float minValue = std::min (std::min (lowerLeft, lower), std::min (right, lowerRight));
939 if (minValue < center)
940 current_row [ci] = minValue;
942 next_row = current_row;
943 current_row -= input_->width;
946 if (border_policy_ == BORDER_POLICY_IGNORE)
951 output.is_dense =
false;
952 unsigned border = int(normal_smoothing_size_);
953 PointOutT* vec1 = &output [0];
954 PointOutT* vec2 = vec1 + input_->width * (input_->height - border);
956 size_t count = border * input_->width;
957 for (
size_t idx = 0; idx < count; ++idx)
959 vec1 [idx].getNormalVector4fMap ().setConstant (bad_point);
960 vec1 [idx].curvature = bad_point;
961 vec2 [idx].getNormalVector4fMap ().setConstant (bad_point);
962 vec2 [idx].curvature = bad_point;
966 vec1 = &output [border * input_->width];
967 vec2 = vec1 + input_->width - border;
968 for (
size_t ri = border; ri < input_->height - border; ++ri, vec1 += input_->width, vec2 += input_->width)
970 for (
size_t ci = 0; ci < border; ++ci)
972 vec1 [ci].getNormalVector4fMap ().setConstant (bad_point);
973 vec1 [ci].curvature = bad_point;
974 vec2 [ci].getNormalVector4fMap ().setConstant (bad_point);
975 vec2 [ci].curvature = bad_point;
979 if (use_depth_dependent_smoothing_)
981 index = border + input_->width * border;
982 unsigned skip = (border << 1);
983 for (
unsigned ri = border; ri < input_->height - border; ++ri, index += skip)
985 for (
unsigned ci = border; ci < input_->width - border; ++ci, ++index)
987 index = ri * input_->width + ci;
989 const float depth = input_->points[index].z;
992 output[index].getNormalVector4fMap ().setConstant (bad_point);
993 output[index].curvature = bad_point;
997 float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_ + static_cast<float>(depth)/10.0f);
999 if (smoothing > 2.0f)
1001 setRectSize (static_cast<int> (smoothing), static_cast<int> (smoothing));
1006 output[index].getNormalVector4fMap ().setConstant (bad_point);
1007 output[index].curvature = bad_point;
1014 float smoothing_constant = normal_smoothing_size_;
1016 index = border + input_->width * border;
1017 unsigned skip = (border << 1);
1018 for (
unsigned ri = border; ri < input_->height - border; ++ri, index += skip)
1020 for (
unsigned ci = border; ci < input_->width - border; ++ci, ++index)
1022 index = ri * input_->width + ci;
1026 output [index].getNormalVector4fMap ().setConstant (bad_point);
1027 output [index].curvature = bad_point;
1031 float smoothing = (std::min)(distanceMap[index], smoothing_constant);
1033 if (smoothing > 2.0f)
1035 setRectSize (static_cast<int> (smoothing), static_cast<int> (smoothing));
1040 output [index].getNormalVector4fMap ().setConstant (bad_point);
1041 output [index].curvature = bad_point;
1047 else if (border_policy_ == BORDER_POLICY_MIRROR)
1049 output.is_dense =
false;
1051 if (use_depth_dependent_smoothing_)
1056 for (
unsigned ri = 0; ri < input_->height; ++ri)
1059 for (
unsigned ci = 0; ci < input_->width; ++ci)
1061 index = ri * input_->width + ci;
1063 const float depth = input_->points[index].z;
1066 output[index].getNormalVector4fMap ().setConstant (bad_point);
1067 output[index].curvature = bad_point;
1071 float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_ + static_cast<float>(depth)/10.0f);
1073 if (smoothing > 2.0f)
1075 setRectSize (static_cast<int> (smoothing), static_cast<int> (smoothing));
1076 computePointNormalMirror (ci, ri, index, output [index]);
1080 output[index].getNormalVector4fMap ().setConstant (bad_point);
1081 output[index].curvature = bad_point;
1088 float smoothing_constant = normal_smoothing_size_;
1093 for (
unsigned ri = 0; ri < input_->height; ++ri)
1096 for (
unsigned ci = 0; ci < input_->width; ++ci)
1098 index = ri * input_->width + ci;
1102 output [index].getNormalVector4fMap ().setConstant (bad_point);
1103 output [index].curvature = bad_point;
1107 float smoothing = (std::min)(distanceMap[index], smoothing_constant);
1109 if (smoothing > 2.0f)
1111 setRectSize (static_cast<int> (smoothing), static_cast<int> (smoothing));
1112 computePointNormalMirror (ci, ri, index, output [index]);
1116 output [index].getNormalVector4fMap ().setConstant (bad_point);
1117 output [index].curvature = bad_point;
1124 delete[] depthChangeMap;
1129 template <
typename Po
intInT,
typename Po
intOutT>
bool
1132 if (!input_->isOrganized ())
1134 PCL_ERROR (
"[pcl::IntegralImageNormalEstimation::initCompute] Input dataset is not organized (height = 1).\n");
1137 return (Feature<PointInT, PointOutT>::initCompute ());
1140 #define PCL_INSTANTIATE_IntegralImageNormalEstimation(T,NT) template class PCL_EXPORTS pcl::IntegralImageNormalEstimation<T,NT>;