|
Point Cloud Library (PCL)
1.4.0
|
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 00059 if (normal_estimation_method_ == COVARIANCE_MATRIX) 00060 initCovarianceMatrixMethod (); 00061 else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT) 00062 initAverage3DGradientMethod (); 00063 else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE) 00064 initAverageDepthChangeMethod (); 00065 } 00066 00067 00069 template <typename PointInT, typename PointOutT> void 00070 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::setRectSize (const int width, const int height) 00071 { 00072 rect_width_ = width; 00073 rect_height_ = height; 00074 } 00075 00077 template <typename PointInT, typename PointOutT> void 00078 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initCovarianceMatrixMethod () 00079 { 00080 // number of DataType entries per element (equal or bigger than dimensions) 00081 int element_stride = sizeof (input_->points[0]) / sizeof (float); 00082 // number of DataType entries per row (equal or bigger than element_stride number of elements per row) 00083 int row_stride = element_stride * input_->width; 00084 00085 float *data_ = reinterpret_cast<float*>((PointInT*)(&(input_->points[0]))); 00086 00087 integral_image_XYZ_.setInput (data_, input_->width, input_->height, element_stride, row_stride); 00088 00089 init_covariance_matrix_ = true; 00090 init_average_3d_gradient_ = init_depth_change_ = false; 00091 } 00092 00094 template <typename PointInT, typename PointOutT> void 00095 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initAverage3DGradientMethod () 00096 { 00097 float *data_ = reinterpret_cast<float*>((PointInT*)(&(input_->points[0]))); 00098 size_t nr_points = 4 * input_->points.size (); 00099 diff_x_ = new float[nr_points]; 00100 diff_y_ = new float[nr_points]; 00101 00102 // number of DataType entries per element (equal or bigger than dimensions) 00103 int element_stride = sizeof (input_->points[0]) / sizeof (float); 00104 // number of DataType entries per row (equal or bigger than element_stride number of elements per row) 00105 int row_stride = element_stride * input_->width; 00106 00107 memset (diff_x_, 0, sizeof(float) * nr_points); 00108 memset (diff_y_, 0, sizeof(float) * nr_points); 00109 00110 for (size_t ri = 1; ri < input_->height - 1; ++ri) 00111 { 00112 float *data_pointer_y_up = data_ + (ri-1)*row_stride + element_stride; 00113 float *data_pointer_y_down = data_ + (ri+1)*row_stride + element_stride; 00114 float *data_pointer_x_left = data_ + ri*row_stride; 00115 float *data_pointer_x_right = data_ + ri*row_stride + 2*element_stride; 00116 00117 float * diff_x_pointer = diff_x_ + ri * 4 * input_->width + 4; 00118 float * diff_y_pointer = diff_y_ + ri * 4 * input_->width + 4; 00119 00120 for (size_t ci = 1; ci < input_->width - 1; ++ci) 00121 { 00122 diff_x_pointer[0] = data_pointer_x_right[0] - data_pointer_x_left[0]; 00123 diff_x_pointer[1] = data_pointer_x_right[1] - data_pointer_x_left[1]; 00124 diff_x_pointer[2] = data_pointer_x_right[2] - data_pointer_x_left[2]; 00125 00126 diff_y_pointer[0] = data_pointer_y_down[0] - data_pointer_y_up[0]; 00127 diff_y_pointer[1] = data_pointer_y_down[1] - data_pointer_y_up[1]; 00128 diff_y_pointer[2] = data_pointer_y_down[2] - data_pointer_y_up[2]; 00129 00130 diff_x_pointer += 4; 00131 diff_y_pointer += 4; 00132 00133 data_pointer_y_up += element_stride; 00134 data_pointer_y_down += element_stride; 00135 data_pointer_x_left += element_stride; 00136 data_pointer_x_right += element_stride; 00137 } 00138 } 00139 00140 // Compute integral images 00141 integral_image_X_.setInput (diff_x_, input_->width, input_->height, 4, 4 * input_->width); 00142 integral_image_Y_.setInput (diff_y_, input_->width, input_->height, 4, 4 * input_->width); 00143 init_covariance_matrix_ = init_depth_change_ = false; 00144 init_average_3d_gradient_ = true; 00145 } 00146 00148 template <typename PointInT, typename PointOutT> void 00149 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::initAverageDepthChangeMethod () 00150 { 00151 // number of DataType entries per element (equal or bigger than dimensions) 00152 int element_stride = sizeof (input_->points[0]) / sizeof (float); 00153 // number of DataType entries per row (equal or bigger than element_stride number of elements per row) 00154 int row_stride = element_stride * input_->width; 00155 00156 float *data_ = reinterpret_cast<float*>((PointInT*)(&(input_->points[0]))); 00157 // compute integral image 00158 //integral_image_ = new pcl::IntegralImage2D<float, double>( 00159 // &(data_[2]), input_->width, input_->height, 1, false, element_stride, row_stride); 00160 00161 integral_image_depth_.setInput (&(data_[2]), input_->width, input_->height, element_stride, row_stride); 00162 init_depth_change_ = true; 00163 init_covariance_matrix_ = init_average_3d_gradient_ = false; 00164 } 00165 00167 template <typename PointInT, typename PointOutT> void 00168 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::computePointNormal ( 00169 const int pos_x, const int pos_y, PointOutT &normal) 00170 { 00171 float bad_point = std::numeric_limits<float>::quiet_NaN (); 00172 00173 if (normal_estimation_method_ == COVARIANCE_MATRIX) 00174 { 00175 if (!init_covariance_matrix_) 00176 initCovarianceMatrixMethod (); 00177 00178 EIGEN_ALIGN16 Eigen::Matrix3f covariance_matrix; 00179 Eigen::Vector3f center; 00180 typename IntegralImage2D<float, 3>::SecondOrderType so_elements; 00181 00182 center = integral_image_XYZ_.getFirstOrderSum(pos_x - (rect_width_ >> 1), pos_y - (rect_height_ >> 1), rect_width_, rect_height_).cast<float> (); 00183 so_elements = integral_image_XYZ_.getSecondOrderSum(pos_x - (rect_width_ >> 1), pos_y - (rect_height_ >> 1), rect_width_, rect_height_); 00184 covariance_matrix.coeffRef (0) = so_elements [0]; 00185 covariance_matrix.coeffRef (1) = covariance_matrix.coeffRef (3) = so_elements [1]; 00186 covariance_matrix.coeffRef (2) = covariance_matrix.coeffRef (6) = so_elements [2]; 00187 covariance_matrix.coeffRef (4) = so_elements [3]; 00188 covariance_matrix.coeffRef (5) = covariance_matrix.coeffRef (7) = so_elements [4]; 00189 covariance_matrix.coeffRef (8) = so_elements [5]; 00190 covariance_matrix -= (center * center.transpose ()) / (rect_width_ * rect_height_); 00191 float eigen_value; 00192 Eigen::Vector3f eigen_vector; 00193 pcl::eigen33 (covariance_matrix, eigen_value, eigen_vector); 00194 if (eigen_vector [2] < 0.0f) 00195 normal.getNormalVector4fMap () = Eigen::Vector4f (eigen_vector [0], eigen_vector [1], eigen_vector [2], 0); 00196 else 00197 normal.getNormalVector4fMap () = Eigen::Vector4f (-eigen_vector [0], -eigen_vector [1], -eigen_vector [2], 0); 00198 00199 // Compute the curvature surface change 00200 if (eigen_value > 0.0) 00201 normal.curvature = fabs ( eigen_value / (covariance_matrix.coeff (0) + covariance_matrix.coeff (4) + covariance_matrix.coeff (8)) ); 00202 else 00203 normal.curvature = 0; 00204 00205 return; 00206 } 00207 else if (normal_estimation_method_ == AVERAGE_3D_GRADIENT) 00208 { 00209 if (!init_average_3d_gradient_) 00210 initAverage3DGradientMethod (); 00211 const float mean_x_x = integral_image_X_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-rect_height_/2, rect_width_, rect_height_) [0]; 00212 const float mean_x_y = integral_image_X_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-rect_height_/2, rect_width_, rect_height_) [1]; 00213 const float mean_x_z = integral_image_X_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-rect_height_/2, rect_width_, rect_height_) [2]; 00214 00215 const float mean_y_x = integral_image_Y_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-rect_height_/2, rect_width_, rect_height_) [0]; 00216 const float mean_y_y = integral_image_Y_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-rect_height_/2, rect_width_, rect_height_) [1]; 00217 const float mean_y_z = integral_image_Y_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-rect_height_/2, rect_width_, rect_height_) [2]; 00218 00219 const float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y; 00220 const float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z; 00221 const float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x; 00222 00223 00224 const float normal_length = sqrt (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z); 00225 00226 if (normal_length == 0.0f) 00227 { 00228 normal.getNormalVector4fMap ().setConstant (bad_point); 00229 normal.curvature = bad_point; 00230 return; 00231 } 00232 00233 const float scale = -1.0f / normal_length; 00234 00235 normal.normal_x = normal_x * scale; 00236 normal.normal_y = normal_y * scale; 00237 normal.normal_z = normal_z * scale; 00238 normal.curvature = bad_point; 00239 return; 00240 } 00241 else if (normal_estimation_method_ == AVERAGE_DEPTH_CHANGE) 00242 { 00243 if (!init_depth_change_) 00244 initAverageDepthChangeMethod (); 00245 00246 PointInT pointL = input_->points[pos_y * input_->width + pos_x-rect_width_/2]; 00247 PointInT pointR = input_->points[pos_y * input_->width + pos_x+rect_width_/2]; 00248 PointInT pointU = input_->points[(pos_y-rect_height_/2) * input_->width+pos_x]; 00249 PointInT pointD = input_->points[(pos_y+rect_height_/2) * input_->width+pos_x]; 00250 00251 const float mean_L_z = integral_image_depth_.getFirstOrderSum (pos_x-1-rect_width_/2, pos_y-rect_height_/2, rect_width_-1, rect_height_-1)/((rect_width_-1)*(rect_height_-1)); 00252 const float mean_R_z = integral_image_depth_.getFirstOrderSum (pos_x+1-rect_width_/2, pos_y-rect_height_/2, rect_width_-1, rect_height_-1)/((rect_width_-1)*(rect_height_-1)); 00253 const float mean_U_z = integral_image_depth_.getFirstOrderSum (pos_x-rect_width_/2, pos_y-1-rect_height_/2, rect_width_-1, rect_height_-1)/((rect_width_-1)*(rect_height_-1)); 00254 const float mean_D_z = integral_image_depth_.getFirstOrderSum (pos_x-rect_width_/2, pos_y+1-rect_height_/2, rect_width_-1, rect_height_-1)/((rect_width_-1)*(rect_height_-1)); 00255 00256 const float mean_x_z = (mean_R_z - mean_L_z)/2.0f; 00257 const float mean_y_z = (mean_D_z - mean_U_z)/2.0f; 00258 00259 const float mean_x_x = (pointR.x - pointL.x)/(rect_width_); 00260 const float mean_x_y = (pointR.y - pointL.y)/(rect_height_); 00261 const float mean_y_x = (pointD.x - pointU.x)/(rect_width_); 00262 const float mean_y_y = (pointD.y - pointU.y)/(rect_height_); 00263 00264 const float normal_x = mean_x_y * mean_y_z - mean_x_z * mean_y_y; 00265 const float normal_y = mean_x_z * mean_y_x - mean_x_x * mean_y_z; 00266 const float normal_z = mean_x_x * mean_y_y - mean_x_y * mean_y_x; 00267 00268 const float normal_length = sqrt (normal_x * normal_x + normal_y * normal_y + normal_z * normal_z); 00269 00270 if (normal_length == 0.0f) 00271 { 00272 normal.getNormalVector4fMap ().setConstant (bad_point); 00273 normal.curvature = bad_point; 00274 return; 00275 } 00276 00277 const float scale = -1.0f / normal_length; 00278 00279 normal.normal_x = normal_x*scale; 00280 normal.normal_y = normal_y*scale; 00281 normal.normal_z = normal_z*scale; 00282 normal.curvature = bad_point; 00283 00284 return; 00285 } 00286 normal.getNormalVector4fMap ().setConstant (bad_point); 00287 normal.curvature = bad_point; 00288 return; 00289 } 00290 00292 template <typename PointInT, typename PointOutT> void 00293 pcl::IntegralImageNormalEstimation<PointInT, PointOutT>::computeFeature (PointCloudOut &output) 00294 { 00295 float bad_point = std::numeric_limits<float>::quiet_NaN (); 00296 00297 // compute depth-change map 00298 unsigned char * depthChangeMap = new unsigned char[input_->points.size ()]; 00299 memset (depthChangeMap, 255, input_->points.size ()); 00300 00301 for (unsigned int ri = 0; ri < input_->height-1; ++ri) 00302 { 00303 for (unsigned int ci = 0; ci < input_->width-1; ++ci) 00304 { 00305 const float depth = (*input_)(ci, ri ).z; 00306 const float depthR = (*input_)(ci + 1, ri ).z; 00307 const float depthD = (*input_)(ci, ri + 1).z; 00308 00309 const float depthDependendDepthChange = (max_depth_change_factor_ * (fabs(depth)+1.0f))/(500.0f*0.001f); 00310 00311 if (abs (depth - depthR) > depthDependendDepthChange 00312 || !pcl_isfinite (depth) || !pcl_isfinite (depthR)) 00313 { 00314 depthChangeMap[ri*input_->width + ci] = 0; 00315 depthChangeMap[ri*input_->width + ci+1] = 0; 00316 } 00317 if (abs (depth - depthD) > depthDependendDepthChange 00318 || !pcl_isfinite (depth) || !pcl_isfinite (depthD)) 00319 { 00320 depthChangeMap[ri*input_->width + ci] = 0; 00321 depthChangeMap[(ri+1)*input_->width + ci] = 0; 00322 } 00323 } 00324 } 00325 00326 00327 // compute distance map 00328 float *distanceMap = new float[input_->points.size ()]; 00329 for (size_t index = 0; index < input_->points.size (); ++index) 00330 { 00331 if (depthChangeMap[index] == 0) 00332 distanceMap[index] = 0.0f; 00333 else 00334 distanceMap[index] = 640.0f; 00335 } 00336 00337 // first pass 00338 for (size_t ri = 1; ri < input_->height; ++ri) 00339 { 00340 for (size_t ci = 1; ci < input_->width; ++ci) 00341 { 00342 const float upLeft = distanceMap[(ri-1)*input_->width + ci-1] + 1.4f; 00343 const float up = distanceMap[(ri-1)*input_->width + ci] + 1.0f; 00344 const float upRight = distanceMap[(ri-1)*input_->width + ci+1] + 1.4f; 00345 const float left = distanceMap[ri*input_->width + ci-1] + 1.0f; 00346 const float center = distanceMap[ri*input_->width + ci]; 00347 00348 const float minValue = std::min (std::min (upLeft, up), std::min (left, upRight)); 00349 00350 if (minValue < center) 00351 distanceMap[ri * input_->width + ci] = minValue; 00352 } 00353 } 00354 00355 // second pass 00356 for (int ri = input_->height-2; ri >= 0; --ri) 00357 { 00358 for (int ci = input_->width-2; ci >= 0; --ci) 00359 { 00360 const float lowerLeft = distanceMap[(ri+1)*input_->width + ci-1] + 1.4f; 00361 const float lower = distanceMap[(ri+1)*input_->width + ci] + 1.0f; 00362 const float lowerRight = distanceMap[(ri+1)*input_->width + ci+1] + 1.4f; 00363 const float right = distanceMap[ri*input_->width + ci+1] + 1.0f; 00364 const float center = distanceMap[ri*input_->width + ci]; 00365 00366 const float minValue = std::min (std::min (lowerLeft, lower), std::min (right, lowerRight)); 00367 00368 if (minValue < center) 00369 distanceMap[ri*input_->width + ci] = minValue; 00370 } 00371 } 00372 00373 // Set all normals that we do not touch to NaN 00374 for (size_t ri = 0; ri < normal_smoothing_size_; ++ri) 00375 { 00376 for (size_t ci = 0; ci < input_->width; ++ci) 00377 { 00378 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00379 output (ci, ri).curvature = bad_point; 00380 } 00381 } 00382 for (size_t ri = normal_smoothing_size_; ri < input_->height; ++ri) 00383 { 00384 for (size_t ci = 0; ci < normal_smoothing_size_; ++ci) 00385 { 00386 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00387 output (ci, ri).curvature = bad_point; 00388 } 00389 } 00390 00391 for (size_t ri = input_->height - normal_smoothing_size_; ri < input_->height; ++ri) 00392 { 00393 for (size_t ci = normal_smoothing_size_; ci < input_->width; ++ci) 00394 { 00395 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00396 output (ci, ri).curvature = bad_point; 00397 } 00398 } 00399 00400 for (size_t ri = normal_smoothing_size_; ri < input_->height - normal_smoothing_size_; ++ri) 00401 { 00402 for (size_t ci = input_->width - normal_smoothing_size_; ci < input_->width; ++ci) 00403 { 00404 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00405 output (ci, ri).curvature = bad_point; 00406 } 00407 } 00408 00409 if (use_depth_dependent_smoothing_) 00410 { 00411 for (int ri = normal_smoothing_size_; ri < input_->height-normal_smoothing_size_; ++ri) 00412 { 00413 for (int ci = normal_smoothing_size_; ci < input_->width-normal_smoothing_size_; ++ci) 00414 { 00415 const float depth = (*input_)(ci, ri).z; 00416 if (!pcl_isfinite (depth)) 00417 { 00418 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00419 output (ci, ri).curvature = bad_point; 00420 continue; 00421 } 00422 00423 float smoothing = (std::min)(distanceMap[ri*input_->width + ci], normal_smoothing_size_ + static_cast<float>(depth)/10.0f); 00424 00425 if (smoothing > 2.0f) 00426 { 00427 setRectSize (smoothing, smoothing); 00428 computePointNormal (ci, ri, output (ci, ri)); 00429 } 00430 else 00431 { 00432 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00433 output (ci, ri).curvature = bad_point; 00434 } 00435 } 00436 } 00437 } 00438 else 00439 { 00440 float smoothing_constant = normal_smoothing_size_ * static_cast<float>(1.0f) / (500.0f * 0.001f); 00441 for (int ri = normal_smoothing_size_; ri < input_->height-normal_smoothing_size_; ++ri) 00442 { 00443 for (int ci = normal_smoothing_size_; ci < input_->width-normal_smoothing_size_; ++ci) 00444 { 00445 if (!pcl_isfinite ((*input_) (ci, ri).z)) 00446 { 00447 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00448 output (ci, ri).curvature = bad_point; 00449 continue; 00450 } 00451 00452 float smoothing = (std::min)(distanceMap[ri*input_->width + ci], smoothing_constant); 00453 00454 if (smoothing > 2.0f) 00455 { 00456 setRectSize (smoothing, smoothing); 00457 computePointNormal (ci, ri, output (ci, ri)); 00458 } 00459 else 00460 { 00461 output (ci, ri).getNormalVector4fMap ().setConstant (bad_point); 00462 output (ci, ri).curvature = bad_point; 00463 } 00464 } 00465 } 00466 } 00467 00468 delete[] depthChangeMap; 00469 delete[] distanceMap; 00470 } 00471 00472 #define PCL_INSTANTIATE_IntegralImageNormalEstimation(T,NT) template class PCL_EXPORTS pcl::IntegralImageNormalEstimation<T,NT>; 00473 00474 #endif 00475
1.7.6.1