00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00033 #include <algorithm>
00034 #include <cfloat>
00035 #include <stereo_wall_detection/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
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
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
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
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
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
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 }