00001
00063 #include "cob_table_object_cluster/table_object_cluster.h"
00064
00065 #include <cob_3d_mapping_common/minimal_rectangle_2d.h>
00066 #include <pcl/segmentation/extract_polygonal_prism_data.h>
00067 #include <pcl/filters/extract_indices.h>
00068 #include <pcl/filters/crop_box.h>
00069 #include <pcl/io/io.h>
00070 #include <pcl/common/common.h>
00071 #include <pcl/kdtree/kdtree_flann.h>
00072 #include <pcl/segmentation/extract_clusters.h>
00073 #include <pcl/sample_consensus/sac_model_plane.h>
00074 #include <pcl/surface/convex_hull.h>
00075 #include <pcl/io/pcd_io.h>
00076
00077
00078
00079 #include <ros/console.h>
00080
00081 struct null_deleter
00082 {
00083 void operator()(void const *) const
00084 {
00085 }
00086 };
00087
00088
00089 template<typename Point> void
00090 TableObjectCluster<Point>::extractTableRoi(PointCloudPtr& hull,
00091 pcl::PointIndices& pc_roi)
00092 {
00093 #ifdef PCL_MINOR_VERSION >= 6
00094 pcl::ConvexHull<Point> chull;
00095 chull.setDimension(2);
00096 chull.setInputCloud(hull);
00097 PointCloudPtr conv_hull(new pcl::PointCloud<Point>);
00098 chull.reconstruct(*conv_hull);
00099 #endif
00100
00101 pcl::ExtractPolygonalPrismData<Point> prism;
00102
00103
00104
00105
00106 prism.setHeightLimits(height_min_, height_max_);
00107
00108
00109 prism.setInputCloud(input_);
00110
00111 #ifdef PCL_MINOR_VERSION >= 6
00112 prism.setInputPlanarHull(conv_hull);
00113 #else
00114 prism.setInputPlanarHull(hull);
00115 #endif
00116
00117 prism.segment(pc_roi);
00118
00119
00120
00121
00122
00123
00124 }
00125
00126 template<typename Point> void
00127 TableObjectCluster<Point>::extractTableRoi2(const PointCloudConstPtr& pc_in,
00128 PointCloudPtr& hull,
00129 Eigen::Vector4f& plane_coeffs,
00130 pcl::PointCloud<Point>& pc_roi)
00131 {
00132 pcl::PointIndices indices;
00133 for(unsigned int i=0; i<pc_in->size(); i++)
00134 indices.indices.push_back(i);
00135
00136 pcl::PointCloud<Point> projected_points;
00137 pcl::SampleConsensusModelPlane<Point> sacmodel (pc_in);
00138
00139 sacmodel.projectPoints (indices.indices, plane_coeffs, projected_points, false);
00140 pcl::io::savePCDFileASCII ("/home/goa/tmp/proj.pcd", projected_points);
00141 pcl::io::savePCDFileASCII ("/home/goa/tmp/hull.pcd", *hull);
00142 pcl::PointIndices inliers;
00143 std::cout << "Coeffs:" << plane_coeffs << std::endl;
00144 int ctr=0, ctr2=0;
00145 for(unsigned int i=0; i<pc_in->size(); i++)
00146 {
00147 double distance = pcl::pointToPlaneDistanceSigned (pc_in->points[i], plane_coeffs);
00148 if (distance < height_min_ || distance > height_max_)
00149 continue;
00150 ctr++;
00151 if (!pcl::isXYPointIn2DXYPolygon (projected_points.points[i], *hull))
00152 continue;
00153 ctr2++;
00154 ROS_INFO("Point is in polygon");
00155 inliers.indices.push_back(i);
00156 }
00157 ROS_INFO("Pts in height: %d", ctr);
00158 ROS_INFO("Pts in poly: %d", ctr2);
00159
00160 pcl::ExtractIndices<Point> extract_roi;
00161 extract_roi.setInputCloud (pc_in);
00162 extract_roi.setIndices (boost::make_shared<const pcl::PointIndices> (inliers));
00163 extract_roi.filter (pc_roi);
00164 }
00165
00166 template<typename Point> void
00167 TableObjectCluster<Point>::removeKnownObjects(const PointCloudConstPtr& pc_roi,
00168 std::vector<BoundingBox>& bounding_boxes,
00169 const PointCloudPtr& pc_roi_red)
00170 {
00171
00172 boost::shared_ptr<pcl::PointIndices> all_indices(new pcl::PointIndices);
00173 pcl::CropBox<Point> cb;
00174 for(unsigned int i=0; i<bounding_boxes.size(); i++)
00175 {
00176 std::vector<int> indices;
00177 cb.setMin(bounding_boxes[i].min_pt);
00178 cb.setMax(bounding_boxes[i].max_pt);
00179 cb.setTransform(bounding_boxes[i].pose);
00180 cb.filter(indices);
00181 all_indices->indices.insert(all_indices->indices.end(), indices.begin(), indices.end());
00182 }
00183 pcl::ExtractIndices<Point> extract;
00184 extract.setInputCloud(pc_roi);
00185 extract.setIndices(all_indices);
00186 extract.setNegative(true);
00187 extract.filter(*pc_roi_red);
00188 }
00189
00190 template<typename Point> void
00191 TableObjectCluster<Point>::calculateBoundingBox(
00192 const PointCloudPtr& cloud,
00193 const pcl::PointIndices& indices,
00194 const Eigen::Vector3f& plane_normal,
00195 const Eigen::Vector3f& plane_point,
00196 Eigen::Vector3f& position,
00197 Eigen::Quaternion<float>& orientation,
00198 Eigen::Vector3f& size)
00199 {
00200
00201 Eigen::Affine3f tf;
00202 pcl::getTransformationFromTwoUnitVectorsAndOrigin(plane_normal.unitOrthogonal(), plane_normal, plane_point, tf);
00203 pcl::PointCloud<pcl::PointXYZ>::Ptr pc2d(new pcl::PointCloud<pcl::PointXYZ>);
00204 float height = 0.0;
00205 for(std::vector<int>::const_iterator it=indices.indices.begin(); it != indices.indices.end(); ++it)
00206 {
00207 Eigen::Vector3f tmp = tf * (*cloud)[*it].getVector3fMap();
00208 height = std::max<float>(height, fabs(tmp(2)));
00209 pc2d->push_back(pcl::PointXYZ(tmp(0),tmp(1),0.0));
00210 }
00211
00212
00213 #ifdef PCL_MINOR_VERSION >= 6
00214 pcl::PointCloud<pcl::PointXYZ>::Ptr conv_hull(new pcl::PointCloud<pcl::PointXYZ>);
00215 pcl::ConvexHull<pcl::PointXYZ> chull;
00216 chull.setDimension(2);
00217 chull.setInputCloud(pc2d);
00218 chull.reconstruct(*conv_hull);
00219 #endif
00220
00221
00222
00223
00224
00225 Eigen::Vector2f p1, p2, p3;
00226 cob_3d_mapping::MinimalRectangle2D mr2d;
00227 mr2d.setConvexHull(conv_hull->points);
00228 mr2d.rotatingCalipers(p2, p1, p3);
00229
00230
00231
00232
00233
00234 position[0] = 0.5f*(p1[0] + p3[0]);
00235 position[1] = 0.5f*(p1[1] + p3[1]);
00236 position[2] = 0.0f;
00237
00238 Eigen::Affine3f inv_tf = tf.inverse();
00239 position = inv_tf * position;
00240
00241 float norm_1 = (p3-p2).norm();
00242 float norm_2 = (p1-p2).norm();
00243
00244 Eigen::Vector3f direction;
00245 if (norm_1 < norm_2)
00246 {
00247 direction = Eigen::Vector3f(p3[0]-p2[0], p3[1]-p2[1], 0) / (norm_1);
00248 size[0] = norm_2 * 0.5f;
00249 size[1] = norm_1 * 0.5f;
00250 }
00251 else
00252 {
00253 direction = Eigen::Vector3f(p1[0]-p2[0], p1[1]-p2[1], 0) / (norm_2);
00254 size[0] = norm_1 * 0.5f;
00255 size[1] = norm_2 * 0.5f;
00256 }
00257 size[2] = -height;
00258
00259
00260 direction = inv_tf.rotation() * direction;
00261 orientation = pcl::getTransformationFromTwoUnitVectors(direction, plane_normal).rotation();
00262
00263 return;
00264 Eigen::Matrix3f M = Eigen::Matrix3f::Identity() - plane_normal * plane_normal.transpose();
00265 Eigen::Vector3f xn = M * Eigen::Vector3f::UnitX();
00266 Eigen::Vector3f xxn = M * direction;
00267 float cos_phi = acos(xn.normalized().dot(xxn.normalized()));
00268 cos_phi = cos(0.5f * cos_phi);
00269 float sin_phi = sqrt(1.0f-cos_phi*cos_phi);
00270
00271
00272
00273
00274 }
00275
00276 template<typename Point> void
00277 TableObjectCluster<Point>::extractClusters(
00278 const pcl::PointIndices::Ptr& pc_roi,
00279 std::vector<PointCloudPtr>& object_clusters,
00280 std::vector<pcl::PointIndices>& object_cluster_indices)
00281 {
00282
00283 #ifdef PCL_VERSION_COMPARE //fuerte
00284
00285 typename pcl::search::KdTree<Point>::Ptr clusters_tree (new pcl::search::KdTree<Point>());
00286 #else //electric
00287 typename pcl::KdTreeFLANN<Point>::Ptr clusters_tree (new pcl::KdTreeFLANN<Point> ());
00288 #endif
00289
00290 pcl::EuclideanClusterExtraction<Point> cluster_obj;
00291 cluster_obj.setClusterTolerance (cluster_tolerance_);
00292 cluster_obj.setMinClusterSize (min_cluster_size_);
00293 cluster_obj.setInputCloud (input_);
00294 cluster_obj.setIndices(pc_roi);
00295 cluster_obj.setSearchMethod (clusters_tree);
00296 cluster_obj.extract (object_cluster_indices);
00297
00298 pcl::ExtractIndices<Point> ei;
00299 ei.setInputCloud(input_);
00300 for(unsigned int i = 0; i < object_cluster_indices.size(); ++i)
00301 {
00302 PointCloudPtr cluster_ptr(new pcl::PointCloud<Point>);
00303 boost::shared_ptr<pcl::PointIndices> ind_ptr(&object_cluster_indices[i], null_deleter());
00304 ei.setIndices(ind_ptr);
00305 ei.filter(*cluster_ptr);
00306 object_clusters.push_back(cluster_ptr);
00307 }
00308 }
00309
00310 template<typename Point> void
00311 TableObjectCluster<Point>::calculateBoundingBoxesOld(pcl::PointIndices::Ptr& pc_roi,
00312 std::vector<PointCloudPtr >& object_clusters,
00313 std::vector<pcl::PointCloud<pcl::PointXYZ> >& bounding_boxes)
00314 {
00315 ROS_INFO("roi: %d", pc_roi->indices.size());
00316 #ifdef PCL_VERSION_COMPARE //fuerte
00317 typename pcl::search::KdTree<Point>::Ptr clusters_tree (new pcl::search::KdTree<Point>());
00318
00319 #else //electric
00320 typename pcl::KdTreeFLANN<Point>::Ptr clusters_tree (new pcl::KdTreeFLANN<Point> ());
00321 #endif
00322
00323 pcl::EuclideanClusterExtraction<Point> cluster_obj;
00324
00325
00326 cluster_obj.setClusterTolerance (cluster_tolerance_);
00327 cluster_obj.setMinClusterSize (min_cluster_size_);
00328 cluster_obj.setInputCloud (input_);
00329 cluster_obj.setIndices(pc_roi);
00330
00331 std::vector<pcl::PointIndices> object_cluster_indices;
00332 cluster_obj.extract (object_cluster_indices);
00333 pcl::ExtractIndices<Point> ei;
00334 ei.setInputCloud(input_);
00335 for(unsigned int i = 0; i < object_cluster_indices.size(); ++i)
00336 {
00337 boost::shared_ptr<pcl::PointIndices> ind_ptr(&object_cluster_indices[i], null_deleter());
00338 ei.setIndices(ind_ptr);
00339 PointCloudPtr cluster_ptr(new pcl::PointCloud<Point>);
00340 ei.filter(*cluster_ptr);
00341 object_clusters.push_back(cluster_ptr);
00342 pcl::PointCloud<pcl::PointXYZ> bb;
00343 Eigen::Vector4f min_pt, max_pt;
00344 pcl::getMinMax3D(*input_, object_cluster_indices[i], min_pt, max_pt);
00345
00346 pcl::PointXYZ p;
00347 p.x = min_pt(0);
00348 p.y = min_pt(1);
00349 p.z = min_pt(2);
00350 bb.push_back(p);
00351 p.x = max_pt(0);
00352 p.y = max_pt(1);
00353 p.z = max_pt(2);
00354 bb.push_back(p);
00355 bounding_boxes.push_back(bb);
00356 }
00357 }
00358
00359 template class TableObjectCluster<pcl::PointXYZ>;
00360
00361 template class TableObjectCluster<pcl::PointXYZRGB>;