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 #include <ros/ros.h>
00034 #include <std_msgs/String.h>
00035
00036 #include <sensor_msgs/CameraInfo.h>
00037 #include <stereo_msgs/DisparityImage.h>
00038
00039 #include <fast_plane_detection/Plane.h>
00040
00041 #include <visualization_msgs/Marker.h>
00042
00043 #include <tf/transform_listener.h>
00044
00045 #include <cv_bridge/cv_bridge.h>
00046 #include <sensor_msgs/image_encodings.h>
00047 #include <opencv2/imgproc/imgproc.hpp>
00048 #include <opencv2/highgui/highgui.hpp>
00049
00050 #include "fast_plane_detector/plane_detection.h"
00051 #include "fast_plane_detector/plane_transform.h"
00052
00053 #include "fast_plane_detector/timercpu.h"
00054 #include "fast_plane_detector/utils.h"
00055
00056 #include <fast_plane_detection/SetPosition.h>
00057
00058 namespace enc = sensor_msgs::image_encodings;
00059
00060 #define PI 3.1415926535897932384626433832795
00061
00062 namespace fast_plane_detection {
00063
00064 class FastRegionPlaneDetector
00065 {
00066
00067 private:
00068
00069 bool maskDisparityImage( const stereo_msgs::DisparityImage::ConstPtr& disparity,
00070 const stereo_msgs::DisparityImage::Ptr &masked_disparity);
00072 ros::NodeHandle root_nh_;
00074 ros::NodeHandle priv_nh_;
00075
00077 ros::Subscriber disparity_image_sub_;
00078 std::string disparity_image_topic_;
00079
00081 int buffer_size_;
00082
00084 stereo_msgs::DisparityImage::ConstPtr disparity_image_;
00085
00087 stereo_msgs::DisparityImage disparity_masked_;
00088 stereo_msgs::DisparityImage::Ptr disparity_masked_ptr;
00089
00091 ros::Publisher plane_marker_pub_;
00092
00094 ros::Publisher plane_msg_pub_;
00095
00097 ros::Publisher disparity_image_pub_;
00098
00100 ros::Publisher hist_image_pub_;
00101 ros::Publisher hist_image_x_pub_;
00102
00104 ros::Publisher labels_pub_;
00105
00106 tf::TransformListener listener_;
00107
00109 PlaneDetection* plane_detect_y_;
00110
00112 PlaneDetection* plane_detect_x_;
00113
00115 bool find_table_;
00116
00118 PlaneTransform* plane_transform_;
00119
00121 double up_direction_;
00122
00124 int inlier_threshold_;
00125
00126
00127 ros::ServiceServer srv_position_;
00128 double X;
00129 double Y;
00130 double Z;
00131 bool transform_;
00132
00133
00135 geometry_msgs::Vector3Stamped point_;
00136 int region_width_;
00137 int region_height_;
00138
00139 int marker_id_;
00140
00141 float fx_;
00142 float fy_;
00143 float cx_;
00144 float cy_;
00145
00146 public:
00147
00148 FastRegionPlaneDetector( int buffer_size );
00149 ~FastRegionPlaneDetector();
00150
00151
00152
00154 void planeCallback(const stereo_msgs::DisparityImage::ConstPtr&
00155 disparity_image);
00156
00157
00158 bool setPosition(fast_plane_detection::SetPosition::Request& req,
00159 fast_plane_detection::SetPosition::Response& resp);
00160
00161
00162
00164 Plane plane_;
00165
00166 };
00167
00168
00169 FastRegionPlaneDetector::FastRegionPlaneDetector( int buffer_size)
00170 : root_nh_("")
00171 , priv_nh_("~")
00172 , buffer_size_(buffer_size)
00173 , X(-0.11f)
00174 , Y(0.01f)
00175
00176
00177
00178
00179 , Z(1)
00180 , transform_(false)
00181 , region_width_(20)
00182 , region_height_(20)
00183 , marker_id_(354345)
00184 , fx_(937.91)
00185 , fy_(937.91)
00186 , cx_(298.41)
00187 , cy_(256.18)
00188 {
00189
00190
00191 priv_nh_.param<std::string>("disparity_image_topic",
00192 disparity_image_topic_,
00193 "/narrow_stereo_textured/disparity");
00194 priv_nh_.param<bool>("find_table",
00195 find_table_,
00196 false);
00197 priv_nh_.param<double>("up_direction",
00198 up_direction_,
00199 -1.0f);
00200 priv_nh_.param<int>("inlier_threshold",
00201 inlier_threshold_,
00202 300);
00203
00204
00205
00206
00207 if (transform_)
00208 point_.header.frame_id = "torso_lift_link";
00209 else
00210 point_.header.frame_id = "narrow_stereo_optical_frame";
00211 point_.header.stamp = ros::Time::now();
00212 point_.vector.x = 0.0;
00213 point_.vector.y = 0.0;
00214 point_.vector.z = 1.0;
00215
00216
00217
00218
00219 while (! disparity_image_){
00220 ROS_INFO_STREAM(" Waiting for message on topic "
00221 << disparity_image_topic_);
00222 disparity_image_ = ros::topic::waitForMessage<stereo_msgs::DisparityImage>
00223 (disparity_image_topic_, root_nh_, ros::Duration(1.0));
00224 }
00225
00226
00227 disparity_masked_.header = disparity_image_->header;
00228 disparity_masked_.image.header = disparity_image_->image.header;
00229 disparity_masked_.image.height = disparity_image_->image.height;
00230 disparity_masked_.image.width = disparity_image_->image.width;
00231 disparity_masked_.image.encoding = disparity_image_->image.encoding;
00232 disparity_masked_.image.is_bigendian = disparity_image_->image.is_bigendian;
00233
00234
00235 disparity_masked_.image.step = disparity_image_->image.step;
00236 size_t size
00237 = disparity_masked_.image.step * disparity_masked_.image.height;
00238 disparity_masked_.image.data.resize(size, 0);
00239
00240 disparity_masked_.f = disparity_image_->f;
00241 disparity_masked_.T = disparity_image_->T;
00242 disparity_masked_.min_disparity = disparity_image_->min_disparity;
00243 disparity_masked_.max_disparity = disparity_image_->max_disparity;
00244 disparity_masked_.delta_d = disparity_image_->delta_d;
00245
00246
00247
00248
00249
00250
00251 float drange = disparity_image_->max_disparity -
00252 disparity_image_->min_disparity;
00253 int w = disparity_image_->image.width;
00254 int h = disparity_image_->image.height;
00255
00256 plane_detect_y_ = new PlaneDetection((int)drange, w, h, find_table_,
00257 disparity_image_->image.header);
00258
00259 plane_detect_x_ = new PlaneDetection((int)drange, w, h, find_table_,
00260 disparity_image_->image.header,
00261 false);
00262
00263 plane_transform_ = new PlaneTransform( fx_, fy_, cx_, cy_,
00264 disparity_image_->T,
00265 up_direction_);
00266
00267
00268 std::string topic_disp = root_nh_.resolveName("disparity_in");
00269
00270 disparity_image_sub_ = root_nh_.subscribe(topic_disp,
00271 buffer_size_,
00272 &FastRegionPlaneDetector::planeCallback,
00273 this);
00274
00275
00276 plane_marker_pub_ = root_nh_.advertise<visualization_msgs::Marker>("region_plane_markers", 1);
00277
00278
00279 plane_msg_pub_ = root_nh_.advertise<Plane>("region_plane_msg", 1);
00280
00281
00282 std::string topic = root_nh_.resolveName("/plane_detection/masked_disparity");
00283 disparity_image_pub_
00284 = root_nh_.advertise<stereo_msgs::DisparityImage>(topic, 1);
00285
00286
00287 topic = root_nh_.resolveName("/plane_detection/hist_y");
00288 hist_image_pub_
00289 = root_nh_.advertise<sensor_msgs::Image>(topic, 1);
00290
00291 topic = root_nh_.resolveName("/plane_detection/hist_x");
00292 hist_image_x_pub_
00293 = root_nh_.advertise<sensor_msgs::Image>(topic, 1);
00294
00295 topic = root_nh_.resolveName("/plane_detection/labels");
00296 labels_pub_
00297 = root_nh_.advertise<sensor_msgs::Image>(topic, 1);
00298
00299
00300 srv_position_ = root_nh_.advertiseService("set_position", &FastRegionPlaneDetector::setPosition, this);
00301
00302 }
00303
00304 FastRegionPlaneDetector::~FastRegionPlaneDetector()
00305 {
00306 delete plane_detect_y_;
00307 delete plane_detect_x_;
00308 delete plane_transform_;
00309 }
00310
00311
00312 void FastRegionPlaneDetector::planeCallback(const stereo_msgs::DisparityImage::ConstPtr& disparity_image)
00313 {
00314 TimerCPU timer(2800);
00315
00316 stereo_msgs::DisparityImage::Ptr disparity_masked_ptr
00317 = boost::make_shared<stereo_msgs::DisparityImage> (disparity_masked_);
00318
00319
00320 if(!maskDisparityImage( disparity_image,
00321 disparity_masked_ptr)) {
00322 ROS_WARN("Could not project input point to disparity image");
00323 plane_.result = Plane::OTHER_ERROR;
00324 return;
00325 }
00326
00327 disparity_image_pub_.publish(*disparity_masked_ptr);
00328 plane_detect_y_->Update(disparity_masked_ptr);
00329
00330 float spread_y = plane_detect_y_->GetSpreadY();
00331
00332 float alpha_y, beta_y, d_y;
00333 int min_x_y, max_x_y, min_y_y, max_y_y;
00334 plane_detect_y_->GetPlaneParameters( alpha_y, beta_y, d_y,
00335 min_x_y, max_x_y,
00336 min_y_y, max_y_y);
00337
00338 float alpha_x, beta_x, d_x;
00339 int min_x_x, max_x_x, min_y_x, max_y_x;
00340 plane_detect_x_->Update(disparity_masked_ptr);
00341 float spread_x = plane_detect_x_->GetSpreadX();
00342 plane_detect_x_->GetPlaneParameters( alpha_x, beta_x, d_x,
00343 min_x_x, max_x_x,
00344 min_y_x, max_y_x);
00345
00346 ROS_INFO("Error values - Y: %f - X: %f", spread_y, spread_x);
00347 float alpha, beta, d;
00348 int min_x, max_x, min_y, max_y;
00349 float spread;
00350
00351 int n_inliers;
00352 int n_disps;
00353 float mean_error;
00354 if(spread_y>=spread_x) {
00355
00356 alpha = alpha_x;
00357 beta = beta_x;
00358 d = d_x;
00359 min_x = min_x_x;
00360 min_y = min_y_x;
00361 max_x = max_x_x;
00362 max_y = max_y_x;
00363 plane_detect_x_->GetNInliers(n_inliers);
00364 plane_detect_x_->GetNDisp(n_disps);
00365 mean_error = spread_x;
00366 } else {
00367 alpha = alpha_y;
00368 beta = beta_y;
00369 d = d_y;
00370 min_x = min_x_y;
00371 min_y = min_y_y;
00372 max_x = max_x_y;
00373 max_y = max_y_y;
00374 plane_detect_y_->GetNInliers(n_inliers);
00375 plane_detect_y_->GetNDisp(n_disps);
00376 mean_error = spread_y;
00377 }
00378
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489 sensor_msgs::Image labels;
00490 plane_detect_y_->GetLabels(labels);
00491 labels_pub_.publish(labels);
00492
00493 int n_labels = 0;
00494 for(unsigned int i=0; i<labels.height; ++i)
00495 for(unsigned int j=0; j<labels.width; ++j){
00496 int adr = i*labels.width+j;
00497 if(labels.data[adr]==255)
00498 n_labels++;
00499 }
00500
00501
00502 int percentage_disp_inliers = 100 * (float)n_inliers/(float)n_disps;
00503 ROS_INFO("Number of inliers %d, Number of valid disparities %d, Ratio %d ", n_inliers, n_disps, percentage_disp_inliers);
00504
00505 float percentage_inliers =
00506 100.0f *n_inliers/(float)(region_width_ * region_height_);
00507
00508 ROS_INFO("Number of inliers %d, Region Size %d, Ratio %f ",
00509 n_inliers, region_width_ * region_height_,
00510 percentage_inliers);
00511
00512
00513 inlier_threshold_ = (region_width_ * region_height_)/3;
00514
00515 if(n_inliers<inlier_threshold_){
00516 ROS_WARN("Plane has only %d inliers", n_inliers);
00517 plane_.result = Plane::FEW_INLIERS;
00518 return;
00519 } else {
00520 plane_.result = Plane::SUCCESS;
00521 }
00522
00523 ROS_INFO("Mean Squared error of detected Plane: %f", mean_error );
00524
00525 plane_transform_->setParameters( alpha,
00526 beta,
00527 d,
00528 min_x, max_x,
00529 min_y, max_y,
00530 disparity_image->header);
00531
00532 if(!plane_transform_->getPlane(plane_)) {
00533 ROS_WARN("No Plane found");
00534 plane_.result = Plane::NO_PLANE;
00535 return;
00536 } else {
00537
00538 float a = plane_.normal.vector.x;
00539 float b = plane_.normal.vector.y;
00540 ROS_INFO("Angle %f", acos( -plane_.normal.vector.z)*PI/180.0f );
00541
00542
00543 plane_.error = mean_error;
00544 plane_.percentage_inliers = percentage_inliers;
00545 plane_.percentage_disp_inliers = percentage_disp_inliers;
00546 plane_.percentage_valid_disp = n_disps;
00547
00548 visualization_msgs::Marker delete_marker;
00549 delete_marker.header.stamp = ros::Time::now();
00550 delete_marker.header.frame_id = disparity_image->header.frame_id;
00551 delete_marker.id = marker_id_;
00552 delete_marker.action = visualization_msgs::Marker::DELETE;
00553 delete_marker.ns = "tabletop_node";
00554 plane_marker_pub_.publish(delete_marker);
00555
00556 visualization_msgs::Marker planeMarker
00557 = getPlaneMarker( plane_.top_left,
00558 plane_.top_right,
00559 plane_.bottom_left,
00560 plane_.bottom_right);
00561 planeMarker.header = disparity_image->header;
00562 planeMarker.pose = plane_.pose.pose;
00563 planeMarker.ns = "tabletop_node";
00564 planeMarker.id = marker_id_;
00565 plane_marker_pub_.publish(planeMarker);
00566
00567 }
00568
00569 ROS_INFO_STREAM("Time: " << timer.read() << " ms");
00570
00571 plane_msg_pub_.publish(plane_);
00572
00573 }
00574
00575
00576 bool
00577 FastRegionPlaneDetector::maskDisparityImage( const stereo_msgs::DisparityImage::ConstPtr& disparity, const stereo_msgs::DisparityImage::Ptr &masked_disparity)
00578
00579 {
00580
00581
00582 if (transform_)
00583 point_.header.frame_id = "torso_lift_link";
00584 else
00585 point_.header.frame_id = "narrow_stereo_optical_frame";
00586
00587 point_.header.stamp = disparity->header.stamp;
00588 point_.vector.x = X;
00589 point_.vector.y = Y;
00590 point_.vector.z = Z;
00591
00592 float f = disparity->f;
00593 float T = disparity->T;
00594
00595 if(point_.header.frame_id!=disparity->header.frame_id){
00596
00597 std::string error_msg;
00598
00599 if (!listener_.canTransform(point_.header.frame_id,
00600 disparity->header.frame_id,
00601 disparity->header.stamp, &error_msg)) {
00602 ROS_ERROR("Cannot transform point cloud from frame %s to %s; error %s",
00603 point_.header.frame_id.c_str(),
00604 disparity->header.frame_id.c_str(), error_msg.c_str());
00605 return false;
00606 } try {
00607 listener_.transformVector(disparity->header.frame_id,
00608 point_, point_);
00609 } catch (tf::TransformException ex) {
00610 ROS_ERROR("Failed to transform point cloud from frame %s into %s; error %s",
00611 point_.header.frame_id.c_str(),
00612 disparity->header.frame_id.c_str(), ex.what());
00613 return false;
00614 }
00615 }
00616 point_.header.frame_id = disparity->header.frame_id;
00617
00618
00619 int u = point_.vector.x/point_.vector.z * fx_ + cx_;
00620 int v = point_.vector.y/point_.vector.z * fy_ + cy_;
00621
00622 int d = (f*T)/point_.vector.z;
00623
00624 ROS_INFO("Pixel position of 3D point %d %d ", u, v);
00625
00626 float *dimd_in = (float*)&(disparity->image.data[0]);
00627 float *dimd_out = (float*)&(masked_disparity->image.data[0]);
00628
00629 for (int y=0;y<(int)masked_disparity->image.height; y++) {
00630 for (int x=0;x< (int)masked_disparity->image.width; x++) {
00631 int adr = y*masked_disparity->image.width+x;
00632 if(x>u-region_width_/2 && x<u+region_width_/2 &&
00633 y>v-region_height_/2 && y<v+region_height_/2){
00634 dimd_out[adr] = dimd_in[adr];
00635 } else dimd_out[adr] = -1.0f;
00636 }
00637 }
00638
00639 return true;
00640 }
00641
00643 bool FastRegionPlaneDetector::setPosition(fast_plane_detection::SetPosition::Request& req,
00644 fast_plane_detection::SetPosition::Response& resp)
00645 {
00646 X = req.x;
00647 Y = req.y;
00648 Z = req.z;
00649 transform_ = req.transform;
00650 ROS_INFO("Fast Plane Detector: Position changed");
00651
00652 resp.x = X;
00653 resp.y = Y;
00654 resp.z = Z;
00655 resp.transform = transform_;
00656 return true;
00657 }
00658
00659 }
00660
00661
00662
00663
00664 int main(int argc, char **argv)
00665 {
00666 ros::init(argc, argv, "fast_plane_detection_node");
00667
00669 int buffer_size_ = 1;
00670 fast_plane_detection::FastRegionPlaneDetector node_(buffer_size_);
00671 ros::spin();
00672
00673 return 0;
00674 }