00001 
00063 #ifndef __IMPL_ORGANIZED_NORMAL_ESTIMATION_H__
00064 #define __IMPL_ORGANIZED_NORMAL_ESTIMATION_H__
00065 
00066 
00067 #include "cob_3d_mapping_common/label_defines.h"
00068 #include "cob_3d_features/organized_normal_estimation.h"
00069 #include <pcl/common/eigen.h>
00070 
00071 template <typename PointT, typename LabelT> void
00072 cob_3d_features::OrganizedNormalEstimationHelper::computeSegmentNormal(
00073   Eigen::Vector3f& normal_out,
00074   int index,
00075   boost::shared_ptr<const pcl::PointCloud<PointT> > surface,
00076   boost::shared_ptr<const pcl::PointCloud<LabelT> > labels,
00077   int r, int steps)
00078 {
00079   const int w = surface->width, s = surface->height * surface->width;
00080   const int l_idx = labels->points[index].label;
00081 
00082   
00083   const int w_rem = index%w;
00084   const int x_max = std::min(2*r, r + w - w_rem - 1); 
00085   const int y_min = std::max(index - r*w - r, w_rem - r);
00086   const int y_max = std::min(index + r*w - r, s - (w - w_rem) - r);
00087   Eigen::Matrix<float, 1, 9, Eigen::RowMajor> accu = Eigen::Matrix<float, 1, 9, Eigen::RowMajor>::Zero();
00088   int point_count = 0;
00089   for (int y = y_min; y <= y_max; y += steps*w) 
00090   {
00091     for (int idx = y; idx < y + x_max; idx+=steps)
00092     {
00093       if (labels->points[idx].label != l_idx) { idx = idx - steps + 1; continue; }
00094       PointT const* p_idx = &(surface->points[idx]);
00095       if (pcl_isnan(p_idx->z)) { idx = idx - steps + 1; continue; }
00096 
00097       accu[0] += p_idx->x * p_idx->x;
00098       accu[1] += p_idx->x * p_idx->y;
00099       accu[2] += p_idx->x * p_idx->z;
00100       accu[3] += p_idx->y * p_idx->y;
00101       accu[4] += p_idx->y * p_idx->z;
00102       accu[5] += p_idx->z * p_idx->z;
00103       accu[6] += p_idx->x;
00104       accu[7] += p_idx->y;
00105       accu[8] += p_idx->z;
00106       ++point_count;
00107     }
00108     if (point_count == 0) { y = y - steps*w + w; }
00109   }
00110   
00111 
00112 
00113 
00114 
00115 
00116   if (accu[0] == 0 && accu[3] == 0 && accu[5] == 0)
00117   {
00118     std::cout <<"[NormalEstimation]: null normal!" << std::endl;
00119     normal_out(0) = normal_out(1) = normal_out(2) = std::numeric_limits<float>::quiet_NaN();
00120     return;
00121   }
00122   accu /= static_cast<float>(point_count);
00123 
00124   Eigen::Matrix3f cov;
00125   cov.coeffRef(0) =                   accu(0) - accu(6) * accu(6);
00126   cov.coeffRef(1) = cov.coeffRef(3) = accu(1) - accu(6) * accu(7);
00127   cov.coeffRef(2) = cov.coeffRef(6) = accu(2) - accu(6) * accu(8);
00128   cov.coeffRef(4) =                   accu(3) - accu(7) * accu(7);
00129   cov.coeffRef(5) = cov.coeffRef(7) = accu(4) - accu(7) * accu(8);
00130   cov.coeffRef(8) =                   accu(5) - accu(8) * accu(8);
00131   Eigen::Vector3f eigenvalues;
00132   Eigen::Matrix3f eigenvectors;
00133   pcl::eigen33(cov, eigenvectors, eigenvalues);
00134   if ( surface->points[index].getVector3fMap().dot(eigenvectors.col(0)) > 0)
00135     normal_out = eigenvectors.col(0) * (-1);
00136   else
00137     normal_out = eigenvectors.col(0);
00138 }
00139 
00140 template <typename PointInT, typename PointOutT, typename LabelOutT> void
00141 cob_3d_features::OrganizedNormalEstimation<PointInT,PointOutT,LabelOutT>::recomputeSegmentNormal (
00142   PointCloudInConstPtr cloud_in,
00143   LabelCloudOutConstPtr label_in,
00144   int index,
00145   float& n_x,
00146   float& n_y,
00147   float& n_z)
00148 {
00149   Eigen::Vector3f p = cloud_in->points[index].getVector3fMap();
00150   if (pcl_isnan(p(2)))
00151   {
00152     n_x = n_y = n_z = std::numeric_limits<float>::quiet_NaN();
00153     return;
00154   }
00155 
00156 
00157   int idx, max_gap, gap, init_gap, n_normals = 0;
00158   int idx_x = index % cloud_in->width;
00159   int idx_y = index / cloud_in->width;
00160   int l_idx = label_in->points[index].label;
00161 
00162   bool has_prev_point;
00163 
00164   Eigen::Vector3f p_curr;
00165   Eigen::Vector3f p_prev(0,0,0);
00166   Eigen::Vector3f p_first(0,0,0);
00167   Eigen::Vector3f n_idx(0,0,0);
00168 
00169   std::vector<std::vector<int> >::iterator it_c; 
00170   std::vector<int>::iterator it_ci; 
00171 
00172   
00173   if (idx_y >= pixel_search_radius_ && idx_y < (int)cloud_in->height - pixel_search_radius_ &&
00174       idx_x >= pixel_search_radius_ && idx_x < (int)cloud_in->width - pixel_search_radius_)
00175   {
00176     for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c) 
00177     {
00178       has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size(); 
00179 
00180       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) 
00181       {
00182         idx = index + *it_ci;
00183         
00184         Eigen::Vector3f p_i = cloud_in->points[idx].getVector3fMap();
00185         if ( pcl_isnan(p_i(2)) || label_in->points[idx].label != l_idx) { ++gap; continue; } 
00186         if ( gap <= max_gap && has_prev_point ) 
00187         {
00188           p_curr = p_i - p;
00189           n_idx += (p_prev.cross(p_curr)).normalized(); 
00190           ++n_normals;
00191           p_prev = p_curr;
00192         }
00193         else 
00194         {
00195           p_prev = p_i - p;
00196           if (!has_prev_point)
00197           {
00198             p_first = p_prev; 
00199             init_gap = gap; 
00200             has_prev_point = true;
00201           }
00202         }
00203         gap = 0; 
00204       }
00205 
00206       
00207       if (gap + init_gap <= max_gap)
00208       {
00209         
00210         n_idx += (p_prev.cross(p_first)).normalized();
00211         ++n_normals;
00212       }
00213     } 
00214   }
00215   else
00216   {
00217     for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c) 
00218     {
00219       has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size(); 
00220 
00221       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) 
00222       {
00223         idx = index + *it_ci;
00224         
00225         if ( idx < 0 || idx >= (int)cloud_in->points.size() ) { continue; }
00226         int v = idx * inv_width_; 
00227         if ( v < 0 || v >= (int)cloud_in->height ) { continue; }
00228         Eigen::Vector3f p_i = cloud_in->points[idx].getVector3fMap();
00229         if ( pcl_isnan(p_i(2)) || label_in->points[idx].label != l_idx) { ++gap; continue; } 
00230         if ( gap <= max_gap && has_prev_point ) 
00231         {
00232           p_curr = p_i - p;
00233           n_idx += (p_prev.cross(p_curr)).normalized(); 
00234           ++n_normals;
00235           p_prev = p_curr;
00236         }
00237         else 
00238         {
00239           p_prev = p_i - p;
00240           if (!has_prev_point)
00241           {
00242             p_first = p_prev; 
00243             init_gap = gap; 
00244             has_prev_point = true;
00245           }
00246         }
00247         gap = 0; 
00248       }
00249 
00250       
00251       if (gap + init_gap <= max_gap)
00252       {
00253         
00254         n_idx += (p_prev.cross(p_first)).normalized();
00255         ++n_normals;
00256       }
00257     } 
00258   }
00259 
00260   n_idx /= (float)n_normals;
00261   n_idx = n_idx.normalized();
00262   n_x = n_idx(0);
00263   n_y = n_idx(1);
00264   n_z = n_idx(2);
00265 }
00266 
00267 
00268 template <typename PointInT, typename PointOutT, typename LabelOutT> void
00269 cob_3d_features::OrganizedNormalEstimation<PointInT,PointOutT,LabelOutT>::computePointNormal (
00270   const PointCloudIn &cloud,
00271   int index,
00272   float &n_x,
00273   float &n_y,
00274   float &n_z,
00275   int &label_out)
00276 {
00277   Eigen::Vector3f p = cloud.points[index].getVector3fMap();
00278   if (p(2) != p(2))
00279   {
00280     n_x = n_y = n_z = std::numeric_limits<float>::quiet_NaN();
00281     label_out = I_NAN;
00282     return;
00283   }
00284 
00285   int idx, max_gap, gap, init_gap, n_normals = 0;
00286   int idx_x = index % input_->width;
00287   int idx_y = index * inv_width_;
00288 
00289   float distance_threshold = skip_distant_point_threshold_ * 0.003 * p(2) * p(2);
00290 
00291   bool has_prev_point;
00292 
00293   
00294   Eigen::Vector3f p_curr;
00295   Eigen::Vector3f p_prev(0,0,0);
00296   Eigen::Vector3f p_first(0,0,0);
00297   Eigen::Vector3f n_idx(0,0,0);
00298 
00299   std::vector<std::vector<int> >::iterator it_c; 
00300   std::vector<int>::iterator it_ci; 
00301   
00302 
00303   
00304   if (idx_y >= pixel_search_radius_ && idx_y < (int)cloud.height - pixel_search_radius_ &&
00305       idx_x >= pixel_search_radius_ && idx_x < (int)cloud.width - pixel_search_radius_)
00306   {
00307     for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c) 
00308     {
00309       has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size(); 
00310 
00311       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) 
00312       {
00313         idx = index + *it_ci;
00314         Eigen::Vector3f p_i = cloud.points[idx].getVector3fMap();
00315         if ( p_i(2) != p_i(2) || fabs(p_i(2) - p(2)) > distance_threshold ) { ++gap; continue; } 
00316         
00317         if ( gap <= max_gap && has_prev_point ) 
00318         {
00319           p_curr = p_i - p;
00320           n_idx += (p_prev.cross(p_curr)).normalized(); 
00321           ++n_normals;
00322           p_prev = p_curr;
00323         }
00324         else 
00325         {
00326           p_prev = p_i - p;
00327           if (!has_prev_point)
00328           {
00329             p_first = p_prev; 
00330             init_gap = gap; 
00331             has_prev_point = true;
00332           }
00333         }
00334         gap = 0; 
00335       }
00336 
00337       
00338       if (gap + init_gap <= max_gap)
00339       {
00340         
00341         n_idx += (p_prev.cross(p_first)).normalized();
00342         ++n_normals;
00343       }
00344     } 
00345   }
00346   else
00347   {
00348     for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c) 
00349     {
00350       has_prev_point = false; gap = 0; max_gap = 0.25 * (*it_c).size(); 
00351 
00352       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) 
00353       {
00354         idx = index + *it_ci;
00355         
00356         if ( idx < 0 || idx >= (int)cloud.points.size() ) { ++gap; continue; } 
00357         int v = idx * inv_width_; 
00358         if ( v < 0 || v >= (int)cloud.height || cloud.points[idx].z != cloud.points[idx].z) { ++gap; continue; } 
00359         Eigen::Vector3f p_i = cloud.points[idx].getVector3fMap();
00360         if ( fabs(p_i(2) - p(2)) > distance_threshold ) { ++gap;  continue; }  
00361         if ( gap <= max_gap && has_prev_point) 
00362         {
00363           p_curr = p_i - p;
00364           n_idx += (p_prev.cross(p_curr)).normalized(); 
00365           ++n_normals;
00366           p_prev = p_curr;
00367         }
00368         else 
00369         {
00370           p_prev = p_i - p;
00371           if (!has_prev_point)
00372           {
00373             p_first = p_prev; 
00374             init_gap = gap; 
00375             has_prev_point = true;
00376           }
00377         }
00378         gap = 0; 
00379       }
00380 
00381       
00382       if ( gap + init_gap <= max_gap)
00383       {
00384         
00385         n_idx += (p_prev.cross(p_first)).normalized();
00386         ++n_normals;
00387       }
00388     } 
00389   }
00390 
00391   
00392 
00393   
00394   
00395   n_idx.normalize();
00396   n_x = n_idx(0);
00397   n_y = n_idx(1);
00398   n_z = n_idx(2);
00399 }
00400 
00401 template <typename PointInT, typename PointOutT, typename LabelOutT> void
00402 cob_3d_features::OrganizedNormalEstimation<PointInT,PointOutT,LabelOutT>::computeFeature (PointCloudOut &output)
00403 {
00404   if (labels_->points.size() != input_->size())
00405   {
00406     labels_->points.resize(input_->size());
00407     labels_->height = input_->height;
00408     labels_->width = input_->width;
00409   }
00410 
00411   for (std::vector<int>::iterator it=indices_->begin(); it != indices_->end(); ++it)
00412   {
00413     labels_->points[*it].label = I_UNDEF;
00414     computePointNormal(*surface_, *it,
00415                        output.points[*it].normal[0],
00416                        output.points[*it].normal[1],
00417                        output.points[*it].normal[2],
00418                        labels_->points[*it].label);
00419   }
00420 }
00421 
00422 #define PCL_INSTANTIATE_OrganizedNormalEstimation(T,OutT,LabelT) template class PCL_EXPORTS cob_3d_features::OrganizedNormalEstimation<T,OutT,LabelT>;
00423 
00424 #endif