point.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2008 Radu Bogdan Rusu <rusu -=- cs.tum.edu>
00003  *
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *
00015  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00016  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00019  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00024  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00025  * POSSIBILITY OF SUCH DAMAGE.
00026  *
00027  * $Id$
00028  *
00029  */
00030 
00033 #include <algorithm>
00034 #include <cfloat>
00035 #include <door_handle_detector/geometry/point.h>
00036 #include <door_handle_detector/geometry/statistics.h>
00037 
00038 namespace cloud_geometry
00039 {
00040 
00042 
00046   int
00047     getChannelIndex (const sensor_msgs::PointCloud &points, std::string channel_name)
00048   {
00049     for (unsigned int d = 0; d < points.channels.size (); d++)
00050       if (points.channels[d].name == channel_name)
00051         return (d);
00052     return (-1);
00053   }
00054 
00056 
00060   int
00061     getChannelIndex (sensor_msgs::PointCloudConstPtr points, std::string channel_name)
00062   {
00063     for (unsigned int d = 0; d < points->channels.size (); d++)
00064       if (points->channels[d].name == channel_name)
00065         return (d);
00066     return (-1);
00067   }
00068 
00070 
00073   std::string
00074     getAvailableChannels (const sensor_msgs::PointCloud &cloud)
00075   {
00076     std::string result;
00077     if (cloud.channels.size () == 0)
00078       return (result);
00079     unsigned int i;
00080     for (i = 0; i < cloud.channels.size () - 1; i++)
00081     {
00082       std::string index = cloud.channels[i].name + " ";
00083       result += index;
00084     }
00085     std::string index = cloud.channels[i].name;
00086     result += index;
00087     return (result);
00088   }
00089 
00091 
00094   std::string
00095     getAvailableChannels (const sensor_msgs::PointCloudConstPtr& cloud)
00096   {
00097     std::string result;
00098     if (cloud->channels.size () == 0)
00099       return (result);
00100     unsigned int i;
00101     for (i = 0; i < cloud->channels.size () - 1; i++)
00102     {
00103       std::string index = cloud->channels[i].name + " ";
00104       result += index;
00105     }
00106     std::string index = cloud->channels[i].name;
00107     result += index;
00108     return (result);
00109   }
00110 
00112 
00121   void
00122     getPointIndicesAxisParallelNormals (const sensor_msgs::PointCloud &points, int nx, int ny, int nz, double eps_angle,
00123                                         const geometry_msgs::Point32 &axis, std::vector<int> &indices)
00124   {
00125     // Check all points
00126     for (unsigned int i = 0; i < points.points.size (); i++)
00127     {
00128       geometry_msgs::Point32 p;
00129       p.x = points.channels[nx].values[i];
00130       p.y = points.channels[ny].values[i];
00131       p.z = points.channels[nz].values[i];
00132       // Compute the angle between their normal and the given axis
00133       double angle = acos (dot (p, axis));
00134       if ( (angle < eps_angle) || ( (M_PI - angle) < eps_angle ) )
00135         indices.push_back (i);
00136     }
00137   }
00138 
00140 
00149   void
00150     getPointIndicesAxisPerpendicularNormals (const sensor_msgs::PointCloud &points, int nx, int ny, int nz, double eps_angle,
00151                                              const geometry_msgs::Point32 &axis, std::vector<int> &indices)
00152   {
00153     // Check all points
00154     for (unsigned int i = 0; i < points.points.size (); i++)
00155     {
00156       geometry_msgs::Point32 p;
00157       p.x = points.channels[nx].values[i];
00158       p.y = points.channels[ny].values[i];
00159       p.z = points.channels[nz].values[i];
00160       // Compute the angle between their normal and the given axis
00161       double angle = acos (dot (p, axis));
00162       if (fabs (M_PI / 2.0 - angle) < eps_angle)
00163         indices.push_back (i);
00164     }
00165   }
00166 
00168 
00176   void
00177     downsamplePointCloud (const sensor_msgs::PointCloud &points, const std::vector<int> &indices, sensor_msgs::PointCloud &points_down, geometry_msgs::Point leaf_size,
00178                           std::vector<Leaf> &leaves, int d_idx, double cut_distance)
00179   {
00180     if (d_idx == -1)
00181       cut_distance = DBL_MAX;
00182     // Copy the header (and thus the frame_id) + allocate enough space for points
00183     points_down.header = points.header;
00184     points_down.points.resize (points.points.size ());
00185 
00186     geometry_msgs::Point32 min_p, max_p, min_b, max_b, div_b;
00187     cloud_geometry::statistics::getMinMax (points, indices, min_p, max_p, d_idx, cut_distance);
00188 
00189     // Compute the minimum and maximum bounding box values
00190     min_b.x = (int)(floor (min_p.x / leaf_size.x));
00191     max_b.x = (int)(floor (max_p.x / leaf_size.x));
00192 
00193     min_b.y = (int)(floor (min_p.y / leaf_size.y));
00194     max_b.y = (int)(floor (max_p.y / leaf_size.y));
00195 
00196     min_b.z = (int)(floor (min_p.z / leaf_size.z));
00197     max_b.z = (int)(floor (max_p.z / leaf_size.z));
00198 
00199     // Compute the number of divisions needed along all axis
00200     div_b.x = (int)(max_b.x - min_b.x + 1);
00201     div_b.y = (int)(max_b.y - min_b.y + 1);
00202     div_b.z = (int)(max_b.z - min_b.z + 1);
00203 
00204     // Allocate the space needed
00205     try
00206     {
00207       if (leaves.capacity () < div_b.x * div_b.y * div_b.z)
00208         leaves.reserve (div_b.x * div_b.y * div_b.z);             // fallback to x*y*z from 2*x*y*z due to memory problems
00209       leaves.resize (div_b.x * div_b.y * div_b.z);
00210     }
00211     catch (std::bad_alloc)
00212     {
00213       ROS_ERROR ("Failed while attempting to allocate a vector of %f (%g x %g x %g) leaf elements (%f bytes total)", div_b.x * div_b.y * div_b.z,
00214                  div_b.x, div_b.y, div_b.z, div_b.x * div_b.y * div_b.z * sizeof (Leaf));
00215     }
00216 
00217     unsigned long leaves_size = div_b.x * div_b.y * div_b.z;
00218     if (leaves_size != leaves.size ())
00219       ROS_ERROR("That's odd: %lu != %zu", leaves_size, leaves.size());
00220     for (unsigned int cl = 0; cl < leaves_size; cl++)
00221     {
00222       if (leaves[cl].nr_points > 0)
00223       {
00224         leaves[cl].centroid_x = leaves[cl].centroid_y = leaves[cl].centroid_z = 0.0;
00225         leaves[cl].nr_points = 0;
00226       }
00227     }
00228 
00229     // First pass: go over all points and insert them into the right leaf
00230     for (unsigned int cp = 0; cp < indices.size (); cp++)
00231     {
00232       if (d_idx != -1 && points.channels[d_idx].values[indices.at (cp)] > cut_distance)        // Use a threshold for cutting out points which are too far away
00233         continue;
00234 
00235       int i = (int)(floor (points.points[indices.at (cp)].x / leaf_size.x));
00236       int j = (int)(floor (points.points[indices.at (cp)].y / leaf_size.y));
00237       int k = (int)(floor (points.points[indices.at (cp)].z / leaf_size.z));
00238 
00239       int idx = ( (k - min_b.z) * div_b.y * div_b.x ) + ( (j - min_b.y) * div_b.x ) + (i - min_b.x);
00240       leaves[idx].centroid_x += points.points[indices.at (cp)].x;
00241       leaves[idx].centroid_y += points.points[indices.at (cp)].y;
00242       leaves[idx].centroid_z += points.points[indices.at (cp)].z;
00243       leaves[idx].nr_points++;
00244     }
00245 
00246     // Second pass: go over all leaves and compute centroids
00247     int nr_p = 0;
00248     for (unsigned int cl = 0; cl < leaves_size; cl++)
00249     {
00250       if (leaves[cl].nr_points > 0)
00251       {
00252         points_down.points[nr_p].x = leaves[cl].centroid_x / leaves[cl].nr_points;
00253         points_down.points[nr_p].y = leaves[cl].centroid_y / leaves[cl].nr_points;
00254         points_down.points[nr_p].z = leaves[cl].centroid_z / leaves[cl].nr_points;
00255         nr_p++;
00256       }
00257     }
00258     points_down.points.resize (nr_p);
00259   }
00260 
00262 
00271   void
00272     downsamplePointCloud (const sensor_msgs::PointCloud &points, sensor_msgs::PointCloud &points_down, geometry_msgs::Point leaf_size,
00273                           std::vector<Leaf> &leaves, int d_idx, double cut_distance)
00274   {
00275     if (d_idx == -1)
00276       cut_distance = DBL_MAX;
00277     // Copy the header (and thus the frame_id) + allocate enough space for points
00278     points_down.header = points.header;
00279     points_down.points.resize (points.points.size ());
00280 
00281     geometry_msgs::Point32 min_p, max_p, min_b, max_b, div_b;
00282     cloud_geometry::statistics::getMinMax (points, min_p, max_p, d_idx, cut_distance);
00283 
00284     // Compute the minimum and maximum bounding box values
00285     min_b.x = (int)(floor (min_p.x / leaf_size.x));
00286     max_b.x = (int)(floor (max_p.x / leaf_size.x));
00287 
00288     min_b.y = (int)(floor (min_p.y / leaf_size.y));
00289     max_b.y = (int)(floor (max_p.y / leaf_size.y));
00290 
00291     min_b.z = (int)(floor (min_p.z / leaf_size.z));
00292     max_b.z = (int)(floor (max_p.z / leaf_size.z));
00293 
00294     // Compute the number of divisions needed along all axis
00295     div_b.x = (int)(max_b.x - min_b.x + 1);
00296     div_b.y = (int)(max_b.y - min_b.y + 1);
00297     div_b.z = (int)(max_b.z - min_b.z + 1);
00298 
00299     // Allocate the space needed
00300     try
00301     {
00302       if (leaves.capacity () < div_b.x * div_b.y * div_b.z)
00303         leaves.reserve (div_b.x * div_b.y * div_b.z);             // fallback to x*y*z from 2*x*y*z due to memory problems
00304       leaves.resize (div_b.x * div_b.y * div_b.z);
00305     }
00306     catch (std::bad_alloc)
00307     {
00308       ROS_ERROR ("Failed while attempting to allocate a vector of %f (%g x %g x %g) leaf elements (%f bytes total)", div_b.x * div_b.y * div_b.z,
00309                  div_b.x, div_b.y, div_b.z, div_b.x * div_b.y * div_b.z * sizeof (Leaf));
00310     }
00311 
00312     for (unsigned int cl = 0; cl < leaves.size (); cl++)
00313     {
00314       if (leaves[cl].nr_points > 0)
00315       {
00316         leaves[cl].centroid_x = leaves[cl].centroid_y = leaves[cl].centroid_z = 0.0;
00317         leaves[cl].nr_points = 0;
00318       }
00319     }
00320 
00321     // First pass: go over all points and insert them into the right leaf
00322     for (unsigned int cp = 0; cp < points.points.size (); cp++)
00323     {
00324       if (d_idx != -1 && points.channels[d_idx].values[cp] > cut_distance)        // Use a threshold for cutting out points which are too far away
00325         continue;
00326 
00327       int i = (int)(floor (points.points[cp].x / leaf_size.x));
00328       int j = (int)(floor (points.points[cp].y / leaf_size.y));
00329       int k = (int)(floor (points.points[cp].z / leaf_size.z));
00330 
00331       int idx = ( (k - min_b.z) * div_b.y * div_b.x ) + ( (j - min_b.y) * div_b.x ) + (i - min_b.x);
00332       leaves[idx].centroid_x += points.points[cp].x;
00333       leaves[idx].centroid_y += points.points[cp].y;
00334       leaves[idx].centroid_z += points.points[cp].z;
00335       leaves[idx].nr_points++;
00336     }
00337 
00338     // Second pass: go over all leaves and compute centroids
00339     int nr_p = 0;
00340     for (unsigned int cl = 0; cl < leaves.size (); cl++)
00341     {
00342       if (leaves[cl].nr_points > 0)
00343       {
00344         points_down.points[nr_p].x = leaves[cl].centroid_x / leaves[cl].nr_points;
00345         points_down.points[nr_p].y = leaves[cl].centroid_y / leaves[cl].nr_points;
00346         points_down.points[nr_p].z = leaves[cl].centroid_z / leaves[cl].nr_points;
00347         nr_p++;
00348       }
00349     }
00350     points_down.points.resize (nr_p);
00351   }
00352 
00354 
00363   void
00364     downsamplePointCloud (sensor_msgs::PointCloudConstPtr points, sensor_msgs::PointCloud &points_down, geometry_msgs::Point leaf_size,
00365                           std::vector<Leaf> &leaves, int d_idx, double cut_distance)
00366   {
00367     if (d_idx == -1)
00368       cut_distance = DBL_MAX;
00369     // Copy the header (and thus the frame_id) + allocate enough space for points
00370     points_down.header = points->header;
00371     points_down.points.resize (points->points.size ());
00372 
00373     geometry_msgs::Point32 min_p, max_p, min_b, max_b, div_b;
00374     cloud_geometry::statistics::getMinMax (points, min_p, max_p, d_idx, cut_distance);
00375 
00376     // Compute the minimum and maximum bounding box values
00377     min_b.x = (int)(floor (min_p.x / leaf_size.x));
00378     max_b.x = (int)(floor (max_p.x / leaf_size.x));
00379 
00380     min_b.y = (int)(floor (min_p.y / leaf_size.y));
00381     max_b.y = (int)(floor (max_p.y / leaf_size.y));
00382 
00383     min_b.z = (int)(floor (min_p.z / leaf_size.z));
00384     max_b.z = (int)(floor (max_p.z / leaf_size.z));
00385 
00386     // Compute the number of divisions needed along all axis
00387     div_b.x = (int)(max_b.x - min_b.x + 1);
00388     div_b.y = (int)(max_b.y - min_b.y + 1);
00389     div_b.z = (int)(max_b.z - min_b.z + 1);
00390 
00391     // Allocate the space needed
00392     try
00393     {
00394       if (leaves.capacity () < div_b.x * div_b.y * div_b.z)
00395         leaves.reserve (div_b.x * div_b.y * div_b.z);             // fallback to x*y*z from 2*x*y*z due to memory problems
00396       leaves.resize (div_b.x * div_b.y * div_b.z);
00397     }
00398     catch (std::bad_alloc)
00399     {
00400       ROS_ERROR ("Failed while attempting to allocate a vector of %f (%g x %g x %g) leaf elements (%f bytes total)", div_b.x * div_b.y * div_b.z,
00401                  div_b.x, div_b.y, div_b.z, div_b.x * div_b.y * div_b.z * sizeof (Leaf));
00402     }
00403 
00404     for (unsigned int cl = 0; cl < leaves.size (); cl++)
00405     {
00406       if (leaves[cl].nr_points > 0)
00407       {
00408         leaves[cl].centroid_x = leaves[cl].centroid_y = leaves[cl].centroid_z = 0.0;
00409         leaves[cl].nr_points = 0;
00410       }
00411     }
00412 
00413     // First pass: go over all points and insert them into the right leaf
00414     for (unsigned int cp = 0; cp < points->points.size (); cp++)
00415     {
00416       if (d_idx != -1 && points->channels[d_idx].values[cp] > cut_distance)        // Use a threshold for cutting out points which are too far away
00417         continue;
00418 
00419       int i = (int)(floor (points->points[cp].x / leaf_size.x));
00420       int j = (int)(floor (points->points[cp].y / leaf_size.y));
00421       int k = (int)(floor (points->points[cp].z / leaf_size.z));
00422 
00423       int idx = ( (k - min_b.z) * div_b.y * div_b.x ) + ( (j - min_b.y) * div_b.x ) + (i - min_b.x);
00424       leaves[idx].centroid_x += points->points[cp].x;
00425       leaves[idx].centroid_y += points->points[cp].y;
00426       leaves[idx].centroid_z += points->points[cp].z;
00427       leaves[idx].nr_points++;
00428     }
00429 
00430     // Second pass: go over all leaves and compute centroids
00431     int nr_p = 0;
00432     for (unsigned int cl = 0; cl < leaves.size (); cl++)
00433     {
00434       if (leaves[cl].nr_points > 0)
00435       {
00436         points_down.points[nr_p].x = leaves[cl].centroid_x / leaves[cl].nr_points;
00437         points_down.points[nr_p].y = leaves[cl].centroid_y / leaves[cl].nr_points;
00438         points_down.points[nr_p].z = leaves[cl].centroid_z / leaves[cl].nr_points;
00439         nr_p++;
00440       }
00441     }
00442     points_down.points.resize (nr_p);
00443   }
00444 
00446 
00452   void
00453     downsamplePointCloud (const sensor_msgs::PointCloud &points, sensor_msgs::PointCloud &points_down, geometry_msgs::Point leaf_size)
00454   {
00455     std::vector<Leaf> leaves;
00456     downsamplePointCloud (points, points_down, leaf_size, leaves, -1);
00457   }
00458 
00460 
00465   void
00466     getPointCloud (const sensor_msgs::PointCloud &input, const std::vector<int> &indices, sensor_msgs::PointCloud &output)
00467   {
00468     output.header = input.header;
00469     output.points.resize (indices.size ());
00470     output.channels.resize (input.channels.size ());
00471 
00472     for (unsigned int d = 0; d < output.channels.size (); d++)
00473     {
00474       output.channels[d].name = input.channels[d].name;
00475       output.channels[d].values.resize (indices.size ());
00476     }
00477 
00478     // Copy the data
00479     for (unsigned int i = 0; i < indices.size (); i++)
00480     {
00481       output.points[i].x = input.points[indices.at (i)].x;
00482       output.points[i].y = input.points[indices.at (i)].y;
00483       output.points[i].z = input.points[indices.at (i)].z;
00484       for (unsigned int d = 0; d < output.channels.size (); d++)
00485         output.channels[d].values[i] = input.channels[d].values[indices.at (i)];
00486     }
00487   }
00488 
00490 
00495   void
00496     getPointCloudOutside (const sensor_msgs::PointCloud &input, std::vector<int> indices, sensor_msgs::PointCloud &output)
00497   {
00498     std::vector<int> indices_outside;
00499     // Create the entire index list
00500     std::vector<int> all_indices (input.points.size ());
00501     for (unsigned int i = 0; i < all_indices.size (); i++)
00502       all_indices[i] = i;
00503 
00504     sort (indices.begin (), indices.end ());
00505 
00506     set_difference (all_indices.begin (), all_indices.end (), indices.begin (), indices.end (),
00507                     inserter (indices_outside, indices_outside.begin ()));
00508 
00509     if (indices_outside.size () == 0)
00510       return;
00511 
00512     output.header = input.header;
00513     output.channels.resize (input.channels.size ());
00514 
00515     output.points.resize (indices_outside.size ());
00516 
00517     for (unsigned int d = 0; d < output.channels.size (); d++)
00518     {
00519       output.channels[d].name = input.channels[d].name;
00520       output.channels[d].values.resize (indices_outside.size ());
00521     }
00522 
00523     // Copy the data
00524     for (unsigned int i = 0; i < indices_outside.size (); i++)
00525     {
00526       output.points[i].x = input.points[indices_outside.at (i)].x;
00527       output.points[i].y = input.points[indices_outside.at (i)].y;
00528       output.points[i].z = input.points[indices_outside.at (i)].z;
00529       for (unsigned int d = 0; d < output.channels.size (); d++)
00530         output.channels[d].values[i] = input.channels[d].values[indices_outside.at (i)];
00531     }
00532   }
00533 }


door_handle_detector
Author(s): Radu Bogdan Rusu, Marius
autogenerated on Wed Dec 11 2013 14:17:01