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
00031
00032
00033
00034 #ifndef point_cloud_segmentation_h_DEFINED
00035 #define point_cloud_segmentation_h_DEFINED
00036
00037
00038 #include <std_msgs/Header.h>
00039 #include <sensor_msgs/CameraInfo.h>
00040 #include <geometry_msgs/PointStamped.h>
00041
00042
00043 #include <tf/transform_listener.h>
00044
00045
00046 #include <pcl16/point_cloud.h>
00047 #include <pcl16/point_types.h>
00048 #include <pcl16/common/eigen.h>
00049 #include <pcl16/common/io.h>
00050 #include <pcl16/ModelCoefficients.h>
00051
00052
00053 #include <opencv2/core/core.hpp>
00054
00055
00056 #include <vector>
00057 #include <deque>
00058 #include <string>
00059 #include <math.h>
00060
00061
00062 #include <boost/shared_ptr.hpp>
00063
00064 namespace tabletop_pushing
00065 {
00066
00067 typedef pcl16::PointCloud<pcl16::PointXYZ> XYZPointCloud;
00068 typedef pcl16::PointCloud<pcl16::Normal> NormalCloud;
00069 class ProtoObject
00070 {
00071 public:
00072 XYZPointCloud cloud;
00073 NormalCloud normals;
00074 Eigen::Vector4f centroid;
00075 int id;
00076 bool moved;
00077 Eigen::Matrix4f transform;
00078 std::vector<int> boundary_angle_dist;
00079 std::vector<int> push_history;
00080 bool singulated;
00081 double icp_score;
00082 };
00083 typedef std::deque<ProtoObject> ProtoObjects;
00084
00085 class PointCloudSegmentation
00086 {
00087 public:
00088 PointCloudSegmentation(boost::shared_ptr<tf::TransformListener> tf);
00089
00099 void getTablePlane(XYZPointCloud& cloud, XYZPointCloud& objs_cloud,
00100 XYZPointCloud& plane_cloud, Eigen::Vector4f& center,
00101 bool find_hull=false, bool find_centroid=false);
00102
00112 void getTablePlaneMPS(XYZPointCloud& cloud, XYZPointCloud& objs_cloud,
00113 XYZPointCloud& plane_cloud, Eigen::Vector4f& center,
00114 bool find_hull=false, bool find_centroid=false);
00115
00123 void findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs, bool use_mps=false);
00124
00133 void findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs,
00134 XYZPointCloud& objs_cloud, bool use_mps=false);
00135
00145 void findTabletopObjects(XYZPointCloud& input_cloud, ProtoObjects& objs,
00146 XYZPointCloud& objs_cloud,
00147 XYZPointCloud& plane_cloud, bool use_mps=false);
00148
00155 void clusterProtoObjects(XYZPointCloud& objects_cloud, ProtoObjects& objs);
00156
00165 double ICPProtoObjects(ProtoObject& a, ProtoObject& b, Eigen::Matrix4f& transform);
00166
00167 double ICPBoundarySamples(XYZPointCloud& hull_t_0, XYZPointCloud& hull_t_1, Eigen::Matrix4f& transform,
00168 XYZPointCloud& aligned);
00169
00178 void getMovedRegions(XYZPointCloud& prev_cloud, XYZPointCloud& cur_cloud, ProtoObjects& moved_regions,
00179 std::string suf="");
00180
00188 void matchMovedRegions(ProtoObjects& objs, ProtoObjects& moved_regions);
00189
00190 void fitCylinderRANSAC(ProtoObject& obj, XYZPointCloud& cylinder_cloud, pcl16::ModelCoefficients& cylinder);
00191 void fitSphereRANSAC(ProtoObject& obj, XYZPointCloud& sphere_cloud, pcl16::ModelCoefficients& sphere);
00192
00193 static inline double dist(pcl16::PointXYZ a, pcl16::PointXYZ b)
00194 {
00195 const double dx = a.x-b.x;
00196 const double dy = a.y-b.y;
00197 const double dz = a.z-b.z;
00198 return std::sqrt(dx*dx+dy*dy+dz*dz);
00199 }
00200
00201 static inline double dist(geometry_msgs::Point b, pcl16::PointXYZ a)
00202 {
00203 return dist(a,b);
00204 }
00205
00206 static inline double dist(pcl16::PointXYZ a, geometry_msgs::Point b)
00207 {
00208 const double dx = a.x-b.x;
00209 const double dy = a.y-b.y;
00210 const double dz = a.z-b.z;
00211 return std::sqrt(dx*dx+dy*dy+dz*dz);
00212 }
00213
00214 static inline double sqrDist(Eigen::Vector3f& a, pcl16::PointXYZ& b)
00215 {
00216 const double dx = a[0]-b.x;
00217 const double dy = a[1]-b.y;
00218 const double dz = a[2]-b.z;
00219 return dx*dx+dy*dy+dz*dz;
00220 }
00221
00222 static inline double sqrDist(Eigen::Vector4f& a, Eigen::Vector4f& b)
00223 {
00224 const double dx = a[0]-b[0];
00225 const double dy = a[1]-b[1];
00226 const double dz = a[2]-b[2];
00227 return dx*dx+dy*dy+dz*dz;
00228 }
00229
00230 static inline double sqrDist(pcl16::PointXYZ a, pcl16::PointXYZ b)
00231 {
00232 const double dx = a.x-b.x;
00233 const double dy = a.y-b.y;
00234 const double dz = a.z-b.z;
00235 return dx*dx+dy*dy+dz*dz;
00236 }
00237
00238 static inline double sqrDistXY(pcl16::PointXYZ a, pcl16::PointXYZ b)
00239 {
00240 const double dx = a.x-b.x;
00241 const double dy = a.y-b.y;
00242 return dx*dx+dy*dy;
00243 }
00244
00255 bool cloudsIntersect(XYZPointCloud cloud0, XYZPointCloud cloud1);
00256
00257 bool cloudsIntersect(XYZPointCloud cloud0, XYZPointCloud cloud1,
00258 double thresh);
00259
00260 bool pointIntersectsCloud(XYZPointCloud cloud, geometry_msgs::Point pt,
00261 double thresh);
00262
00263 float pointLineXYDist(pcl16::PointXYZ p,Eigen::Vector3f vec,Eigen::Vector4f base);
00264
00265 void lineCloudIntersection(XYZPointCloud& cloud, Eigen::Vector3f vec,
00266 Eigen::Vector4f base, XYZPointCloud& line_cloud);
00267 void lineCloudIntersectionEndPoints(XYZPointCloud& cloud, Eigen::Vector3f vec, Eigen::Vector4f base,
00268 std::vector<pcl16::PointXYZ>& end_points);
00269
00278 void downsampleCloud(XYZPointCloud& cloud_in, XYZPointCloud& cloud_down);
00279
00289 cv::Mat projectProtoObjectsIntoImage(ProtoObjects& objs, cv::Size img_size, std::string target_frame);
00290
00300 cv::Mat projectProtoObjectIntoImage(ProtoObject& obj, cv::Size img_size, std::string target_frame);
00301
00308 cv::Mat displayObjectImage(cv::Mat& obj_img,
00309 std::string win_name="projected objects",
00310 bool use_display=true);
00311
00312 void projectPointCloudIntoImage(XYZPointCloud& cloud, cv::Mat& lbl_img,
00313 std::string target_frame, unsigned int id=1);
00314
00315 cv::Point projectPointIntoImage(pcl16::PointXYZ cur_point_pcl,
00316 std::string point_frame,
00317 std::string target_frame);
00318
00319 void projectPointCloudIntoImage(XYZPointCloud& cloud, cv::Mat& lbl_img);
00320
00321 cv::Point projectPointIntoImage(geometry_msgs::PointStamped cur_point);
00322
00323 cv::Point projectPointIntoImage(geometry_msgs::PointStamped cur_point,
00324 std::string target_frame);
00325 cv::Point projectPointIntoImage(Eigen::Vector3f cur_point_eig,
00326 std::string point_frame, std::string target_frame);
00327
00328 Eigen::Vector4f getTableCentroid() const
00329 {
00330 return table_centroid_;
00331 }
00332
00333 protected:
00334 boost::shared_ptr<tf::TransformListener> tf_;
00335 Eigen::Vector4f table_centroid_;
00336
00337 public:
00338 std::vector<cv::Vec3f> colors_;
00339 double min_table_z_;
00340 double max_table_z_;
00341 double min_workspace_x_;
00342 double max_workspace_x_;
00343 double min_workspace_z_;
00344 double max_workspace_z_;
00345 double table_ransac_thresh_;
00346 double table_ransac_angle_thresh_;
00347 double cluster_tolerance_;
00348 double cloud_diff_thresh_;
00349 int min_cluster_size_;
00350 int max_cluster_size_;
00351 double voxel_down_res_;
00352 double cloud_intersect_thresh_;
00353 double hull_alpha_;
00354 bool use_voxel_down_;
00355 int num_downsamples_;
00356 sensor_msgs::CameraInfo cam_info_;
00357 std_msgs::Header cur_camera_header_;
00358 int moved_count_thresh_;
00359 int icp_max_iters_;
00360 double icp_transform_eps_;
00361 double icp_max_cor_dist_;
00362 double icp_ransac_thresh_;
00363 int mps_min_inliers_;
00364 double mps_min_angle_thresh_;
00365 double mps_min_dist_thresh_;
00366 double cylinder_ransac_thresh_;
00367 double cylinder_ransac_angle_thresh_;
00368 double sphere_ransac_thresh_;
00369 bool optimize_cylinder_coefficients_;
00370 };
00371
00372 void getMaskedPointCloud(XYZPointCloud& input_cloud, cv::Mat& mask, XYZPointCloud& masked_cloud)
00373 {
00374
00375 pcl16::PointIndices mask_indices;
00376 mask_indices.header = input_cloud.header;
00377 for (int y = 0; y < mask.rows; ++y)
00378 {
00379 uchar* mask_row = mask.ptr<uchar>(y);
00380 for (int x = 0; x < mask.cols; ++x)
00381 {
00382 if (mask_row[x] != 0)
00383 {
00384 mask_indices.indices.push_back(y*input_cloud.width + x);
00385 }
00386 }
00387 }
00388
00389 pcl16::copyPointCloud(input_cloud, mask_indices, masked_cloud);
00390 }
00391 };
00392 #endif // point_cloud_segmentation_h_DEFINED