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 }