statistics.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/statistics.h>
00036 
00037 namespace cloud_geometry
00038 {
00039 
00040   namespace statistics
00041   {
00043 
00046     geometry_msgs::Point32
00047       computeMedian (const sensor_msgs::PointCloud& points)
00048     {
00049       geometry_msgs::Point32 median;
00050 
00051       // Copy the values to vectors for faster sorting
00052       std::vector<double> x (points.points.size ());
00053       std::vector<double> y (points.points.size ());
00054       std::vector<double> z (points.points.size ());
00055       for (unsigned int i = 0; i < points.points.size (); i++)
00056       {
00057         x[i] = points.points[i].x;
00058         y[i] = points.points[i].y;
00059         z[i] = points.points[i].z;
00060       }
00061       std::sort (x.begin (), x.end ());
00062       std::sort (y.begin (), y.end ());
00063       std::sort (z.begin (), z.end ());
00064 
00065       int mid = points.points.size () / 2;
00066       if (points.points.size () % 2 == 0)
00067       {
00068         median.x = (x[mid-1] + x[mid]) / 2;
00069         median.y = (y[mid-1] + y[mid]) / 2;
00070         median.z = (z[mid-1] + z[mid]) / 2;
00071       }
00072       else
00073       {
00074         median.x = x[mid];
00075         median.y = y[mid];
00076         median.z = z[mid];
00077       }
00078       return (median);
00079     }
00080 
00082 
00087     geometry_msgs::Point32
00088       computeMedian (const sensor_msgs::PointCloud &points, const std::vector<int> &indices)
00089     {
00090       geometry_msgs::Point32 median;
00091 
00092       // Copy the values to vectors for faster sorting
00093       std::vector<double> x (indices.size ());
00094       std::vector<double> y (indices.size ());
00095       std::vector<double> z (indices.size ());
00096       for (unsigned int i = 0; i < indices.size (); i++)
00097       {
00098         x[i] = points.points.at (indices.at (i)).x;
00099         y[i] = points.points.at (indices.at (i)).y;
00100         z[i] = points.points.at (indices.at (i)).z;
00101       }
00102       std::sort (x.begin (), x.end ());
00103       std::sort (y.begin (), y.end ());
00104       std::sort (z.begin (), z.end ());
00105 
00106       int mid = indices.size () / 2;
00107       if (indices.size () % 2 == 0)
00108       {
00109         median.x = (x[mid-1] + x[mid]) / 2;
00110         median.y = (y[mid-1] + y[mid]) / 2;
00111         median.z = (z[mid-1] + z[mid]) / 2;
00112       }
00113       else
00114       {
00115         median.x = x[mid];
00116         median.y = y[mid];
00117         median.z = z[mid];
00118       }
00119       return (median);
00120     }
00121 
00123 
00131     double
00132       computeMedianAbsoluteDeviation (const sensor_msgs::PointCloud &points, double sigma)
00133     {
00134       // median (dist (x - median (x)))
00135       geometry_msgs::Point32 median = computeMedian (points);
00136 
00137       std::vector<double> distances (points.points.size ());
00138 
00139       for (unsigned int i = 0; i < points.points.size (); i++)
00140         distances[i] = (points.points[i].x - median.x) * (points.points[i].x - median.x) +
00141                        (points.points[i].y - median.y) * (points.points[i].y - median.y) +
00142                        (points.points[i].z - median.z) * (points.points[i].z - median.z);
00143 
00144       std::sort (distances.begin (), distances.end ());
00145 
00146       double result;
00147       int mid = points.points.size () / 2;
00148       // Do we have a "middle" point or should we "estimate" one ?
00149       if (points.points.size () % 2 == 0)
00150         result = (sqrt (distances[mid-1]) + sqrt (distances[mid])) / 2;
00151       else
00152         result = sqrt (distances[mid]);
00153       return (sigma * result);
00154     }
00155 
00157 
00165     double
00166       computeMedianAbsoluteDeviation (const sensor_msgs::PointCloud &points, const std::vector<int> &indices, double sigma)
00167     {
00168       // median (dist (x - median (x)))
00169       geometry_msgs::Point32 median = computeMedian (points, indices);
00170 
00171       std::vector<double> distances (indices.size ());
00172 
00173       for (unsigned int i = 0; i < indices.size (); i++)
00174         distances[i] = (points.points.at (indices.at (i)).x - median.x) * (points.points.at (indices.at (i)).x - median.x) +
00175                        (points.points.at (indices.at (i)).y - median.y) * (points.points.at (indices.at (i)).y - median.y) +
00176                        (points.points.at (indices.at (i)).z - median.z) * (points.points.at (indices.at (i)).z - median.z);
00177 
00178       std::sort (distances.begin (), distances.end ());
00179 
00180       double result;
00181       int mid = indices.size () / 2;
00182       // Do we have a "middle" point or should we "estimate" one ?
00183       if (indices.size () % 2 == 0)
00184         result = (sqrt (distances[mid-1]) + sqrt (distances[mid])) / 2;
00185       else
00186         result = sqrt (distances[mid]);
00187 
00188       return (sigma * result);
00189     }
00190 
00192 
00198     void
00199       getChannelMeanStd (const sensor_msgs::PointCloud &points, int d_idx, double &mean, double &stddev)
00200     {
00201       double sum = 0, sq_sum = 0;
00202 
00203       for (unsigned int i = 0; i < points.points.size (); i++)
00204       {
00205         sum += points.channels.at (d_idx).values.at (i);
00206         sq_sum += points.channels.at (d_idx).values.at (i) * points.channels.at (d_idx).values.at (i);
00207       }
00208       mean = sum / points.points.size ();
00209       double variance = (double)(sq_sum - sum * sum / points.points.size ()) / (points.points.size () - 1);
00210       stddev = sqrt (variance);
00211     }
00212 
00214 
00221     void
00222       getChannelMeanStd (const sensor_msgs::PointCloud &points, const std::vector<int> &indices, int d_idx, double &mean, double &stddev)
00223     {
00224       double sum = 0, sq_sum = 0;
00225 
00226       for (unsigned int i = 0; i < indices.size (); i++)
00227       {
00228         sum += points.channels.at (d_idx).values.at (indices.at (i));
00229         sq_sum += points.channels.at (d_idx).values.at (indices.at (i)) * points.channels.at (d_idx).values.at (indices.at (i));
00230       }
00231       mean = sum / indices.size ();
00232       double variance = (double)(sq_sum - sum * sum / indices.size ()) / (indices.size () - 1);
00233       stddev = sqrt (variance);
00234     }
00235 
00237 
00247     void
00248       selectPointsOutsideDistribution (const sensor_msgs::PointCloud &points, const std::vector<int> &indices, int d_idx,
00249                                        double mean, double stddev, double alpha, std::vector<int> &inliers)
00250     {
00251       inliers.resize (indices.size ());
00252       int nr_i = 0;
00253       for (unsigned int i = 0; i < indices.size (); i++)
00254       {
00255         if ( (points.channels.at (d_idx).values.at (indices.at (i)) > (mean + alpha * stddev)) ||
00256              (points.channels.at (d_idx).values.at (indices.at (i)) < (mean - alpha * stddev))
00257            )
00258         {
00259           inliers[nr_i] = indices.at (i);
00260           nr_i++;
00261         }
00262       }
00263       inliers.resize (nr_i);
00264     }
00265 
00267 
00277     void
00278       selectPointsInsideDistribution (const sensor_msgs::PointCloud &points, const std::vector<int> &indices, int d_idx,
00279                                       double mean, double stddev, double alpha, std::vector<int> &inliers)
00280     {
00281       inliers.resize (indices.size ());
00282       int nr_i = 0;
00283       for (unsigned int i = 0; i < indices.size (); i++)
00284       {
00285         if ( (points.channels.at (d_idx).values.at (indices.at (i)) < (mean + alpha * stddev)) &&
00286              (points.channels.at (d_idx).values.at (indices.at (i)) > (mean - alpha * stddev))
00287            )
00288         {
00289           inliers[nr_i] = indices.at (i);
00290           nr_i++;
00291         }
00292       }
00293       inliers.resize (nr_i);
00294     }
00295 
00297 
00303     void
00304       getTrimean (std::vector<int> values, double &trimean)
00305     {
00306       nth_element (values.begin (), values.begin () + (int)(values.size () * 0.25), values.end ());
00307       int p_25 = *(values.begin () + (int)(values.size () * 0.25));
00308 
00309       nth_element (values.begin (), values.begin () + (int)(values.size () * 0.5), values.end ());
00310       int p_50 = *(values.begin () + (int)(values.size () * 0.5));
00311 
00312       nth_element (values.begin (), values.begin () + (int)(values.size () * 0.75), values.end ());
00313       int p_75 = *(values.begin () + (int)(values.size () * 0.75));
00314 
00315       trimean = (p_25 + 2.0 * p_50 + p_75) / 4.0;
00316     }
00317 
00318   }
00319 }


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