Point Cloud Library (PCL)  1.5.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
integral_image_normal.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Copyright (c) 2011, Willow Garage, Inc.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of Willow Garage, Inc. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE.
00033  *
00034  */
00035 
00036 #ifndef PCL_FEATURES_INTEGRALIMAGE_BASED_IMPL_NORMAL_ESTIMATOR_H_
00037 #define PCL_FEATURES_INTEGRALIMAGE_BASED_IMPL_NORMAL_ESTIMATOR_H_
00038 
00039 #include "pcl/features/integral_image_normal.h"
00040 
00042 template <typename PointInT, typename PointOutT>
00043 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::~IntegralImageNormalEstimation ()
00044 {
00045   if (diff_x_ != NULL) delete diff_x_;
00046   if (diff_y_ != NULL) delete diff_y_;
00047   if (depth_data_ != NULL) delete depth_data_;
00048 }
00049 
00051 template <typename PointInT, typename PointOutT> void
00052 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initData ()
00053 {
00054   // compute derivatives
00055   if (diff_x_ != NULL) delete diff_x_;
00056   if (diff_y_ != NULL) delete diff_y_;
00057   if (depth_data_ != NULL) delete depth_data_;
00058   diff_x_ = NULL;
00059   diff_y_ = NULL;
00060   depth_data_ = NULL;
00061 
00062   if (normal_estimation_method_ == COVARIANCE_MATRIX)
00063     initCovarianceMatrixMethod ();
00064   else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
00065     initAverage3DGradientMethod ();
00066   else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
00067     initAverageDepthChangeMethod ();
00068   else if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
00069     initSimple3DGradientMethod ();
00070 }
00071 
00072 
00074 template <typename PointInT, typename PointOutT> void
00075 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::setRectSize (const int width, const int height)
00076 {
00077   rect_width_      = width;
00078   rect_width_2_    = width >> 1;
00079   rect_width_4_    = width >> 2;
00080   rect_height_     = height;
00081   rect_height_2_   = height >> 1;
00082   rect_height_4_   = height >> 2;
00083 }
00084 
00086 template <typename PointInT, typename PointOutT> void
00087 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initSimple3DGradientMethod ()
00088 {
00089   // number of DataType entries per element (equal or bigger than dimensions)
00090   int element_stride = sizeof (PointInT) / sizeof (float);
00091   // number of DataType entries per row (equal or bigger than element_stride number of elements per row)
00092   int row_stride     = element_stride * input_->width;
00093 
00094   float *data_ = reinterpret_cast<float*>((PointInT*)(&(input_->points[0])));
00095 
00096   integral_image_XYZ_.setSecondOrderComputation (false);
00097   integral_image_XYZ_.setInput (data_, input_->width, input_->height, element_stride, row_stride);
00098 
00099   init_simple_3d_gradient_ = true;
00100   init_covariance_matrix_ = init_average_3d_gradient_ = init_depth_change_ = false;
00101 }
00102 
00104 template <typename PointInT, typename PointOutT> void
00105 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initCovarianceMatrixMethod ()
00106 {
00107   // number of DataType entries per element (equal or bigger than dimensions)
00108   int element_stride = sizeof (PointInT) / sizeof (float);
00109   // number of DataType entries per row (equal or bigger than element_stride number of elements per row)
00110   int row_stride     = element_stride * input_->width;
00111 
00112   float *data_ = reinterpret_cast<float*>((PointInT*)(&(input_->points[0])));
00113 
00114   integral_image_XYZ_.setSecondOrderComputation (true);
00115   integral_image_XYZ_.setInput (data_, input_->width, input_->height, element_stride, row_stride);
00116 
00117   init_covariance_matrix_ = true;
00118   init_average_3d_gradient_ = init_depth_change_ = init_simple_3d_gradient_ = false;
00119 }
00120 
00122 template <typename PointInT, typename PointOutT> void
00123 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initAverage3DGradientMethod ()
00124 {
00125   size_t data_size = (input_->points.size () << 2);
00126   diff_x_ = new float[data_size];
00127   diff_y_ = new float[data_size];
00128 
00129   memset (diff_x_, 0, sizeof(float) * data_size);
00130   memset (diff_y_, 0, sizeof(float) * data_size);
00131 
00132   // x u x
00133   // l x r
00134   // x d x
00135   const PointInT* point_up = &(input_->points [1]);
00136   const PointInT* point_dn = point_up + (input_->width << 1);//&(input_->points [1 + (input_->width << 1)]);
00137   const PointInT* point_lf = &(input_->points [input_->width]);
00138   const PointInT* point_rg = point_lf + 2; //&(input_->points [input_->width + 2]);
00139   float* diff_x_ptr = diff_x_ + ((input_->width + 1) << 2);
00140   float* diff_y_ptr = diff_y_ + ((input_->width + 1) << 2);
00141   unsigned diff_skip = 8; // skip last element in row and the first in the next row
00142 
00143   for (size_t ri = 1; ri < input_->height - 1; ++ri
00144                                              , point_up += input_->width
00145                                              , point_dn += input_->width
00146                                              , point_lf += input_->width
00147                                              , point_rg += input_->width
00148                                              , diff_x_ptr += diff_skip
00149                                              , diff_y_ptr += diff_skip)
00150   {
00151     for (size_t ci = 0; ci < input_->width - 2; ++ci, diff_x_ptr += 4, diff_y_ptr += 4)
00152     {
00153       diff_x_ptr[0] = point_rg[ci].x - point_lf[ci].x;
00154       diff_x_ptr[1] = point_rg[ci].y - point_lf[ci].y;
00155       diff_x_ptr[2] = point_rg[ci].z - point_lf[ci].z;
00156 
00157       diff_y_ptr[0] = point_dn[ci].x - point_up[ci].x;
00158       diff_y_ptr[1] = point_dn[ci].y - point_up[ci].y;
00159       diff_y_ptr[2] = point_dn[ci].z - point_up[ci].z;
00160     }
00161   }
00162 
00163   // Compute integral images
00164   integral_image_DX_.setInput (diff_x_, input_->width, input_->height, 4, input_->width << 2);
00165   integral_image_DY_.setInput (diff_y_, input_->width, input_->height, 4, input_->width << 2);
00166   init_covariance_matrix_ = init_depth_change_ = init_simple_3d_gradient_ = false;
00167   init_average_3d_gradient_ = true;
00168 }
00169 
00171 template <typename PointInT, typename PointOutT> void
00172 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initAverageDepthChangeMethod ()
00173 {
00174   // number of DataType entries per element (equal or bigger than dimensions)
00175   int element_stride = sizeof (PointInT) / sizeof (float);
00176   // number of DataType entries per row (equal or bigger than element_stride number of elements per row)
00177   int row_stride     = element_stride * input_->width;
00178 
00179   float *data_ = reinterpret_cast<float*>((PointInT*)(&(input_->points[0])));
00180 
00181   // integral image over the z - value
00182   integral_image_depth_.setInput (&(data_[2]), input_->width, input_->height, element_stride, row_stride);
00183   init_depth_change_ = true;
00184   init_covariance_matrix_ = init_average_3d_gradient_ = init_simple_3d_gradient_ = false;
00185 }
00186 
00188 template <typename PointInT, typename PointOutT> void
00189 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::computePointNormal (
00190     const int pos_x, const int pos_y, const unsigned point_index, PointOutT &normal)
00191 {
00192   float bad_point = std::numeric_limits<float>::quiet_NaN ();
00193 
00194   if (normal_estimation_method_ == COVARIANCE_MATRIX)
00195   {
00196     if (!init_covariance_matrix_)
00197       initCovarianceMatrixMethod ();
00198 
00199     unsigned count = integral_image_XYZ_.getFiniteElementsCount (pos_x - (rect_width_2_), pos_y - (rect_height_2_), rect_width_, rect_height_);
00200 
00201     // no valid points within the rectangular reagion?
00202     if (count == 0)
00203     {
00204       normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
00205       return;
00206     }
00207 
00208     EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix;
00209     Eigen::Vector3f center;
00210     typename IntegralImage2D<float, 3>::SecondOrderType so_elements;
00211     center = integral_image_XYZ_.getFirstOrderSum(pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_).cast<float> ();
00212     so_elements = integral_image_XYZ_.getSecondOrderSum(pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
00213 
00214     covariance_matrix.coeffRef (0) = so_elements [0];
00215     covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) = so_elements [1];
00216     covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) = so_elements [2];
00217     covariance_matrix.coeffRef (4) = so_elements [3];
00218     covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) = so_elements [4];
00219     covariance_matrix.coeffRef (8) = so_elements [5];
00220     covariance_matrix -= (center * center.transpose ()) / count;
00221     float eigen_value;
00222     Eigen::Vector3f eigen_vector;
00223     pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector);
00224     if (eigen_vector [2] < 0.0f)
00225       normal.getNormalVector4fMap () = Eigen::Vector4f (eigen_vector [0], eigen_vector [1], eigen_vector [2], 0);
00226     else
00227       normal.getNormalVector4fMap () = Eigen::Vector4f (-eigen_vector [0], -eigen_vector [1], -eigen_vector [2], 0);
00228 
00229     // Compute the curvature surface change
00230     if (eigen_value > 0.0)
00231       normal.curvature = fabs ( eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8)) );
00232     else
00233       normal.curvature = 0;
00234 
00235     return;
00236   }
00237   else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT)
00238   {
00239     if (!init_average_3d_gradient_)
00240       initAverage3DGradientMethod ();
00241 
00242     unsigned count_x = integral_image_DX_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
00243     unsigned count_y = integral_image_DY_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
00244     if (count_x == 0 || count_y == 0)
00245     {
00246       normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
00247       return;
00248     }
00249     Eigen::Vector3d gradient_x = integral_image_DX_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
00250     Eigen::Vector3d gradient_y = integral_image_DY_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
00251 
00252     Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
00253     double normal_length = normal_vector.squaredNorm ();
00254     if (normal_length == 0.0f)
00255     {
00256       normal.getNormalVector4fMap ().setConstant (bad_point);
00257       normal.curvature = bad_point;
00258       return;
00259     }
00260 
00261     normal_vector /= sqrt(normal_length);
00262     normal.normal_x = normal_vector [0];
00263     normal.normal_y = normal_vector [1];
00264     normal.normal_z = normal_vector [2];
00265     normal.curvature = bad_point;
00266     return;
00267   }
00268   else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE)
00269   {
00270     if (!init_depth_change_)
00271       initAverageDepthChangeMethod ();
00272 
00273 //    unsigned count = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, rect_height_);
00274 //    if (count == 0)
00275 //    {
00276 //      normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
00277 //      return;
00278 //    }
00279 //    const float mean_L_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_2_ - 1, pos_y - rect_height_2_    , rect_width_ - 1, rect_height_ - 1) / ((rect_width_-1)*(rect_height_-1));
00280 //    const float mean_R_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_2_ + 1, pos_y - rect_height_2_    , rect_width_ - 1, rect_height_ - 1) / ((rect_width_-1)*(rect_height_-1));
00281 //    const float mean_U_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_2_    , pos_y - rect_height_2_ - 1, rect_width_ - 1, rect_height_ - 1) / ((rect_width_-1)*(rect_height_-1));
00282 //    const float mean_D_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_2_    , pos_y - rect_height_2_ + 1, rect_width_ - 1, rect_height_ - 1) / ((rect_width_-1)*(rect_height_-1));
00283 
00284     // width and height are at least 3 x 3
00285     unsigned count_L_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_2_, pos_y - rect_height_4_, rect_width_2_, rect_height_2_);
00286     unsigned count_R_z = integral_image_depth_.getFiniteElementsCount (pos_x + 1            , pos_y - rect_height_4_, rect_width_2_, rect_height_2_);
00287     unsigned count_U_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_4_, pos_y - rect_height_2_, rect_width_2_, rect_height_2_);
00288     unsigned count_D_z = integral_image_depth_.getFiniteElementsCount (pos_x - rect_width_4_, pos_y + 1             , rect_width_2_, rect_height_2_);
00289 
00290     if (count_L_z == 0 || count_R_z == 0 || count_U_z == 0 || count_D_z == 0)
00291     {
00292       normal.normal_x = normal.normal_y = normal.normal_z = normal.curvature = std::numeric_limits<float>::quiet_NaN ();
00293       return;
00294     }
00295 
00296     float mean_L_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_4_, rect_width_2_, rect_height_2_) / count_L_z;
00297     float mean_R_z = integral_image_depth_.getFirstOrderSum (pos_x + 1            , pos_y - rect_height_4_, rect_width_2_, rect_height_2_) / count_R_z;
00298     float mean_U_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_4_, pos_y - rect_height_2_, rect_width_2_, rect_height_2_) / count_U_z;
00299     float mean_D_z = integral_image_depth_.getFirstOrderSum (pos_x - rect_width_4_, pos_y + 1             , rect_width_2_, rect_height_2_) / count_D_z;
00300 
00301     PointInT pointL = input_->points[point_index - rect_width_4_ - 1];
00302     PointInT pointR = input_->points[point_index + rect_width_4_ + 1];
00303     PointInT pointU = input_->points[point_index - rect_height_4_ * input_->width - 1];
00304     PointInT pointD = input_->points[point_index + rect_height_4_ * input_->width + 1];
00305 
00306     const float mean_x_z = mean_R_z - mean_L_z;
00307     const float mean_y_z = mean_D_z - mean_U_z;
00308 
00309     const float mean_x_x = pointR.x - pointL.x;
00310     const float mean_x_y = pointR.y - pointL.y;
00311     const float mean_y_x = pointD.x - pointU.x;
00312     const float mean_y_y = pointD.y - pointU.y;
00313 
00314     const float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y;
00315     const float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z;
00316     const float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x;
00317 
00318     const float normal_length = (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z);
00319 
00320     if (normal_length == 0.0f)
00321     {
00322       normal.getNormalVector4fMap ().setConstant (bad_point);
00323       normal.curvature = bad_point;
00324       return;
00325     }
00326 
00327     const float scale = -1.0f / sqrt (normal_length);
00328 
00329     normal.normal_x = normal_x * scale;
00330     normal.normal_y = normal_y * scale;
00331     normal.normal_z = normal_z * scale;
00332     normal.curvature = bad_point;
00333 
00334     return;
00335   }
00336   else if (normal_estimation_method_ == SIMPLE_3D_GRADIENT)
00337   {
00338     if (!init_simple_3d_gradient_)
00339       initSimple3DGradientMethod ();
00340 
00341     // this method does not work if lots of NaNs are in the neighborhood of the point
00342     Eigen::Vector3d gradient_x = integral_image_XYZ_.getFirstOrderSum (pos_x + rect_width_2_, pos_y - rect_height_2_, 1, rect_height_) -
00343                                  integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, 1, rect_height_);
00344 
00345     Eigen::Vector3d gradient_y = integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y + rect_height_2_, rect_width_, 1) -
00346                                  integral_image_XYZ_.getFirstOrderSum (pos_x - rect_width_2_, pos_y - rect_height_2_, rect_width_, 1);
00347     Eigen::Vector3d normal_vector = gradient_y.cross (gradient_x);
00348     double normal_length = normal_vector.squaredNorm ();
00349     if (normal_length == 0.0f)
00350     {
00351       normal.getNormalVector4fMap ().setConstant (bad_point);
00352       normal.curvature = bad_point;
00353       return;
00354     }
00355 
00356     normal_vector /= sqrt(normal_length);
00357     normal.normal_x = normal_vector [0];
00358     normal.normal_y = normal_vector [1];
00359     normal.normal_z = normal_vector [2];
00360     normal.curvature = bad_point;
00361     return;
00362   }
00363 
00364   normal.getNormalVector4fMap ().setConstant (bad_point);
00365   normal.curvature = bad_point;
00366   return;
00367 }
00368 
00370 template <typename PointInT, typename PointOutT> void
00371 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::computeFeature (PointCloudOut &output)
00372 {
00373   float bad_point = std::numeric_limits<float>::quiet_NaN ();
00374 
00375   // compute depth-change map
00376   unsigned char * depthChangeMap = new unsigned char[input_->points.size ()];
00377   memset (depthChangeMap, 255, input_->points.size ());
00378 
00379   unsigned index = 0;
00380   for (unsigned int ri = 0; ri < input_->height-1; ++ri)
00381   {
00382     for (unsigned int ci = 0; ci < input_->width-1; ++ci, ++index)
00383     {
00384 //      const float depth  = (*input_)(ci,     ri    ).z;
00385 //      const float depthR = (*input_)(ci + 1, ri    ).z;
00386 //      const float depthD = (*input_)(ci,     ri + 1).z;
00387 
00388       const float depth  = input_->points [index].z;
00389       const float depthR = input_->points [index + 1].z;
00390       const float depthD = input_->points [index + input_->width].z;
00391 
00392       //const float depthDependendDepthChange = (max_depth_change_factor_ * (fabs(depth)+1.0f))/(500.0f*0.001f);
00393       const float depthDependendDepthChange = (max_depth_change_factor_ * (fabs (depth) + 1.0f) * 2.0f);
00394 
00395       if (abs (depth - depthR) > depthDependendDepthChange
00396         || !pcl_isfinite (depth) || !pcl_isfinite (depthR))
00397       {
00398         depthChangeMap[index] = 0;
00399         depthChangeMap[index] = 0;
00400       }
00401       if (abs (depth - depthD) > depthDependendDepthChange
00402         || !pcl_isfinite (depth) || !pcl_isfinite (depthD))
00403       {
00404         depthChangeMap[index] = 0;
00405         depthChangeMap[index + input_->width] = 0;
00406       }
00407     }
00408   }
00409 
00410   // compute distance map
00411   float *distanceMap = new float[input_->points.size ()];
00412   for (size_t index = 0; index < input_->points.size (); ++index)
00413   {
00414     if (depthChangeMap[index] == 0)
00415       distanceMap[index] = 0.0f;
00416     else
00417       distanceMap[index] = input_->width + input_->height;
00418   }
00419 
00420   // first pass
00421   float* previous_row = distanceMap;
00422   float* current_row = previous_row + input_->width;
00423   for (size_t ri = 1; ri < input_->height; ++ri)
00424   {
00425     for (size_t ci = 1; ci < input_->width; ++ci)
00426     {
00427       const float upLeft  = previous_row [ci - 1] + 1.4f; //distanceMap[(ri-1)*input_->width + ci-1] + 1.4f;
00428       const float up      = previous_row [ci] + 1.0f;     //distanceMap[(ri-1)*input_->width + ci] + 1.0f;
00429       const float upRight = previous_row [ci + 1] + 1.4f; //distanceMap[(ri-1)*input_->width + ci+1] + 1.4f;
00430       const float left    = current_row  [ci - 1] + 1.0f;  //distanceMap[ri*input_->width + ci-1] + 1.0f;
00431       const float center  = current_row  [ci];             //distanceMap[ri*input_->width + ci];
00432 
00433       const float minValue = std::min (std::min (upLeft, up), std::min (left, upRight));
00434 
00435       if (minValue < center)
00436         current_row [ci] = minValue; //distanceMap[ri * input_->width + ci] = minValue;
00437     }
00438     previous_row = current_row;
00439     current_row += input_->width;
00440   }
00441 
00442   float* next_row    = distanceMap + input_->width * (input_->height - 1);
00443   current_row = next_row - input_->width;
00444   // second pass
00445   for (int ri = input_->height-2; ri >= 0; --ri)
00446   {
00447     for (int ci = input_->width-2; ci >= 0; --ci)
00448     {
00449       const float lowerLeft  = next_row [ci - 1] + 1.4f;    //distanceMap[(ri+1)*input_->width + ci-1] + 1.4f;
00450       const float lower      = next_row [ci] + 1.0f;        //distanceMap[(ri+1)*input_->width + ci] + 1.0f;
00451       const float lowerRight = next_row [ci + 1] + 1.4f;    //distanceMap[(ri+1)*input_->width + ci+1] + 1.4f;
00452       const float right      = current_row [ci + 1] + 1.0f; //distanceMap[ri*input_->width + ci+1] + 1.0f;
00453       const float center     = current_row [ci];            //distanceMap[ri*input_->width + ci];
00454 
00455       const float minValue = std::min (std::min (lowerLeft, lower), std::min (right, lowerRight));
00456 
00457       if (minValue < center)
00458         current_row [ci] = minValue; //distanceMap[ri*input_->width + ci] = minValue;
00459     }
00460   }
00461 
00462   // Set all normals that we do not touch to NaN
00463   // top and bottom borders
00464   unsigned border = int(normal_smoothing_size_);
00465   PointOutT* vec1 = &output [0];
00466   PointOutT* vec2 = vec1 + input_->width * (input_->height - border);
00467 
00468   size_t count = border * input_->width;
00469   for (size_t idx = 0; idx < count; ++idx)
00470   {
00471     vec1 [idx].getNormalVector4fMap ().setConstant (bad_point);
00472     vec1 [idx].curvature = bad_point;
00473     vec2 [idx].getNormalVector4fMap ().setConstant (bad_point);
00474     vec2 [idx].curvature = bad_point;
00475   }
00476 
00477   // left and right borders actually columns
00478   vec1 = &output [border * input_->width];
00479   vec2 = vec1 + input_->width - border;
00480   for (size_t ri = border; ri < input_->height - border; ++ri, vec1 += input_->width, vec2 += input_->width)
00481   {
00482     for (size_t ci = 0; ci < border; ++ci)
00483     {
00484       vec1 [ci].getNormalVector4fMap ().setConstant (bad_point);
00485       vec1 [ci].curvature = bad_point;
00486       vec2 [ci].getNormalVector4fMap ().setConstant (bad_point);
00487       vec2 [ci].curvature = bad_point;
00488     }
00489   }
00490 
00491   if (use_depth_dependent_smoothing_)
00492   {
00493     index = border + input_->width * border;
00494     unsigned skip = (border << 1);
00495     for (unsigned ri = border; ri < input_->height - border; ++ri, index += skip)
00496     {
00497       for (unsigned ci = border; ci < input_->width - border; ++ci, ++index)
00498       {
00499         const float depth = input_->points[index].z;
00500         if (!pcl_isfinite (depth))
00501         {
00502           output[index].getNormalVector4fMap ().setConstant (bad_point);
00503           output[index].curvature = bad_point;
00504           continue;
00505         }
00506 
00507         float smoothing = (std::min)(distanceMap[index], normal_smoothing_size_ + static_cast<float>(depth)/10.0f);
00508 
00509         if (smoothing > 2.0f)
00510         {
00511           setRectSize (smoothing, smoothing);
00512           computePointNormal (ci, ri, index, output [index]);
00513         }
00514         else
00515         {
00516           output[index].getNormalVector4fMap ().setConstant (bad_point);
00517           output[index].curvature = bad_point;
00518         }
00519       }
00520     }
00521   }
00522   else
00523   {
00524     float smoothing_constant = normal_smoothing_size_ * 2.0f;
00525 
00526     index = border + input_->width * border;
00527     unsigned skip = (border << 1);
00528     for (unsigned ri = border; ri < input_->height - border; ++ri, index += skip)
00529     {
00530       for (unsigned ci = border; ci < input_->width - border; ++ci, ++index)
00531       {
00532         if (!pcl_isfinite (input_->points[index].z))
00533         {
00534           output [index].getNormalVector4fMap ().setConstant (bad_point);
00535           output [index].curvature = bad_point;
00536           continue;
00537         }
00538 
00539         float smoothing = (std::min)(distanceMap[index], smoothing_constant);
00540 
00541         if (smoothing > 2.0f)
00542         {
00543           setRectSize (smoothing, smoothing);
00544           computePointNormal (ci, ri, index, output [index]);
00545         }
00546         else
00547         {
00548           output [index].getNormalVector4fMap ().setConstant (bad_point);
00549           output [index].curvature = bad_point;
00550         }
00551       }
00552     }
00553   }
00554 
00555   delete[] depthChangeMap;
00556   delete[] distanceMap;
00557 }
00558 
00560 template <typename PointInT, typename PointOutT> bool
00561 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initCompute ()
00562 {
00563   if (!input_->isOrganized ())
00564   {
00565     PCL_ERROR ("[pcl::IntegralImageNormalEstimation::initCompute] Input dataset is not organized (height = 1).\n");
00566     return (false);
00567   }
00568   return (Feature<PointInT, PointOutT>::initCompute ());
00569 }
00570 
00571 #define PCL_INSTANTIATE_IntegralImageNormalEstimation(T,NT) template class PCL_EXPORTS pcl::IntegralImageNormalEstimation<T,NT>;
00572 
00573 #endif
00574