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/point.h>
00036 #include <stereo_wall_detection/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
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
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
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
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
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
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
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
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);
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
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)
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
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
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
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
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
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);
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
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)
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
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
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
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
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
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);
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
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)
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
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
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
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
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 }