organized_normal_estimation.hpp
Go to the documentation of this file.
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   // compute mask boundary constrains first,
00083   const int w_rem = index%w;
00084   const int x_max = std::min(2*r, r + w - w_rem - 1); // max offset at each line
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) // y: beginning of each line
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   /*if (point_count <= 1)
00111   {
00112     std::cout << "Still to less valid points" << std::endl;
00113     //normal_out(0) = normal_out(1) = normal_out(2) = std::numeric_limits<float>::quiet_NaN();
00114     //return;
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; // circle iterator
00170   std::vector<int>::iterator it_ci; // points in circle iterator
00171 
00172   // check where query point is and use out-of-image validation for neighbors or not
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) // iterate circles
00177     {
00178       has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size(); // reset loop
00179 
00180       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) // iterate current circle
00181       {
00182         idx = index + *it_ci;
00183         //std::cout << idx % cloud_in->width << " / " << idx / cloud_in->width << std::endl;
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; } // count as gap point
00186         if ( gap <= max_gap && has_prev_point ) // check gap is small enough and a previous point exists
00187         {
00188           p_curr = p_i - p;
00189           n_idx += (p_prev.cross(p_curr)).normalized(); // compute normal of p_prev and p_curr
00190           ++n_normals;
00191           p_prev = p_curr;
00192         }
00193         else // current is first point in circle or just after a gap
00194         {
00195           p_prev = p_i - p;
00196           if (!has_prev_point)
00197           {
00198             p_first = p_prev; // remember the first valid point in circle
00199             init_gap = gap; // save initial gap size
00200             has_prev_point = true;
00201           }
00202         }
00203         gap = 0; // found valid point, reset gap counter
00204       }
00205 
00206       // close current circle (last and first point) if gap is small enough
00207       if (gap + init_gap <= max_gap)
00208       {
00209         // compute normal of p_first and p_prev
00210         n_idx += (p_prev.cross(p_first)).normalized();
00211         ++n_normals;
00212       }
00213     } // end loop of circles
00214   }
00215   else
00216   {
00217     for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c) // iterate circles
00218     {
00219       has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size(); // reset loop
00220 
00221       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) // iterate current circle
00222       {
00223         idx = index + *it_ci;
00224         //std::cout << idx % cloud_in->width << " / " << idx / cloud_in->width << std::endl;
00225         if ( idx < 0 || idx >= (int)cloud_in->points.size() ) { continue; }
00226         int v = idx * inv_width_; // calculate y coordinate in image, // check left, right border
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; } // count as gap point
00230         if ( gap <= max_gap && has_prev_point ) // check gap is small enough and a previous point exists
00231         {
00232           p_curr = p_i - p;
00233           n_idx += (p_prev.cross(p_curr)).normalized(); // compute normal of p_prev and p_curr
00234           ++n_normals;
00235           p_prev = p_curr;
00236         }
00237         else // current is first point in circle or just after a gap
00238         {
00239           p_prev = p_i - p;
00240           if (!has_prev_point)
00241           {
00242             p_first = p_prev; // remember the first valid point in circle
00243             init_gap = gap; // save initial gap size
00244             has_prev_point = true;
00245           }
00246         }
00247         gap = 0; // found valid point, reset gap counter
00248       }
00249 
00250       // close current circle (last and first point) if gap is small enough
00251       if (gap + init_gap <= max_gap)
00252       {
00253         // compute normal of p_first and p_prev
00254         n_idx += (p_prev.cross(p_first)).normalized();
00255         ++n_normals;
00256       }
00257     } // end loop of circles
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)/*pcl_isnan(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   //std::vector<int> range_border_counter(mask_.size(), 0);
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; // circle iterator
00300   std::vector<int>::iterator it_ci; // points in circle iterator
00301   //std::vector<int>::iterator it_rbc = range_border_counter.begin();
00302 
00303   // check where query point is and use out-of-image validation for neighbors or not
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/*, ++it_rbc*/) // iterate circles
00308     {
00309       has_prev_point = false; init_gap = gap = 0; max_gap = 0.25 * (*it_c).size(); // reset loop
00310 
00311       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) // iterate current circle
00312       {
00313         idx = index + *it_ci;
00314         Eigen::Vector3f p_i = cloud.points[idx].getVector3fMap();
00315         if ( p_i(2) != p_i(2)/*pcl_isnan(p_i(2))*/ || fabs(p_i(2) - p(2)) > distance_threshold ) { ++gap; continue; } // count as gap point
00316         //if (  ) { ++gap; /*++(*it_rbc);*/ continue; }  // count as gap point
00317         if ( gap <= max_gap && has_prev_point ) // check gap is small enough and a previous point exists
00318         {
00319           p_curr = p_i - p;
00320           n_idx += (p_prev.cross(p_curr)).normalized(); // compute normal of p_prev and p_curr
00321           ++n_normals;
00322           p_prev = p_curr;
00323         }
00324         else // current is first point in circle or just after a gap
00325         {
00326           p_prev = p_i - p;
00327           if (!has_prev_point)
00328           {
00329             p_first = p_prev; // remember the first valid point in circle
00330             init_gap = gap; // save initial gap size
00331             has_prev_point = true;
00332           }
00333         }
00334         gap = 0; // found valid point, reset gap counter
00335       }
00336 
00337       // close current circle (last and first point) if gap is small enough
00338       if (gap + init_gap <= max_gap)
00339       {
00340         // compute normal of p_first and p_prev
00341         n_idx += (p_prev.cross(p_first)).normalized();
00342         ++n_normals;
00343       }
00344     } // end loop of circles
00345   }
00346   else
00347   {
00348     for (it_c = mask_.begin(); it_c != mask_.end(); ++it_c/*, ++it_rbc*/) // iterate circles
00349     {
00350       has_prev_point = false; gap = 0; max_gap = 0.25 * (*it_c).size(); // reset circle loop
00351 
00352       for (it_ci = (*it_c).begin(); it_ci != (*it_c).end(); ++it_ci) // iterate current circle
00353       {
00354         idx = index + *it_ci;
00355         // check top and bottom image border
00356         if ( idx < 0 || idx >= (int)cloud.points.size() ) { ++gap; continue; } // count as gap point
00357         int v = idx * inv_width_; // calculate y coordinate in image, // check left, right border
00358         if ( v < 0 || v >= (int)cloud.height || /*pcl_isnan(cloud.points[idx].z)*/cloud.points[idx].z != cloud.points[idx].z) { ++gap; continue; } // count as gap point
00359         Eigen::Vector3f p_i = cloud.points[idx].getVector3fMap();
00360         if ( fabs(p_i(2) - p(2)) > distance_threshold ) { ++gap; /*++(*it_rbc);*/ continue; }  // count as gap point
00361         if ( gap <= max_gap && has_prev_point) // check gap is small enough and a previous point exists
00362         {
00363           p_curr = p_i - p;
00364           n_idx += (p_prev.cross(p_curr)).normalized(); // compute normal of p_prev and p_curr
00365           ++n_normals;
00366           p_prev = p_curr;
00367         }
00368         else // current is first point in circle or just after a gap
00369         {
00370           p_prev = p_i - p;
00371           if (!has_prev_point)
00372           {
00373             p_first = p_prev; // remember the first valid point in circle
00374             init_gap = gap; // save initial gap size
00375             has_prev_point = true;
00376           }
00377         }
00378         gap = 0; // found valid point, reset gap counter
00379       }
00380 
00381       // close current circle (last and first point) if gap is small enough
00382       if ( gap + init_gap <= max_gap)
00383       {
00384         // compute normal of p_first and p_prev
00385         n_idx += (p_prev.cross(p_first)).normalized();
00386         ++n_normals;
00387       }
00388     } // end loop of circles
00389   }
00390 
00391   //if (range_border_counter[mask_.size()-1] > 0) label_out = I_BORDER;
00392 
00393   //n_idx /= (float)n_normals;
00394   //n_idx = n_idx.normalized();
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


cob_3d_features
Author(s): Georg Arbeiter
autogenerated on Wed Aug 26 2015 11:02:26