object_segmentation_rviz_ui.cpp
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009, Willow Garage, Inc.
00003  * All rights reserved.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  *
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00014  *       contributors may be used to endorse or promote products derived from
00015  *       this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00018  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00021  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00022  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00023  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00024  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00025  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00026  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00027  * POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00030 #include <QMouseEvent>
00031 
00032 #include "object_segmentation_gui/object_segmentation_rviz_ui.h"
00033 
00034 #include "rviz_interaction_tools/image_tools.h"
00035 #include "rviz_interaction_tools/image_overlay.h"
00036 #include "rviz_interaction_tools/camera_tools.h"
00037 #include "rviz_interaction_tools/unique_string_manager.h"
00038 
00039 #include <rviz/window_manager_interface.h>
00040 #include <rviz/render_panel.h>
00041 #include <rviz/visualization_manager.h>
00042 #include <rviz/validate_floats.h>
00043 #include <rviz/frame_manager.h>
00044 
00045 #include <OGRE/OgreRenderWindow.h>
00046 #include <OGRE/OgreRoot.h>
00047 
00048 #include "tabletop_object_detector/marker_generator.h"
00049 
00050 #include "pcl/point_cloud.h"
00051 #include "pcl/point_types.h"
00052 #include "pcl/filters/statistical_outlier_removal.h"
00053 #include "pcl/filters/voxel_grid.h"
00054 
00055 #include <sensor_msgs/PointCloud.h>
00056 #include <sensor_msgs/PointCloud2.h>
00057 #include <sensor_msgs/point_cloud_conversion.h>
00058 #include <sensor_msgs/image_encodings.h>
00059 
00060 #include "ui_main_frame.h" // generated by uic during build from main_frame.ui
00061 
00062 namespace enc = sensor_msgs::image_encodings;
00063 
00064 // Does not work right now, probably colliding with OGRE in Rviz
00065 //#define USE_CUDA
00066 
00067 #define MAX_FG 6
00068 
00069 namespace object_segmentation_gui
00070 {
00071 
00072 typedef pcl::PointXYZ PCL_Point;
00073 
00074 static const char
00075     * HELP_TEXT =
00076         "Left Mouse Button: Click on objects or drag a rectangle to segment them. \n\
00077      Segment Button: Start Segmentation. \n\
00078      Reset Button: Reset Segmentation and Seeds. \n\
00079      Cancel Button: Cancel Segmentation. \n\
00080      OK Button: Accept Segmentation. ";
00081 
00082 ObjectSegmentationRvizUI::ObjectSegmentationRvizUI( rviz::VisualizationManager *visualization_manager, QWidget* parent )
00083   : QWidget( parent )
00084   , object_segmentation_server_(0)
00085   , nh_("")
00086   , priv_nh_("~")
00087   , n_iter_(2)
00088   , use_gpu_(false)
00089   , object_segmenter_(0)
00090   , num_fg_hypos_(0)
00091   , running_(false)
00092   , paused_(true)
00093   , num_markers_published_(1)
00094   , current_marker_id_(1)
00095   , ui_( new Ui::MainFrame )
00096 {
00097   // Set up UI and make connections.
00098   ui_->setupUi( this );
00099 
00100   render_panel_ = ui_->render_panel_;
00101   render_panel_->installEventFilter( this ); // process mouse events on the render_panel_ here, in eventFilter().
00102 
00103   connect( ui_->accept_button_, SIGNAL( clicked() ), this, SLOT( acceptButtonClicked() ));
00104   connect( ui_->cancel_button_, SIGNAL( clicked() ), this, SLOT( cancelButtonClicked() ));
00105   connect( ui_->reset_button_, SIGNAL( clicked() ), this, SLOT( resetButtonClicked() ));
00106   connect( ui_->restart_button_, SIGNAL( clicked() ), this, SLOT( restartButtonClicked() ));
00107   connect( ui_->segment_button_, SIGNAL( clicked() ), this, SLOT( segmentButtonClicked() ));
00108 
00109   connect( ui_->with_surface_, SIGNAL( toggled( bool )), this, SLOT( withSurfaceChecked() ));
00110   connect( ui_->with_disparity_, SIGNAL( toggled( bool )), this, SLOT( withDisparityChecked() ));
00111   connect( ui_->with_color_, SIGNAL( toggled( bool )), this, SLOT( withColorChecked() ));
00112   connect( ui_->with_holes_, SIGNAL( toggled( bool )), this, SLOT( withHolesChecked() ));
00113   connect( ui_->uniform_, SIGNAL( toggled( bool )), this, SLOT( uniformChecked() ));
00114 
00115   connect( ui_->grad_weight_slider_, SIGNAL( valueChanged( int )), this, SLOT( gradWeightChanged( int )));
00116   connect( ui_->grad_weight_slider_, SIGNAL( valueChanged( int )), ui_->grad_weight_value_label_, SLOT( setNum( int )));
00117 
00119   //    image_transport::ImageTransport it_(nh_);
00120   //    image_pub_ = it_.advertise("rgb_out", 1);
00121 
00122   rviz_interaction_tools::UniqueStringManager usm;
00123 
00124   //construct basic ogre scene
00125   scene_manager_ = Ogre::Root::getSingleton().createSceneManager(
00126       Ogre::ST_GENERIC, usm.unique("ObjectSegmentationRvizUI"));
00127 
00128   scene_root_ = scene_manager_->getRootSceneNode()->createChildSceneNode();
00129 
00130   image_overlay_ = new rviz_interaction_tools::ImageOverlay(scene_root_,
00131       Ogre::RENDER_QUEUE_OVERLAY - 2);
00132 
00133   //put a render panel into the window
00134   setupRenderPanel(visualization_manager);
00135 
00136   setWindowTitle( "Interactive Object Segmentation" );
00137   ui_->bottom_label_->setText( HELP_TEXT );
00138 
00139   click_info_.down_ = false;
00140   click_info_.down_x_ = click_info_.down_y_ = 0;
00141 
00142   marker_pub_ = nh_.advertise<visualization_msgs::Marker> (nh_.resolveName(
00143       "tabletop_segmentation_markers"), 10);
00144 
00145   box_object_ = scene_manager_->createManualObject("SelectRegionIndicator");
00146   box_object_->setUseIdentityProjection(true);
00147   box_object_->setUseIdentityView(true);
00148   box_object_->setDynamic(true);
00149   box_object_->begin("BaseWhiteNoLighting",
00150       Ogre::RenderOperation::OT_LINE_STRIP);
00151   box_object_->position(0.0, 0.0, 0.0);
00152   box_object_->position(0.0, 0.0, 0.0);
00153   box_object_->position(0.0, 0.0, 0.0);
00154   box_object_->position(0.0, 0.0, 0.0);
00155   box_object_->index(0);
00156   box_object_->index(1);
00157   box_object_->index(2);
00158   box_object_->index(3);
00159   box_object_->index(0);
00160   box_object_->end();
00161   Ogre::AxisAlignedBox aabInf;
00162   aabInf.setInfinite();
00163   box_object_->setBoundingBox(aabInf);
00164   //click indicator will be rendered last
00165   box_object_->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY);
00166   scene_root_->attachObject(box_object_);
00167 
00168   priv_nh_.param<int> ("inlier_threshold", inlier_threshold_, 300);
00169   priv_nh_.param<double> ("up_direction", up_direction_, -1.0);
00170 
00171   priv_nh_.param<double> ("mean_k", mean_k_, 50.0);
00172   priv_nh_.param<double> ("std", std_, 1.0);
00173 
00174   priv_nh_.param<double> ("clustering_voxel_size", clustering_voxel_size_,
00175       0.003);
00176 
00177   nh_.param<double> ("grad_weight", grad_weight_, 80.0);
00178 
00179   nh_.param<double> ("window_size", window_size_, 0.10);
00180 
00181   nh_.param<double> ("ball_size", ball_size_, 0.10);
00182 
00183   object_segmenter_ = new ObjectSegmenter(grad_weight_, n_iter_, use_gpu_,
00184       window_size_, ball_size_);
00185 
00186 }
00187 
00188 ObjectSegmentationRvizUI::~ObjectSegmentationRvizUI()
00189 {
00190   if (object_segmentation_server_)
00191     stopActionServer();
00192 
00193   render_panel_->getRenderWindow()->setActive(false);
00194   delete render_panel_;
00195   delete image_overlay_;
00196   delete object_segmenter_;
00197 }
00198 
00199 void ObjectSegmentationRvizUI::setupRenderPanel(
00200     rviz::VisualizationManager *visualization_manager )
00201 {
00202   render_panel_->initialize(scene_manager_, visualization_manager);
00203 
00204   render_panel_->setAutoRender(false);
00205   render_panel_->getViewport()->setOverlaysEnabled(false);
00206   render_panel_->getViewport()->setClearEveryFrame(true);
00207   render_panel_->getRenderWindow()->setAutoUpdated(false);
00208   render_panel_->getRenderWindow()->setActive(true);
00209 }
00210 
00211 void ObjectSegmentationRvizUI::startActionServer( ros::NodeHandle &node_handle )
00212 {
00213   if (object_segmentation_server_)
00214   {
00215     ROS_ERROR( "ObjectSegmentationGuiAction server already started!" );
00216     return;
00217   }
00218 
00219   ROS_INFO("Starting ObjectSegmentationGuiAction server.");
00220 
00221   //create non-threaded action server
00222   object_segmentation_server_ = new actionlib::SimpleActionServer<
00223       ObjectSegmentationGuiAction>(node_handle, "segmentation_popup", false);
00224 
00225   object_segmentation_server_->registerGoalCallback(boost::bind(
00226       &ObjectSegmentationRvizUI::acceptNewGoal, this));
00227   object_segmentation_server_->registerPreemptCallback(boost::bind(
00228       &ObjectSegmentationRvizUI::preempt, this));
00229 
00230   object_segmentation_server_->start();
00231 }
00232 
00233 void ObjectSegmentationRvizUI::stopActionServer()
00234 {
00235   if (!object_segmentation_server_)
00236   {
00237     ROS_ERROR("ObjectSegmentationGuiAction server cannot be stopped because it is not running.");
00238     return;
00239   }
00240 
00241   //if we're currently being active, we have to cancel everything, clean up & hide the window
00242   if (object_segmentation_server_->isActive())
00243   {
00244     ROS_WARN("Aborting ObjectSegmentationGuiAction goal.");
00245     stopSegmentation();
00246     object_segmentation_server_->setAborted();
00247     cleanupAndHide();
00248   }
00249 
00250   ROS_INFO("Stopping ObjectSegmentationGuiAction server.");
00251   delete object_segmentation_server_;
00252   object_segmentation_server_ = 0;
00253 }
00254 
00255 void ObjectSegmentationRvizUI::acceptNewGoal()
00256 {
00257 
00258   // only if segmentation is running labeling can be accepted
00259   ui_->accept_button_->setEnabled(running_);
00260 
00261   // only if segmentation has been run at least once,
00262   // same seed point cloud be reused
00263   ui_->restart_button_->setEnabled(!previous_queue_.empty());
00264 
00265   // only if segmentation is not running, it can be started
00266   ui_->segment_button_->setEnabled(!running_);
00267 
00268   const ObjectSegmentationGuiGoal::ConstPtr &goal =
00269       object_segmentation_server_->acceptNewGoal();
00270 
00271   rviz_interaction_tools::updateCamera(render_panel_->getCamera(),
00272       goal->camera_info);
00273 
00274   ROS_ASSERT( goal->point_cloud.height ==
00275       goal->disparity_image.image.height &&
00276       goal->point_cloud.width ==
00277       goal->disparity_image.image.width);
00278 
00279   current_point_cloud_ = goal->point_cloud;
00280   current_camera_info_ = goal->camera_info;
00281   current_disparity_image_ = goal->disparity_image;
00282   fillRgbImage(current_image_, current_point_cloud_);
00283   //    image_pub_.publish(current_image_);
00284 
00285   float baseline = current_disparity_image_.T;
00286   table_transformer_.setParams(current_camera_info_, baseline, up_direction_);
00287 
00288   //store data for later use in update()
00289   //we can't directly put in in ogre because
00290   //this runs in a different thread
00291   image_overlay_->setImage(current_image_);
00292   image_overlay_->update();
00293 
00294   show();
00295 
00296   click_info_.down_x_ = click_info_.down_y_ = 0;
00297 
00298   // initialise segmentation
00299   object_segmenter_->setNewData(current_image_, current_disparity_image_);
00300 
00301   // set checkboxes accordingly
00302   bool with_colors, with_color_holes, uniform, with_disparities, with_surface;
00303   object_segmenter_->getCurrentSegmFlags(with_colors, with_color_holes,
00304       uniform, with_disparities, with_surface);
00305 
00306   ui_->with_surface_->setChecked(with_surface);
00307   ui_->with_surface_->setEnabled(true);
00308   ui_->with_disparity_->setChecked(with_disparities);
00309   ui_->with_disparity_->setEnabled(true);
00310   ui_->with_color_->setChecked(with_colors);
00311   ui_->with_color_->setEnabled(true);
00312   ui_->with_holes_->setChecked(with_color_holes);
00313   ui_->with_holes_->setEnabled(true);
00314   ui_->uniform_->setChecked(uniform);
00315   ui_->uniform_->setEnabled(true);
00316 
00317   ui_->grad_weight_slider_->setValue( int( grad_weight_ ));
00318 
00319   initStorage(current_image_);
00320 
00321 }
00322 
00323 void ObjectSegmentationRvizUI::initStorage( const sensor_msgs::Image &image )
00324 {
00325   // initialise mask container
00326   inits_.header.frame_id = "narrow_stereo_optical_frame";
00327   inits_.header.stamp = ros::Time::now();
00328   inits_.height = image.height;
00329   inits_.width = image.width;
00330   inits_.encoding = enc::MONO8;
00331   inits_.is_bigendian = false;
00332   inits_.step = image.width;
00333   size_t size = inits_.step * inits_.height;
00334   inits_.data.resize(size);
00335 
00336   texture_buffer_.header = image.header;
00337   texture_buffer_.height = image.height;
00338   texture_buffer_.width = image.width;
00339   texture_buffer_.encoding = enc::RGB8;
00340   texture_buffer_.is_bigendian = false;
00341   texture_buffer_.step = 3 * texture_buffer_.width;
00342   size = texture_buffer_.step * texture_buffer_.height;
00343   texture_buffer_.data.resize(size);
00344 }
00345 
00346 void ObjectSegmentationRvizUI::preempt()
00347 {
00348   stopSegmentation();
00349   object_segmentation_server_->setPreempted();
00350   cleanupAndHide();
00351 }
00352 
00353 void ObjectSegmentationRvizUI::cleanupAndHide()
00354 {
00355   image_overlay_->clear();
00356   ui_->segment_button_->setText("Segment");
00357   paused_ = true;
00358   resetVars();
00359   previous_queue_.clear();
00360   hide();
00361 }
00362 
00363 void ObjectSegmentationRvizUI::stopSegmentation()
00364 {
00365   ObjectSegmenter::Action action;
00366   action.type_ = ObjectSegmenter::STOP;
00367   object_segmenter_->queueAction(action);
00368 }
00369 
00370 void ObjectSegmentationRvizUI::resetVars()
00371 {
00372   for (size_t i = 0; i < clusters_.size(); ++i)
00373     clusters_[i].points.clear();
00374 
00375   clusters_.clear();
00376   segm_size_.clear();
00377   table_points_.points.clear();
00378   num_fg_hypos_ = 0;
00379   color_code_.clear();
00380 
00381   size_t size = inits_.step * inits_.height;
00382   inits_.data.clear();
00383   inits_.data.resize(size, 0);
00384 
00385   labels_.data.clear();
00386   labels_.data.resize(size, 0);
00387 
00388   image_overlay_->setImage(current_image_);
00389   image_overlay_->update();
00390 
00391   region_queue_.clear();
00392   //previous_queue_.clear();
00393 
00394   running_ = false;
00395   paused_ = true;
00396 
00397   // only if segmentation is running labeling can be accepted
00398   ui_->accept_button_->setEnabled(running_);
00399 
00400   // only if segmentation has been run at least once,
00401   // same seed point cloud be reused
00402   ui_->restart_button_->setEnabled(!previous_queue_.empty());
00403 
00404   // only if segmentation is not running, it can be started
00405   ui_->segment_button_->setEnabled(!running_);
00406 }
00407 
00408 void ObjectSegmentationRvizUI::update( float wall_dt, float ros_dt )
00409 {
00410   render_panel_->getRenderWindow()->update();
00411 
00412   // if button pressed
00413   if (click_info_.down_)
00414     updateSelectBox(click_info_.down_x_, click_info_.down_y_, click_info_.x_,
00415         click_info_.y_);
00416   else
00417     updateSelectBox(0.0, 0.0, 0.0, 0.0);
00418 
00419   if (num_fg_hypos_ > 0)
00420   {
00421     if (running_)
00422     {
00423       object_segmenter_->getCurrentResult(labels_);
00424       /*
00425        ROS_INFO("Sum of labels %d given %d foreground hypos",
00426        sumLabels(labels_), num_fg_hypos_);
00427        */
00428       //        image_pub_.publish(labels_);
00429     }
00430     overlaySegmentationMask();
00431   }
00432 
00433   // only if segmentation has been run at least once,
00434   // same seed point cloud be reused
00435   ui_->restart_button_->setEnabled(!previous_queue_.empty());
00436 }
00437 
00438 int ObjectSegmentationRvizUI::sumLabels( const sensor_msgs::Image &labels )
00439 {
00440   int sum = 0;
00441   for (unsigned int i = 0; i < labels.width; ++i)
00442     for (unsigned int j = 0; j < labels.height; ++j)
00443     {
00444       int adr = j * labels.width + i;
00445       sum += labels.data[adr];
00446     }
00447 
00448   return sum;
00449 }
00450 
00451 bool ObjectSegmentationRvizUI::eventFilter( QObject* watched_object, QEvent* event )
00452 {
00453   // Only handle events for render_panel_.
00454   if( watched_object != render_panel_ )
00455   {
00456     return QWidget::eventFilter( watched_object, event );
00457   }
00458 
00459   // Explicitly ignore wheel events in render_panel_.
00460   if( event->type() == QEvent::Wheel )
00461   {
00462     return true;
00463   }
00464 
00465   // Let parent class handle other non-mouse events.
00466   if( event->type() != QEvent::MouseMove &&
00467       event->type() != QEvent::MouseButtonPress &&
00468       event->type() != QEvent::MouseButtonRelease &&
00469       event->type() != QEvent::MouseButtonDblClick )
00470   {
00471     return QWidget::eventFilter( watched_object, event );
00472   }
00473 
00474   // It must be a mouse event at this point.
00475   QMouseEvent* mevent = static_cast<QMouseEvent*>( event );
00476 
00477   int x = mevent->x();
00478   int y = mevent->y();
00479   //convert to coordinates in the original image resolution
00480   x = floor(x * current_image_.width / render_panel_->width());
00481   y = floor(y * current_image_.height / render_panel_->height());
00482 
00483   if( mevent->type() == QEvent::MouseButtonPress &&
00484       mevent->button() == Qt::LeftButton )
00485   {
00486     click_info_.down_ = true;
00487 
00488     ROS_DEBUG("Good click at (%d,%d)", x, y);
00489     click_info_.down_x_ = x;
00490     click_info_.down_y_ = y;
00491 
00492     click_info_.x_ = x;
00493     click_info_.y_ = y;
00494   }
00495   else if( mevent->type() == QEvent::MouseButtonRelease &&
00496            mevent->button() == Qt::LeftButton )
00497   {
00498     if (click_info_.down_x_ > click_info_.x_)
00499       swap(click_info_.down_x_, click_info_.x_);
00500 
00501     if (click_info_.down_y_ > click_info_.y_)
00502       swap(click_info_.down_y_, click_info_.y_);
00503 
00504     float dist_clicks = dist(click_info_.down_x_, click_info_.down_y_,
00505                              click_info_.x_, click_info_.y_);
00506 
00507     ObjectSegmenter::Action action;
00508 
00509     Point tl;
00510     tl.x = click_info_.down_x_;
00511     tl.y = click_info_.down_y_;
00512 
00513     Point br;
00514 
00515     if (click_info_.dragged_ && dist_clicks > 2)
00516     {
00517 
00518       br.x = click_info_.x_;
00519       br.y = click_info_.y_;
00520 
00521       click_info_.dragged_ = false;
00522       action.type_ = ObjectSegmenter::REGION;
00523 
00524     } else
00525     {
00526 
00527       br.x = -1;
00528       br.y = -1;
00529 
00530       click_info_.dragged_ = false;
00531       action.type_ = ObjectSegmenter::CLICK;
00532     }
00533 
00534     ObjectSegmenter::Box2D region;
00535     region.p_tl_ = tl;
00536     region.p_br_ = br;
00537 
00538     if (!running_ && region_queue_.size() < MAX_FG)
00539     {
00540       region_queue_.push_back(region);
00541       previous_queue_.push_back(region);
00542       addToMasks(region);
00543       num_fg_hypos_++;
00544       addColorCode();
00545     } else if (num_fg_hypos_ < MAX_FG)
00546     {
00547       previous_queue_.push_back(region);
00548       action.box_ = region;
00549       object_segmenter_->queueAction(action);
00550       num_fg_hypos_++;
00551       addColorCode();
00552     }
00553     else      ROS_WARN("Maximum Number of Segments reached.");
00554 
00555     click_info_.down_ = false;
00556 
00557   }
00558   else if( mevent->type() == QEvent::MouseMove &&
00559            mevent->buttons() == Qt::LeftButton )
00560   {
00561     if (click_info_.down_)
00562     {
00563       click_info_.dragged_ = true;
00564 
00565       click_info_.x_ = x;
00566       click_info_.y_ = y;
00567     }
00568   }
00569   // Return true so mouse events not handled here are ignored, and
00570   // events handled here are not also interpreted by anyone else.
00571   return true;
00572 }
00573 
00574 void ObjectSegmentationRvizUI::addColorCode()
00575 {
00576   // Generate random colour for segment
00577 
00578   int zero = rand()&2;
00579   for(int i=0; i<3; i++)
00580   if(i==zero)
00581   color_code_.push_back(0);
00582   else
00583   color_code_.push_back(rand()&255);
00584 }
00585 
00586 void ObjectSegmentationRvizUI::addToMasks(const ObjectSegmenter::Box2D &select_)
00587 {
00588 
00589   int w = inits_.width;
00590 
00591   int size = 0;
00592 
00593   // region selected 
00594   if(!(select_.p_br_.x == -1 && select_.p_br_.y == -1))
00595   {
00596 
00597     for(int y=select_.p_tl_.y; y<select_.p_br_.y; ++y)
00598     {
00599       for(int x=select_.p_tl_.x; x<select_.p_br_.x; ++x)
00600       {
00601         int i = y*w + x;
00602         inits_.data[i]=num_fg_hypos_ + 2; // the same as the labels from the segmentation
00603         size ++;
00604       }
00605     }
00606 
00607     ROS_DEBUG("Added rectangle of size %d", size);
00608 
00609   } else
00610   {
00611     // point selected - region initialisation done automatically
00612 
00613     int radius = 10;
00614 
00615     for(int y=select_.p_tl_.y-radius; y<select_.p_tl_.y+radius; ++y)
00616     {
00617       for(int x=select_.p_tl_.x-radius; x<select_.p_tl_.x+radius; ++x)
00618       {
00619 
00620         if(dist((int)select_.p_tl_.x, (int)select_.p_tl_.y, x, y)<=radius)
00621         {
00622           int i = y*w + x;
00623           inits_.data[i]=num_fg_hypos_ + 2;
00624           size++;
00625         }
00626       }
00627     }
00628 
00629     ROS_DEBUG("Added circle of size %d", size);
00630   }
00631 }
00632 
00633 void ObjectSegmentationRvizUI::fillRgbImage(sensor_msgs::Image &rgb_img,
00634     const sensor_msgs::PointCloud2 &point_cloud)
00635 {
00636 
00637   ROS_DEBUG("Width and Height: (%d %d)",point_cloud.height, point_cloud.width );
00638 
00639   rgb_img.header = point_cloud.header;
00640   rgb_img.height = point_cloud.height;
00641   rgb_img.width = point_cloud.width;
00642   rgb_img.encoding = enc::RGB8;
00643   rgb_img.is_bigendian = false;
00644   rgb_img.step = 3 * rgb_img.width;
00645   size_t size = rgb_img.step * rgb_img.height;
00646   rgb_img.data.resize(size);
00647 
00648   for(unsigned int x=0; x<rgb_img.width; ++x)
00649   {
00650     for(unsigned int y=0; y<rgb_img.height; ++y)
00651     {
00652       int i = y * rgb_img.width + x;
00653 
00654       float rgb;
00655       memcpy ( &rgb, &point_cloud.data[i * point_cloud.point_step + point_cloud.fields[3].offset], sizeof (float));
00656       float r, g, b;
00657       transformRgb(rgb, r, g, b);
00658 
00659       int wide_i = y * rgb_img.step + x*3;
00660       rgb_img.data[wide_i+0] = round(r*255.0f);
00661       rgb_img.data[wide_i+1] = round(g*255.0f);
00662       rgb_img.data[wide_i+2] = round(b*255.0f);
00663 
00664     }
00665   }
00666 }
00667 
00668 void ObjectSegmentationRvizUI::overlaySegmentationMask()
00669 {
00670 
00671   sensor_msgs::Image::ConstPtr overlay_ptr;
00672 
00673   if( !running_)
00674   {
00675     overlay_ptr = boost::make_shared<const sensor_msgs::Image> (inits_);
00676   } else
00677   {
00678     overlay_ptr = boost::make_shared<const sensor_msgs::Image> (labels_);
00679   }
00680 
00681   // decrease in gray shade for surface 
00682   //    uint8_t darker = 50;
00683 
00684   //copy image to a new buffer so we can paint the segmentation mask
00685 
00686   int count = 0;
00687 
00688   int w = current_image_.width;
00689   int h = current_image_.height;
00690 
00691   for (int i=0; i<h; i++)
00692   {
00693     for (int j=0; j<w; j++)
00694     {
00695       unsigned int adr = i *w + j;
00696       // foreground segments start at label 2, background=0, flat surface=1
00697       int label = (int)(overlay_ptr->data[adr]);
00698 
00699       for(int c=0; c<3; c++)
00700       {
00701         uint8_t val;
00702         // we want to color all foreground segments
00703         if(label>1)
00704         {
00705           // only one channel will be changed,
00706           // the other will have 0 and colour info has to be kept
00707           ROS_ASSERT(label-2<num_fg_hypos_);
00708           ROS_ASSERT(3 * (label-2) + c<(int)color_code_.size());
00709           if( color_code_.at(3 * (label-2) + c)==0)
00710           val = current_image_.data[3 * adr + c];
00711           else
00712           val = color_code_.at(3 * (label-2) + c);
00713 
00714           count ++;
00715 
00716         } /*else if(label==1){
00717          val = current_image_.data[3 * adr + c];
00718          val = val>darker ? val-darker : 0;
00719          }
00720          */
00721         else
00722         {
00723           val = current_image_.data[3 * adr + c];
00724         }
00725 
00726         texture_buffer_.data.at( 3 * adr + c ) = val;
00727       }
00728     }
00729   }
00730 
00731   image_overlay_->setImage(texture_buffer_);
00732   image_overlay_->update();
00733 }
00734 
00735 void ObjectSegmentationRvizUI::updateSelectBox(int start_x,
00736     int start_y,
00737     int stop_x,
00738     int stop_y)
00739 {
00740 
00741   if(start_x>stop_x)
00742   swap(start_x, stop_x);
00743 
00744   if(start_y>stop_y)
00745   swap(start_y, stop_y);
00746 
00747   float x0 = start_x / ((float)current_image_.width / 2.0 ) - 1.0;
00748   float y0 = - (start_y / ((float)current_image_.height / 2.0 ) - 1.0);
00749 
00750   float x1 = stop_x / ((float)current_image_.width / 2.0 ) - 1.0;
00751   float y1 = - (stop_y / ((float)current_image_.height / 2.0 ) - 1.0);
00752 
00753   box_object_->beginUpdate(0);
00754   box_object_->position(x0, y0, 0.0);
00755   box_object_->position(x0, y1, 0.0);
00756   box_object_->position(x1, y1, 0.0);
00757   box_object_->position(x1, y0, 0.0);
00758   box_object_->index(0);
00759   box_object_->index(1);
00760   box_object_->index(2);
00761   box_object_->index(3);
00762   box_object_->index(0);
00763   box_object_->end();
00764 }
00765 
00766 void ObjectSegmentationRvizUI::acceptButtonClicked()
00767 {
00768   if( !running_) return;
00769 
00770   ObjectSegmentationGuiResult result;
00771 
00772   while(!object_segmenter_->getCurrentResult( labels_))
00773   {
00774     ROS_INFO("Waiting for final labeling");
00775   }
00776   float alpha, beta, gamma;
00777   object_segmenter_->getCurrentSurface( alpha, beta, gamma);
00778 
00779   // stop segmentation thread
00780   stopSegmentation();
00781 
00782   getClusterSize();
00783 
00784   if ( segm_size_[0] < (int)inlier_threshold_)
00785   {
00786     ROS_INFO("Plane detection has %d inliers, below min threshold of %d",
00787         segm_size_[0],
00788         inlier_threshold_);
00789     result.result = result.NO_TABLE;
00790     return;
00791   }
00792 
00793   for(int i=1; i<(int)segm_size_.size(); ++i)
00794   if(segm_size_[i] == 0)
00795   {
00796     ROS_INFO("Segment %d has 0 points.", segm_size_[i]);
00797     num_fg_hypos_--;
00798   }
00799 
00800   reconstructAndClusterPointCloud(result);
00801 
00802   // get table parameters in 3d
00803   tabletop_object_detector::Table table = table_transformer_.get3DTable(alpha, beta, gamma, table_points_,
00804       clusters_[0].header);
00805   result.table = table;
00806 
00807   result.result = result.SUCCESS;
00808 
00809   ROS_INFO("ObjectSegmentation was successful.");
00810 
00811   object_segmentation_server_->setSucceeded(result);
00812 
00813   cleanupAndHide();
00814 }
00815 
00816 void ObjectSegmentationRvizUI::cancelButtonClicked()
00817 {
00818   stopSegmentation();
00819   object_segmentation_server_->setAborted();
00820   cleanupAndHide();
00821 }
00822 
00823 void ObjectSegmentationRvizUI::resetButtonClicked()
00824 {
00825   reset( );
00826   previous_queue_.clear();
00827 }
00828 
00829 void ObjectSegmentationRvizUI::reset( )
00830 {
00831   ObjectSegmenter::Action action;
00832   action.type_ = ObjectSegmenter::RESET;
00833   includeFlags(action);
00834   object_segmenter_->queueAction(action);
00835   image_overlay_->clear();
00836 
00837   ui_->segment_button_->setText("Segment");
00838   paused_ = true;
00839 
00840   resetVars();
00841 }
00842 
00843 void ObjectSegmentationRvizUI::restartButtonClicked()
00844 {
00845   // copy old seeds into new queue
00846   reset();
00847   // ObjectSegmenter::Action action;
00848   // action.type_ = ObjectSegmenter::RESET;
00849   // includeFlags(action);
00850   // object_segmenter_->queueAction(action);
00851   // image_overlay_->clear();
00852 
00853 
00854   // region_queue_.clear();
00855 
00856   for(int i=0; i<(int)previous_queue_.size();++i)
00857   {
00858     if( num_fg_hypos_ < MAX_FG )
00859     {
00860       region_queue_.push_back(previous_queue_[i]);
00861       addToMasks(previous_queue_[i]);
00862       num_fg_hypos_++;
00863       addColorCode();
00864     } else
00865     {
00866       ROS_INFO("Maximum number of segments reached");
00867     }
00868   }
00869 
00870   segment();
00871   //    std::string pause("Pause");
00872   ui_->segment_button_->setText("Pause");
00873   paused_ = false;
00874 }
00875 
00876 void ObjectSegmentationRvizUI::includeFlags( ObjectSegmenter::Action &ac)
00877 {
00878   // keep the current segmentation flags
00879   ac.with_colors_ = ui_->with_color_->isChecked();
00880   ac.with_color_holes_ = ui_->with_holes_->isChecked();
00881   ac.uniform_ = ui_->uniform_->isChecked();
00882   ac.with_disparities_ = ui_->with_disparity_->isChecked();
00883   ac.with_surface_ = ui_->with_surface_->isChecked();
00884 
00885 }
00886 
00887 void ObjectSegmentationRvizUI::segmentButtonClicked()
00888 {
00889   if(paused_)
00890   {
00891     segment();
00892     ui_->segment_button_->setText("Pause");
00893     paused_ = false;
00894   } else
00895   {
00896     // copy old seeds into new queue
00897     ObjectSegmenter::Action action;
00898     action.type_ = ObjectSegmenter::PAUSE;
00899     object_segmenter_->queueAction(action);
00900     ui_->segment_button_->setText("Segment");
00901     paused_ = true;
00902   }
00903 }
00904 
00905 void ObjectSegmentationRvizUI::segment()
00906 {
00907 
00908   if(region_queue_.empty())
00909   {
00910     // no region has been selected or click executed
00911     ObjectSegmenter::Action action;
00912     ObjectSegmenter::Box2D dummy;
00913     dummy.p_tl_.x = -1;
00914     dummy.p_tl_.y = -1;
00915     dummy.p_br_.x = -1;
00916     dummy.p_br_.y = -1;
00917     action.type_ = ObjectSegmenter::CLICK;
00918     action.box_ = dummy;
00919     object_segmenter_->queueAction(action);
00920 
00921   } else
00922   {
00923     while(!region_queue_.empty())
00924     {
00925       ObjectSegmenter::Action action;
00926       if(region_queue_[0].p_br_.x==-1 && region_queue_[0].p_br_.y==-1)
00927       {
00928         action.type_ = ObjectSegmenter::CLICK;
00929       } else
00930       {
00931         action.type_ = ObjectSegmenter::REGION;
00932       }
00933 
00934       action.box_ = region_queue_[0];
00935 
00936       object_segmenter_->queueAction(action);
00937       region_queue_.pop_front();
00938     }
00939   }
00940 
00941   running_=true;
00942   // only if segmentation is running labeling can be accepted
00943   ui_->accept_button_->setEnabled(running_);
00944 
00945   // only if segmentation has been run at least once, 
00946   // same seed point cloud be reused
00947   ui_->restart_button_->setEnabled(!previous_queue_.empty());
00948 
00949 }
00950 
00951 void ObjectSegmentationRvizUI::withSurfaceChecked()
00952 { reset();}
00953 
00954 void ObjectSegmentationRvizUI::withDisparityChecked()
00955 {
00956   if(!ui_->with_disparity_->isChecked())
00957   {
00958     ui_->with_color_->setChecked(true);
00959     ui_->with_holes_->setEnabled(true);
00960     ui_->uniform_->setEnabled(true);
00961   }
00962   reset();
00963 }
00964 
00965 void ObjectSegmentationRvizUI::withColorChecked()
00966 {
00967   if(!ui_->with_color_->isChecked())
00968   {
00969     ui_->with_disparity_->setChecked(true);
00970     ui_->with_holes_->setEnabled(false);
00971     ui_->uniform_->setEnabled(false);
00972   } else
00973   {
00974     ui_->with_holes_->setEnabled(true);
00975     ui_->uniform_->setEnabled(true);
00976   }
00977 
00978   reset();
00979 }
00980 
00981 void ObjectSegmentationRvizUI::withHolesChecked()
00982 { reset();}
00983 
00984 void ObjectSegmentationRvizUI::uniformChecked()
00985 { reset();}
00986 
00987 void ObjectSegmentationRvizUI::gradWeightChanged( int new_value )
00988 {
00989   grad_weight_ = (double) new_value;
00990   ObjectSegmenter::Action action;
00991   action.type_ = ObjectSegmenter::GRADCHANGE;
00992   action.grad_weight_ = grad_weight_;
00993   object_segmenter_->queueAction(action);
00994 }
00995 
00996 void ObjectSegmentationRvizUI::getClusterSize()
00997 {
00998   int w = labels_.width;
00999   int h = labels_.height;
01000 
01001   // take into account surface and foreground hypotheses
01002   segm_size_.resize(num_fg_hypos_+1,0);
01003 
01004   for (int i=0; i<h; i++)
01005   {
01006     for (int j=0; j<w; j++)
01007     {
01008 
01009       unsigned int adr = i *w + j;
01010       unsigned int label = labels_.data[adr];
01011       // take foreground objects
01012       if(rviz_interaction_tools::hasDisparityValue(current_disparity_image_,
01013               i, j))
01014       {
01015         if(label>1)
01016         segm_size_.at(label-1)++;
01017         else if(label==1)
01018         segm_size_.at(0)++;
01019       }
01020     }
01021   }
01022 }
01023 
01024 void ObjectSegmentationRvizUI::reconstructAndClusterPointCloud( ObjectSegmentationGuiResult &result)
01025 {
01026   clusters_.clear();
01027   clusters_.resize(num_fg_hypos_);
01028   for(int i=0; i<num_fg_hypos_; ++i)
01029   {
01030     clusters_[i].header.frame_id = current_point_cloud_.header.frame_id;
01031     clusters_[i].header.stamp = ros::Time::now();
01032     clusters_[i].points.reserve(segm_size_[i+1]);
01033   }
01034 
01035   table_points_.header.frame_id = current_point_cloud_.header.frame_id;
01036   table_points_.header.stamp = ros::Time::now();
01037   table_points_.points.reserve(segm_size_[0]);
01038 
01039   int nan_cluster =0;
01040 
01041   for(unsigned int x=0; x<current_point_cloud_.width; ++x)
01042   {
01043     for(unsigned int y=0; y<current_point_cloud_.height; ++y)
01044     {
01045       int i = y * current_point_cloud_.width + x;
01046       float nan;
01047       memcpy (&nan,
01048           &current_point_cloud_.data[i * current_point_cloud_.point_step + current_point_cloud_.fields[0].offset],
01049           sizeof (float));
01050       if(!isnan(nan))
01051       {
01052         geometry_msgs::Point32 p;
01053         float x, y, z;
01054         memcpy (&x,
01055             &current_point_cloud_.data[i
01056             * current_point_cloud_.point_step
01057             + current_point_cloud_.fields[0].offset],
01058             sizeof (float));
01059         memcpy (&y,
01060             &current_point_cloud_.data[i
01061             * current_point_cloud_.point_step
01062             + current_point_cloud_.fields[1].offset],
01063             sizeof (float));
01064         memcpy (&z,
01065             &current_point_cloud_.data[i
01066             * current_point_cloud_.point_step
01067             + current_point_cloud_.fields[2].offset],
01068             sizeof (float));
01069         p.x = x;
01070         p.y = y;
01071         p.z = z;
01072 
01073         unsigned int label = labels_.data[i];
01074         if(label>1)
01075         {
01076           clusters_[label-2].points.push_back( p );
01077         } else if(label==1)
01078         {
01079           table_points_.points.push_back( p );
01080         }
01081       } else
01082       {
01083         nan_cluster++;
01084       }
01085     }
01086   }
01087 
01088   filterOutliersAndDownsample(clusters_);
01089 
01090   result.clusters = clusters_;
01091 }
01092 
01093 void ObjectSegmentationRvizUI::filterOutliersAndDownsample(std::vector<sensor_msgs::PointCloud> &clusters)
01094 {
01095   std::vector<sensor_msgs::PointCloud> filtered_clusters;
01096   filtered_clusters.reserve(clusters.size());
01097 
01098   for (size_t i=0; i<clusters.size(); i++)
01099   {
01100 
01101     // annoying conversion to different point cloud formats
01102     sensor_msgs::PointCloud2 converted_cloud;
01103     sensor_msgs::convertPointCloudToPointCloud2(clusters[i], converted_cloud);
01104 
01105     pcl::PointCloud<PCL_Point> cloud_t;
01106     pcl::fromROSMsg (converted_cloud, cloud_t);
01107     pcl::PointCloud<PCL_Point>::ConstPtr cloud_ptr
01108     = boost::make_shared<const pcl::PointCloud<PCL_Point> > (cloud_t);
01109 
01110     // statistical outlier removal
01111     pcl::StatisticalOutlierRemoval<PCL_Point> sor;
01112     sor.setInputCloud (cloud_ptr);
01113     sor.setMeanK (mean_k_);
01114     sor.setStddevMulThresh (std_);
01115     pcl::PointCloud<PCL_Point>::Ptr
01116     cloud_filtered(new pcl::PointCloud<PCL_Point> ());
01117     sor.filter (*cloud_filtered);
01118 
01119     // and annoying back conversion into old point cloud format
01120     sensor_msgs::PointCloud2 filt_converted_cloud;
01121     pcl::toROSMsg ( *cloud_filtered, filt_converted_cloud);
01122     sensor_msgs::PointCloud2::ConstPtr filt_converted_cloud_ptr
01123     = boost::make_shared<const sensor_msgs::PointCloud2> (filt_converted_cloud);
01124 
01125     // downsampling of point clouds
01126     pcl::VoxelGrid<sensor_msgs::PointCloud2> dvx;
01127     dvx.setInputCloud(filt_converted_cloud_ptr);
01128     dvx.setLeafSize (clustering_voxel_size_,
01129         clustering_voxel_size_,
01130         clustering_voxel_size_);
01131     sensor_msgs::PointCloud2::Ptr
01132     cloud_downsampled(new sensor_msgs::PointCloud2());
01133     dvx.filter (*cloud_downsampled);
01134 
01135     sensor_msgs::PointCloud cloud_tmp;
01136     sensor_msgs::convertPointCloud2ToPointCloud(*cloud_downsampled, cloud_tmp);
01137 
01138     filtered_clusters.push_back(cloud_tmp);
01139   }
01140 
01141   clusters.clear();
01142   clusters = filtered_clusters;
01143 
01144 }
01145 
01146 } // namespace object_segmentation_gui


object_segmentation_gui
Author(s): Jeannette Bohg
autogenerated on Fri Jan 3 2014 12:03:36