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 #include <ros/ros.h>
00032 #include <boost/thread/mutex.hpp>
00033 #include <boost/thread.hpp>
00034 #include <pcl_ros/point_cloud.h>
00035 #include "pcl/ModelCoefficients.h"
00036 #include "pcl/point_types.h"
00037 #include "pcl/io/pcd_io.h"
00038 #include "pcl/sample_consensus/method_types.h"
00039 #include "pcl/sample_consensus/model_types.h"
00040 #include "pcl/segmentation/sac_segmentation.h"
00041 #include <pcl/filters/extract_indices.h>
00042 #include <pcl/filters/passthrough.h>
00043 #include "sensor_msgs/Image.h"
00044 #include "image_transport/image_transport.h"
00045 #include "cv_bridge/CvBridge.h"
00046 #include <opencv/cv.h>
00047 #include <opencv/highgui.h>
00048 #include <vector>
00049 #include "geometry_msgs/Point.h"
00050 #include "UI_segment_object/GetObject.h"
00051 #include "UI_segment_object/GetPt.h"
00052 #include "UI_segment_object/None_Bool.h"
00053 #include "UI_segment_object/Save.h"
00054 #include "pcl_ros/transforms.h"
00055 #include <tf/transform_listener.h>
00056 
00057 boost::mutex m;
00058 
00059 
00060 
00061 std::vector<std::vector<int> > poly_vec;
00062 std::vector<int> in_indices;
00063 int counter(0);
00064 int counter_ind(0);
00065 
00066 CvPoint pts[1000];
00067 int done (0);
00068 
00069 
00070 
00071 
00072 class UI {
00073 
00074 public:
00075   
00076   UI(ros::NodeHandle &nh);
00077   ~UI();
00078   bool reset_cb(UI_segment_object::None_Bool::Request ®, UI_segment_object::None_Bool::Response &res);
00079   static void mouse_callback(int event, int x, int y, int flags, void* param);
00080   void color_segment_callback();
00081   void pt_callback();
00082   void callback(const sensor_msgs::ImageConstPtr& msg_ptr);
00083   void cloud_callback();
00084   int pnpoly(int npol, std::vector<std::vector<int > > poly_vec, int x, int y);
00085   bool save_image(UI_segment_object::Save::Request ®, UI_segment_object::Save::Response &res);
00086   ros::ServiceServer reset_service;
00087   ros::ServiceServer save_img;
00088   
00089 protected:
00090   ros::NodeHandle nh_;
00091   image_transport::ImageTransport it_;
00092   sensor_msgs::CvBridge bridge_;
00093   image_transport::Subscriber image_sub_;
00094   IplImage* cv_image;
00095   int height;
00096   int width;
00097 };
00098 
00099 
00100   
00101 UI::UI(ros::NodeHandle &nh) :
00102   nh_(nh), it_(nh_)
00103 {
00104   
00105   
00106   cv_image = NULL;
00107   counter = 0;
00108   counter_ind = 0;
00109   
00110   
00111   reset_service = nh_.advertiseService("UI_reset", &UI::reset_cb, this);
00112   save_img = nh_.advertiseService("save_image", &UI::save_image, this);
00113 }
00114 
00115 UI::~UI()
00116 {
00117   cvDestroyWindow("Select");                                                             
00118 }
00119 
00120 bool UI::reset_cb(UI_segment_object::None_Bool::Request ®, UI_segment_object::None_Bool::Response &res)
00121 {
00122   printf("resetting vectors..");
00123   poly_vec.clear();
00124   in_indices.clear();
00125   counter = 0;
00126   counter_ind = 0;
00127   done = 0;
00128   res.state = true;
00129   return (true);
00130 }
00131 
00132 
00133 void UI::mouse_callback(int event, int x, int y, int flags, void* param)
00134 {
00135   
00136   
00137   
00138   
00139   
00140   
00141   
00142   
00143   
00144   
00145   
00146   
00147   
00148   
00149   
00150 
00151   if (event == CV_EVENT_LBUTTONDOWN)
00152     {
00153       poly_vec.push_back(std::vector<int>());
00154       poly_vec[counter].push_back(x);
00155       poly_vec[counter].push_back(y);
00156       counter++;
00157     }
00158 
00159   if (event == CV_EVENT_RBUTTONDOWN)
00160     {
00161       std::cerr << "you did click the right mouse button" << std::endl;
00162       done = 1;
00163     }
00164 }
00165 
00166 void UI::color_segment_callback()
00167 {
00168   cvNamedWindow("Select");
00169   cvSetMouseCallback("Select", mouse_callback);
00170   sensor_msgs::ImageConstPtr image_in = ros::topic::waitForMessage<sensor_msgs::Image>("/camera/rgb/image_color", nh_);
00171   cv_image = bridge_.imgMsgToCv(image_in, "bgr8"); 
00172   while (done == 0)
00173     {
00174       for (int i = 0; i < counter; i++)
00175         {
00176           cvCircle(cv_image, cvPoint(poly_vec[i][0], poly_vec[i][1]), 2, CV_RGB(255, 0, 0), 2, 8);
00177         }
00178       cvShowImage("Select", cv_image);
00179       cvWaitKey(33);
00180     }
00181 
00182 
00183   
00184   height = cv_image->height;
00185   width = cv_image->width;
00186   
00187   for (int j = 0; j < poly_vec.size(); j++)
00188     {
00189       pts[j] = cvPoint(poly_vec[j][0], poly_vec[j][1]);
00190     }
00191   IplImage* mask = cvCreateImage(cvSize(width, height), 8, 1);
00192   cvFillConvexPoly(mask, pts, poly_vec.size(), cvScalar(255));
00193   cvSaveImage("./mask.png", mask);
00194 
00195   
00196   
00197 
00198 }
00199 
00200 void UI::pt_callback()
00201 {
00202   cvNamedWindow("Select");                                                               
00203   cvSetMouseCallback("Select", mouse_callback);
00204 
00205   
00206   sensor_msgs::ImageConstPtr image_in = ros::topic::waitForMessage<sensor_msgs::Image>("/camera/rgb/image_color", nh_);
00207   cv_image = bridge_.imgMsgToCv(image_in, "bgr8");
00208   
00209   while (done == 0)
00210     {
00211       for (int i = 0; i < counter; i++)
00212         {
00213           cvCircle(cv_image, cvPoint(poly_vec[i][0], poly_vec[i][1]), 2, CV_RGB(255, 0, 0), 2, 8);
00214         }
00215       cvShowImage("Select", cv_image);
00216       cvWaitKey(33);
00217     }
00218 
00219   
00220   height = cv_image->height;
00221   width = cv_image->width;
00222   int index;
00223   index = poly_vec[0][1]*width+poly_vec[0][0];
00224   in_indices.push_back(index);
00225   cvDestroyWindow("Select");
00226 }
00227 
00228 void UI::callback(const sensor_msgs::ImageConstPtr& msg_ptr)
00229 {
00230   cv_image = bridge_.imgMsgToCv(msg_ptr, "bgr8");
00231 }
00232 
00233 void UI::cloud_callback(){
00234   cvNamedWindow("Select");                                                               
00235   cvSetMouseCallback("Select", mouse_callback);
00236 
00237   
00238   sensor_msgs::ImageConstPtr image_in = ros::topic::waitForMessage<sensor_msgs::Image>("/camera/rgb/image_color", nh_);
00239   cv_image = bridge_.imgMsgToCv(image_in, "bgr8");
00240   
00241   while (done == 0)
00242     {
00243       for (int i = 0; i < counter; i++)
00244         {
00245           cvCircle(cv_image, cvPoint(poly_vec[i][0], poly_vec[i][1]), 2, CV_RGB(255, 0, 0), 2, 8);
00246         }
00247       cvShowImage("Select", cv_image);
00248       cvWaitKey(33);
00249     }
00250 
00251   
00252   height = cv_image->height;
00253   width = cv_image->width;
00254   int max_x(0);
00255   int min_x(width);
00256   int max_y(0);
00257   int min_y(height);
00258   for (int i=0; i<counter; i++)
00259     {
00260       if (poly_vec[i][0]>max_x)
00261         max_x = poly_vec[i][0];
00262       if (poly_vec[i][0]<min_x)
00263         min_x = poly_vec[i][0];
00264       if (poly_vec[i][1]>max_y)
00265         max_y = poly_vec[i][1];
00266       if (poly_vec[i][1]<min_y)
00267         min_y = poly_vec[i][1];
00268     }
00269 
00270   
00271   
00272   for (int i=min_y; i<max_y; i++)
00273     {
00274       for (int j=min_x; j<max_x; j++)
00275         {
00276           int in;
00277           in = pnpoly(counter, poly_vec, j, i);
00278           if (in == 1)
00279             {
00280               in_indices.push_back((i)*width+j);
00281               counter_ind ++;
00282             }
00283         }
00284     }
00285   
00286   cvDestroyWindow("Select");
00287 }
00288 
00289 
00290 int UI::pnpoly(int npol, std::vector<std::vector<int > > poly_vec, int x, int y)
00291 {
00292   int i, j, c = 0;
00293   for (i = 0, j = npol-1; i < npol; j = i++) 
00294     {
00295       if ((((poly_vec[i][1] <= y) && (y < poly_vec[j][1])) ||
00296            ((poly_vec[j][1] <= y) && (y < poly_vec[i][1]))) &&
00297           (x < (poly_vec[j][0] - poly_vec[i][0]) * (y - poly_vec[i][1]) / (poly_vec[j][1] - poly_vec[i][1]) + poly_vec[i][0]))
00298         c = !c;
00299     }
00300   return c;   
00301 }
00302 
00303 bool UI::save_image(UI_segment_object::Save::Request ®, UI_segment_object::Save::Response &res)
00304 {
00305   
00306   m.lock();
00307   cv_image = bridge_.imgMsgToCv(ros::topic::waitForMessage<sensor_msgs::Image>("/camera/rgb/image_color", nh_), "bgr8");
00308   cvSaveImage(reg.file.c_str(), cv_image);
00309   m.unlock();
00310   res.state = true;
00311   return(true);
00312 }
00313 
00314 
00315 
00316 
00317 class PointCloudPub {
00318 
00319 public:
00320   PointCloudPub(ros::NodeHandle &nh);
00321   ~PointCloudPub();
00322   
00323   void publish_region(const sensor_msgs::PointCloud2 &msg);
00324   void publish_object(const sensor_msgs::PointCloud2 &msg);
00325   sensor_msgs::PointCloud2 cloud_callback(const sensor_msgs::PointCloud2ConstPtr& msg);
00326   bool get_cloud(UI_segment_object::GetObject::Request ®, UI_segment_object::GetObject::Response &res);
00327   bool get_pt(UI_segment_object::GetPt::Request ®, UI_segment_object::GetPt::Response &res);
00328   bool reset_plane_coeff(UI_segment_object::None_Bool::Request ®, UI_segment_object::None_Bool::Response &res);
00329   bool save_cloud(UI_segment_object::Save::Request ®, UI_segment_object::Save::Response &res);
00330   geometry_msgs::Point pt_callback(const sensor_msgs::PointCloud2ConstPtr& msg);
00331   UI::UI ui;
00332 
00333 
00334 protected:
00335   ros::NodeHandle nh_;
00336   ros::Publisher pub_region_;
00337   ros::Publisher pub_object_;
00338   pcl::PointCloud<pcl::PointXYZ> cloud_plane_; 
00339   pcl::PointCloud<pcl::PointXYZRGB> cloud_xyz_rgb;
00340   pcl::PointCloud<pcl::PointXYZRGB> cloud_xyz_rgb2;
00341   sensor_msgs::PointCloud2::ConstPtr cloud_msg;
00342   sensor_msgs::PointCloud2::ConstPtr ptcloud2_xyz_rgb;
00343   pcl::ModelCoefficients coefficients;
00344   pcl::SACSegmentation<pcl::PointXYZRGB> seg;  
00345   pcl::PointIndices inliers;
00346   bool new_plane_coeff;
00347   bool transform_pts;
00348   std::string transform_pts_frame_id;
00349 };
00350 
00351 PointCloudPub::PointCloudPub(ros::NodeHandle &nh):
00352     ui(nh)
00353 {
00354   nh_ = nh;
00355   pub_region_ = nh_.advertise<sensor_msgs::PointCloud2>("segment_plane", 1);
00356   pub_object_ = nh_.advertise<sensor_msgs::PointCloud2>("segment_object", 1);
00357   
00358   new_plane_coeff = true;
00359   seg.setOptimizeCoefficients (true);
00360   seg.setModelType (pcl::SACMODEL_PLANE);
00361   seg.setMethodType (pcl::SAC_RANSAC);
00362   seg.setDistanceThreshold (0.01);
00363   seg.setProbability(0.98);
00364 
00365   while (nh_.getParam("/transform_cloud/use", transform_pts) == false)
00366     {
00367       std::cerr << "waiting for boolean param to transform pts or not ... \n";
00368       sleep(0.05);
00369     }
00370   if (transform_pts == true)
00371     {
00372       while (nh_.getParam("/transform_cloud/frame_id", transform_pts_frame_id) == false)
00373         {
00374           std::cerr << "waiting for frame_id to transform pts ... \n";
00375           sleep(0.05);
00376         }
00377     }
00378 }
00379 
00380 PointCloudPub::~PointCloudPub()
00381 {
00382 }
00383 
00384 
00385 void PointCloudPub::publish_region(const sensor_msgs::PointCloud2 &msg)
00386 {
00387   pub_region_.publish(msg);
00388 }
00389 
00390 void PointCloudPub::publish_object(const sensor_msgs::PointCloud2 &msg)
00391 {
00392   pub_object_.publish(msg);
00393 }
00394 
00395 
00396 bool PointCloudPub::get_cloud(UI_segment_object::GetObject::Request ®, UI_segment_object::GetObject::Response &res)
00397 {
00398   m.lock();
00399   
00400   cloud_msg = ros::topic::waitForMessage<sensor_msgs::PointCloud2>("/camera/rgb/points", nh_, ros::Duration(30.0));
00401 
00402   if (done == 0)
00403     {
00404       ui.cloud_callback();
00405     }
00406   
00407   
00408 
00409   sensor_msgs::PointCloud2 msg2 = cloud_callback(cloud_msg);
00410   
00411   m.unlock();
00412   return (true);
00413 }
00414 
00415 
00416 bool PointCloudPub::save_cloud(UI_segment_object::Save::Request ®, UI_segment_object::Save::Response &res)
00417 {
00418   m.lock();
00419   pcl::io::savePCDFileASCII (reg.file, cloud_xyz_rgb);
00420   res.state = true;
00421   m.unlock();
00422   return(true);
00423 }
00424 
00425 
00426 bool PointCloudPub::reset_plane_coeff(UI_segment_object::None_Bool::Request ®, UI_segment_object::None_Bool::Response &res)
00427 {
00428   new_plane_coeff = true;
00429   res.state = true;
00430   return (true);
00431 }
00432 
00433 
00435 bool PointCloudPub::get_pt(UI_segment_object::GetPt::Request ®, UI_segment_object::GetPt::Response &res)
00436 {
00437   
00438 
00439   cloud_msg = ros::topic::waitForMessage<sensor_msgs::PointCloud2>("/camera/rgb/points", nh_, ros::Duration(30.0));
00440 
00441   if (done == 0)
00442     {
00443       ui.pt_callback();
00444     }
00445   geometry_msgs::Point pt = pt_callback(cloud_msg);
00446   res.pt = pt;
00447 
00448   return (true);
00449 }
00450 
00451 geometry_msgs::Point PointCloudPub::pt_callback(const sensor_msgs::PointCloud2ConstPtr& msg)
00452 {
00453   m.lock();
00454   pcl::PointCloud<pcl::PointXYZ> cloud_xyz;
00455   pcl::fromROSMsg(*msg, cloud_xyz);
00456 
00457   geometry_msgs::Point pt;
00458 
00459   pt.x = cloud_xyz.points[in_indices[0]].x;
00460   pt.y = cloud_xyz.points[in_indices[0]].y;
00461   pt.z = cloud_xyz.points[in_indices[0]].z;
00462   std::cerr << "here is ind :" << in_indices[0] << std::endl;
00463   std::cerr << "here is pt :" << pt.x << "\t" << pt.y << "\t" << pt.z << std::endl;
00464   m.unlock();
00465   return pt;
00466 }
00467 
00469 
00470 sensor_msgs::PointCloud2 PointCloudPub::cloud_callback(const sensor_msgs::PointCloud2ConstPtr& msg)
00471 {
00472   tf::TransformListener tf_listener;
00473 
00474   pcl::PointCloud<pcl::PointXYZRGB> pt_cloud_before_trans;
00475   pcl::PointCloud<pcl::PointXYZ> cloud_xyz;
00476   pcl::PointCloud<pcl::PointXYZ> cloud_xyz2;
00477 
00478   pcl::PointCloud<pcl::PointXYZRGB> cloud_plane;  
00479   sensor_msgs::PointCloud2 object;
00480   sensor_msgs::PointCloud2 region;
00481   std::cerr << "Point cloud data: " << msg->height*msg->width << " points" << std::endl;
00482   
00483   
00484   
00485   
00486   
00487   pcl::fromROSMsg(*msg, cloud_xyz);
00488 
00489   if (transform_pts == true)
00490     {
00491       pcl::fromROSMsg(*msg, pt_cloud_before_trans);
00492       tf::StampedTransform transform;
00493       tf_listener.waitForTransform(transform_pts_frame_id, "/openni_rgb_optical_frame2", ros::Time(0), ros::Duration(5.0));
00494       tf_listener.lookupTransform(transform_pts_frame_id, "/openni_rgb_optical_frame2", ros::Time(0), transform);
00495       pcl_ros::transformPointCloud(pt_cloud_before_trans, cloud_xyz_rgb, transform);
00496     }
00497   else
00498     {
00499       pcl::fromROSMsg(*msg, cloud_xyz_rgb);
00500     }
00501 
00502   pcl::ExtractIndices<pcl::PointXYZRGB> extract;
00503 
00504   
00505   pcl::PointIndices ui_ind;
00507   for (int i = 0; i < counter_ind ; i++)
00508     {
00509       ui_ind.indices.push_back(in_indices[i]);
00510     }
00511   
00512   extract.setInputCloud(cloud_xyz_rgb.makeShared());
00513 
00514   extract.setIndices(boost::make_shared<pcl::PointIndices>(ui_ind));
00515   extract.setNegative(false);
00516   extract.filter(cloud_xyz_rgb2);
00517   pcl::toROSMsg(cloud_xyz_rgb2, region);
00518   publish_region(region);
00519 
00520   if (new_plane_coeff==true)
00521     {
00522       new_plane_coeff = false;
00523       
00524       
00525     }
00526 
00527   seg.setInputCloud (cloud_xyz_rgb2.makeShared());
00528   seg.segment (inliers, coefficients);
00529 
00530   extract.setInputCloud(cloud_xyz_rgb2.makeShared());
00531   extract.setIndices(boost::make_shared<pcl::PointIndices>(inliers));
00532   extract.setNegative(true);
00533   extract.filter(cloud_plane);
00534 
00535   pcl::toROSMsg(cloud_plane, object);
00536   publish_object(object);
00537 
00538   if (inliers.indices.size () == 0)
00539     {
00540       ROS_ERROR ("Could not estimate a planar model for the given dataset.");
00541     }
00542 
00543   std::cerr << "Model coefficients: " << coefficients.values[0] << " " << coefficients.values[1] << " "
00544             << coefficients.values[2] << " " << coefficients.values[3] << std::endl;
00545 
00546   return object;
00547 }
00548 
00549 
00550 int main (int argc, char** argv)
00551 {
00552   ros::init(argc, argv, "segment_object");
00553   ros::NodeHandle nh;
00554   PointCloudPub pcb(nh);
00555   ros::ServiceServer service = nh.advertiseService("get_object_on_plane", &PointCloudPub::get_cloud, &pcb);
00556   ros::ServiceServer service2 = nh.advertiseService("get_3D_pt", &PointCloudPub::get_pt, &pcb);
00557   ros::ServiceServer service3 = nh.advertiseService("save_pt_cloud", &PointCloudPub::save_cloud, &pcb);
00558   
00559   ros::spin();
00560 
00561   return (0);
00562 }