Point Cloud Library (PCL)  1.4.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
organized.hpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (BSD License)
00003  *
00004  *  Point Cloud Library (PCL) - www.pointclouds.org
00005  *  Copyright (c) 2010-2011, Willow Garage, Inc.
00006  *
00007  *  All rights reserved.
00008  *
00009  *  Redistribution and use in source and binary forms, with or without
00010  *  modification, are permitted provided that the following conditions
00011  *  are met:
00012  *
00013  *   * Redistributions of source code must retain the above copyright
00014  *     notice, this list of conditions and the following disclaimer.
00015  *   * Redistributions in binary form must reproduce the above
00016  *     copyright notice, this list of conditions and the following
00017  *     disclaimer in the documentation and/or other materials provided
00018  *     with the distribution.
00019  *   * Neither the name of Willow Garage, Inc. nor the names of its
00020  *     contributors may be used to endorse or promote products derived
00021  *     from this software without specific prior written permission.
00022  *
00023  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00024  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00025  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00026  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00027  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00028  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00029  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00030  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00031  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00033  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00034  *  POSSIBILITY OF SUCH DAMAGE.
00035  *
00036  * $Id: organized.hpp 3749 2011-12-31 22:58:01Z rusu $
00037  *
00038  */
00039 
00040 #ifndef PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_
00041 #define PCL_SEARCH_IMPL_ORGANIZED_NEIGHBOR_SEARCH_H_
00042 
00043 #include "pcl/search/organized.h"
00044 
00046 template<typename PointT> int
00047 pcl::search::OrganizedNeighbor<PointT>::radiusSearch (const PointCloudConstPtr    &cloud, 
00048                                                       int                         index,
00049                                                       double                      radius, 
00050                                                       std::vector<int>            &k_indices,
00051                                                       std::vector<float>          &k_sqr_distances, 
00052                                                       int                         max_nn)
00053 {
00054   this->setInputCloud (cloud);
00055   return (radiusSearch (index, radius, k_indices, k_sqr_distances, max_nn));
00056 }
00057 
00059 template<typename PointT> int
00060 pcl::search::OrganizedNeighbor<PointT>::radiusSearch (int                 index, 
00061                                                       const double        radius,
00062                                                       std::vector<int>    &k_indices,
00063                                                       std::vector<float>  &k_sqr_distances, 
00064                                                       int                 max_nn) const
00065 {
00066   const PointT searchPoint = getPointByIndex (index);
00067   return (radiusSearch (searchPoint, radius, k_indices, k_sqr_distances, max_nn));
00068 }
00069 
00071 template<typename PointT> int
00072 pcl::search::OrganizedNeighbor<PointT>::radiusSearch (const               PointT &p_q, 
00073                                                       const double        radius,
00074                                                       std::vector<int>    &k_indices,
00075                                                       std::vector<float>  &k_sqr_distances, 
00076                                                       int                 max_nn) const
00077 {
00078   if (input_->height == 1 || input_->width == 1)
00079   {
00080     PCL_ERROR ("[pcl::%s::radiusSearch] Input dataset is not organized!\n", getName ().c_str ());
00081     return (0);
00082   }
00083 
00084   // NAN test
00085   if (!pcl_isfinite (p_q.x) || !pcl_isfinite (p_q.y) || !pcl_isfinite (p_q.z))
00086     return (0);
00087 
00088   // search window
00089   int leftX, rightX, leftY, rightY;
00090   int x, y, idx;
00091   double squared_distance, squared_radius;
00092   int nnn;
00093 
00094   k_indices.clear ();
00095   k_sqr_distances.clear ();
00096 
00097   squared_radius = radius * radius;
00098 
00099   this->getProjectedRadiusSearchBox (p_q, squared_radius, leftX, rightX, leftY, rightY);
00100 
00101   // iterate over search box
00102   nnn = 0;
00103   for (x = leftX; (x <= rightX) && (nnn < max_nn); x++)
00104   {
00105     for (y = leftY; (y <= rightY) && (nnn < max_nn); y++)
00106     {
00107       idx = y * input_->width + x;
00108       const PointT& point = input_->points[idx];
00109 
00110       const double point_dist_x = point.x - p_q.x;
00111       const double point_dist_y = point.y - p_q.y;
00112       const double point_dist_z = point.z - p_q.z;
00113 
00114       // calculate squared distance
00115       squared_distance = (point_dist_x * point_dist_x + point_dist_y * point_dist_y + point_dist_z * point_dist_z);
00116 
00117       // check distance and add to results
00118       if (squared_distance <= squared_radius)
00119       {
00120         k_indices.push_back (idx);
00121         k_sqr_distances.push_back (squared_distance);
00122         nnn++;
00123       }
00124     }
00125   }
00126   return (nnn);
00127 }
00128 
00130 template<typename PointT> int
00131 pcl::search::OrganizedNeighbor<PointT>::exactNearestKSearch (int                 index, 
00132                                                              int                 k, 
00133                                                              std::vector<int>    &k_indices,
00134                                                              std::vector<float>  &k_sqr_distances)
00135 {
00136   const PointT searchPoint = getPointByIndex (index);
00137   return (exactNearestKSearch (searchPoint, k, k_indices, k_sqr_distances));
00138 }
00139 
00141 template<typename PointT> int
00142 pcl::search::OrganizedNeighbor<PointT>::nearestKSearch (const pcl::PointCloud<PointT> &cloud, 
00143                                                         int                           index,
00144                                                         int                           k, 
00145                                                         std::vector<int>              &k_indices,
00146                                                         std::vector<float>            &k_sqr_distances)
00147 {
00148   if (!exactFocalLength_)
00149   {
00150     estimateFocalLengthFromInputCloud (cloud);
00151     generateRadiusLookupTable (cloud.width, cloud.height);
00152     exactFocalLength_ = 1;
00153   }
00154   return (exactNearestKSearch (index, k, k_indices, k_sqr_distances));
00155 }
00156 
00158 template<typename PointT> int
00159 pcl::search::OrganizedNeighbor<PointT>::exactNearestKSearch (const PointT &p_q, 
00160                                                              int k,
00161                                                              std::vector<int> &k_indices,
00162                                                              std::vector<float> &k_sqr_distances)
00163 {
00164   PCL_ERROR ("[pcl::search::OrganizedNeighbor::exactNearestKSearch] Method not implemented!\n");
00165   return (0);
00166 }
00167 
00169 template<typename PointT> int
00170 pcl::search::OrganizedNeighbor<PointT>::nearestKSearch (int index, 
00171                                                         int k,
00172                                                         std::vector<int> &k_indices,
00173                                                         std::vector<float> &k_distances)
00174 {
00175   if (!input_)
00176   {
00177     PCL_ERROR ("[pcl::%s::approxNearestKSearch] Input dataset was not set! use setInputCloud before continuing.\n", getName ().c_str ());
00178     return (0);
00179   }
00180 
00181   k_indices.resize (k);
00182   if (!input_->isOrganized ())
00183   {
00184     PCL_ERROR ("[pcl::%s::approxNearestKSearch] Input dataset is not organized!\n", getName ().c_str ());
00185     return (0);
00186   }
00187   int data_size = input_->points.size ();
00188   if (index >= data_size)
00189     return (0);
00190 
00191   // Get the cloud width
00192   int width = input_->width;
00193 
00194   // Obtain the <u,v> pixel values
00195   int u = index / width;
00196   int v = index % width;
00197 
00198   int l = -1, idx, uwv = u * width + v, uwvx;
00199 
00200   // Save the query point as the first neighbor (*ANN compatibility)
00201   k_indices[++l] = index;
00202 
00203   if (horizontal_window_ == 0 || vertical_window_)
00204     setSearchWindowAsK (k);
00205 
00206   // Get all point neighbors in a H x V window
00207 
00208   for (int x = -horizontal_window_; x != horizontal_window_; ++x)
00209   {
00210     uwvx = uwv + x * width; // Get the correct index
00211 
00212     for (int y = -vertical_window_; y != vertical_window_; ++y)
00213     {
00214       // idx = (u+x) * cloud.width + (v+y);
00215       idx = uwvx + y;
00216 
00217       // If the index is not in the point cloud, continue
00218       if (idx == index || idx < 0 || idx >= data_size)
00219         continue;
00220 
00221       if (max_distance_ != 0)
00222       {
00223         if (fabs (input_->points[index].z - input_->points[index].z) < max_distance_)
00224           k_indices[++l] = idx;
00225       }
00226       else
00227         k_indices[++l] = idx;
00228     }
00229   }
00230   // We need at least min_pts_ nearest neighbors to do something useful with them
00231   if (l < min_pts_)
00232     return (0);
00233   return (k);
00234 }
00235 
00236 
00238 template<typename PointT> void
00239 pcl::search::OrganizedNeighbor<PointT>::getProjectedRadiusSearchBox (const PointT& point,
00240                                                                      double squared_radius, 
00241                                                                      int &minX,
00242                                                                      int &maxX, 
00243                                                                      int &minY, 
00244                                                                      int & maxY) const
00245 {
00246   double r_sqr, r_quadr, z_sqr;
00247   double sqrt_term_y, sqrt_term_x, norm;
00248   double x_times_z, y_times_z;
00249   double x1, x2, y1, y2;
00250   double term_x, term_y;
00251 
00252   // see http://www.wolframalpha.com/input/?i=solve+%5By%2Fsqrt%28f^2%2By^2%29*c-f%2Fsqrt%28f^2%2By^2%29*b%2Br%3D%3D0%2C+f%3D1%2C+y%5D
00253   // where b = p_q.y, c = p_q.z, r = radius, f = oneOverFocalLength_
00254 
00255   r_sqr = squared_radius;
00256   r_quadr = r_sqr * r_sqr;
00257   z_sqr = point.z * point.z;
00258   norm = 1.0 / (z_sqr - r_sqr);
00259 
00260   // radius sphere projection on X axis
00261   term_x = point.x * point.x * r_sqr + z_sqr * r_sqr - r_quadr;
00262 
00263   // radius sphere projection on Y axis
00264   term_y = point.y * point.y * r_sqr + z_sqr * r_sqr - r_quadr;
00265 
00266   if ((term_x > 0) && (term_y > 0))
00267   {
00268     sqrt_term_x = sqrt (term_x);
00269 
00270     x_times_z = point.x * point.z;
00271 
00272     x1 = (x_times_z - sqrt_term_x) * norm;
00273     x2 = (x_times_z + sqrt_term_x) * norm;
00274 
00275     // determine 2-D search window
00276     minX = (int)floor ((double)input_->width / 2 + (x1 / oneOverFocalLength_));
00277     maxX = (int)ceil ((double)input_->width / 2 + (x2 / oneOverFocalLength_));
00278 
00279     // make sure the coordinates fit to point cloud resolution
00280     minX = std::max<int> (0, minX);
00281     maxX = std::min<int> ((int)input_->width - 1, maxX);
00282 
00283     sqrt_term_y = sqrt (term_y);
00284 
00285     y_times_z = point.y * point.z;
00286 
00287     y1 = (y_times_z - sqrt_term_y) * norm;
00288     y2 = (y_times_z + sqrt_term_y) * norm;
00289 
00290     // determine 2-D search window
00291     minY = (int)floor ((double)input_->height / 2 + (y1 / oneOverFocalLength_));
00292     maxY = (int)ceil ((double)input_->height / 2 + (y2 / oneOverFocalLength_));
00293 
00294     // make sure the coordinates fit to point cloud resolution
00295     minY = std::max<int> (0, minY);
00296     maxY = std::min<int> ((int)input_->height - 1, maxY);
00297   }
00298   else
00299   {
00300     // search point lies within search sphere
00301     minX = 0;
00302     maxX = (int)input_->width - 1;
00303 
00304     minY = 0;
00305     maxY = (int)input_->height - 1;
00306   }
00307 
00308 }
00309 
00311 template<typename PointT> double
00312 pcl::search::OrganizedNeighbor<PointT>::estimateFocalLengthFromInputCloud (const pcl::PointCloud<PointT> &cloud)
00313 {
00314   if (input_->height == 1 || input_->width == 1)
00315   {
00316     PCL_ERROR ("[pcl::%s::estimateFocalLenghtFromInputCloud] Input dataset is not organized!\n", getName ().c_str ());
00317     return (0.0);
00318   }
00319   size_t i, count;
00320   int x, y;
00321 
00322   oneOverFocalLength_ = 0;
00323 
00324   count = 0;
00325   for (y = 0; y < (int)input_->height; y++)
00326     for (x = 0; x < (int)input_->width; x++)
00327     {
00328       i = y * input_->width + x;
00329       if ((cloud.points[i].x == cloud.points[i].x) && // check for NaNs
00330           (cloud.points[i].y == cloud.points[i].y) && 
00331           (cloud.points[i].z == cloud.points[i].z))
00332       {
00333         const PointT& point = cloud.points[i];
00334         if ((double)(x - cloud.width / 2) * (double)(y - cloud.height / 2) * point.z != 0)
00335         {
00336           // estimate the focal length for point.x and point.y
00337           oneOverFocalLength_ += point.x / ((double)(x - (int)cloud.width / 2) * point.z);
00338           oneOverFocalLength_ += point.y / ((double)(y - (int)cloud.height / 2) * point.z);
00339           count += 2;
00340         }
00341       }
00342     }
00343   // calculate an average of the focalLength
00344   oneOverFocalLength_ /= (double)count;
00345   if (pcl_isfinite (oneOverFocalLength_))
00346     return (oneOverFocalLength_);
00347   else
00348   {
00349     PCL_ERROR ("[pcl::%s::estimateFocalLenghtFromInputCloud] Input dataset is not projectable!\n", getName ().c_str ());
00350     return (0.0);
00351   }
00352 }
00353 
00355 template<typename PointT> void
00356 pcl::search::OrganizedNeighbor<PointT>::generateRadiusLookupTable (unsigned int width, 
00357                                                                    unsigned int height)
00358 {
00359   int x, y, c;
00360 
00361   //check if point cloud dimensions changed
00362   if ((radiusLookupTableWidth_ != (int)width) || (radiusLookupTableHeight_ != (int)height))
00363   {
00364     radiusLookupTableWidth_ = (int)width;
00365     radiusLookupTableHeight_ = (int)height;
00366 
00367     radiusSearchLookup_.clear ();
00368     radiusSearchLookup_.resize ((2 * width + 1) * (2 * height + 1));
00369 
00370     c = 0;
00371     for (x = -(int)width; x < (int)width + 1; x++)
00372       for (y = -(int)height; y < (int)height + 1; y++)
00373         radiusSearchLookup_[c++].defineShiftedSearchPoint (x, y);
00374 
00375     std::sort (radiusSearchLookup_.begin (), radiusSearchLookup_.end ());
00376   }
00377 }
00378 
00380 template<typename PointT> const PointT&
00381 pcl::search::OrganizedNeighbor<PointT>::getPointByIndex (const unsigned int index) const
00382 {
00383   // retrieve point from input cloud
00384   return (this->input_->points[index]);
00385 }
00386 
00388 template<typename PointT> void
00389 pcl::search::OrganizedNeighbor<PointT>::setSearchWindowAsK (int k)
00390 {
00391   int hw = 0, vw = 0;
00392   while ((2 * hw + 1) * (2 * vw + 1) < k)
00393   {
00394     ++hw;
00395     ++vw;
00396   }
00397   horizontal_window_ = hw - 1;
00398   vertical_window_ = vw - 1;
00399 }
00400 
00401 #define PCL_INSTANTIATE_OrganizedNeighbor(T) template class PCL_EXPORTS pcl::search::OrganizedNeighbor<T>;
00402 
00403 #endif
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines