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