$search
00001 /********************************************************************* 00002 * 00003 * Software License Agreement (BSD License) 00004 * 00005 * Copyright (c) 2011, Robert Bosch LLC. 00006 * All rights reserved. 00007 * 00008 * Redistribution and use in source and binary forms, with or without 00009 * modification, are permitted provided that the following conditions 00010 * are met: 00011 * 00012 * * Redistributions of source code must retain the above copyright 00013 * notice, this list of conditions and the following disclaimer. 00014 * * Redistributions in binary form must reproduce the above 00015 * copyright notice, this list of conditions and the following 00016 * disclaimer in the documentation and/or other materials provided 00017 * with the distribution. 00018 * * Neither the name of the Robert Bosch nor the names of its 00019 * contributors may be used to endorse or promote products derived 00020 * from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 00025 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 00026 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 00027 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 00028 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00029 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 00030 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00032 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00033 * POSSIBILITY OF SUCH DAMAGE. 00034 * 00035 *********************************************************************/ 00036 #include <ros/ros.h> 00037 #include<sys/stat.h> 00038 #include<fstream> 00039 #include<iostream> 00040 00041 //#include<sys/type.h> 00042 #include <ros/package.h> 00043 #include <cv_bridge/cv_bridge.h> 00044 #include <sensor_msgs/image_encodings.h> 00045 #include <sensor_msgs/point_cloud_conversion.h> 00046 #include <opencv2/imgproc/imgproc.hpp> 00047 #include <opencv2/highgui/highgui.hpp>s 00048 00049 00050 #include "image_segmentation_demo/utils.h" 00051 #include "image_segmentation_demo/object_segmentation_ui.h" 00052 00053 #include <wx/wx.h> 00054 #include <wx/app.h> 00055 00056 #include "object_segmentation_frame.h" 00057 00058 00059 using namespace std; 00060 using namespace rgbd_assembler; 00061 namespace enc = sensor_msgs::image_encodings; 00062 00063 namespace image_segmentation_demo 00064 { 00065 static const char WINDOW[] = "Image window"; 00066 00070 ObjectSegmentationUI::ObjectSegmentationUI(wxWindow* parentwindow ): ObjectSegmentationFrame(parentwindow), object_segmenter_(0), listener_(ros::Duration(120.0)) 00071 { 00072 //can't accept until you segment something 00073 accept_button_->Enable(false); 00074 ogre_tools::initializeOgre(); 00075 root_ = Ogre::Root::getSingletonPtr(); 00076 00077 00078 try{ 00079 scene_manager_ = root_->createSceneManager( Ogre::ST_GENERIC, "TestSceneManager" ); 00080 render_window_ = new ogre_tools::wxOgreRenderWindow( root_, ImagePanel ); 00081 00082 00083 render_window_->setAutoRender(false); 00084 00085 render_window_->SetSize(this->GetSize() ); 00086 //render_window_->SetSize( panel->GetSize() ); 00087 ogre_tools::V_string paths; 00088 paths.push_back(ros::package::getPath(ROS_PACKAGE_NAME) + "/ogre_media/textures"); 00089 paths.push_back(ros::package::getPath(ROS_PACKAGE_NAME) + "/ui"); 00090 data_location_=ros::package::getPath(ROS_PACKAGE_NAME) + "/data"; 00091 ogre_tools::initializeResources(paths); 00092 00093 camera_ = scene_manager_->createCamera("Camera"); 00094 00095 render_window_->getViewport()->setCamera( camera_ ); 00096 00097 texture_ = new ROSImageTexture(); 00098 00099 object_segmenter_ = new GrabCut3DObjectSegmenter(); 00100 00101 //setup ROS Pick and Place Interfaces 00102 SetUpPickandPlaceApp(); 00103 //call sensor data 00104 GetSensorData(); 00105 00106 display_image_=current_image_; 00107 00108 boost::shared_ptr<sensor_msgs::Image>temp_image_(new sensor_msgs::Image ()); 00109 *temp_image_=display_image_; 00110 texture_->setNewImage(temp_image_); 00111 00112 Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( "Material", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME ); 00113 material->setCullingMode(Ogre::CULL_NONE); 00114 material->getTechnique(0)->getPass(0)->setDepthWriteEnabled(true); 00115 material->getTechnique(0)->setLightingEnabled(false); 00116 Ogre::TextureUnitState* tu = material->getTechnique(0)->getPass(0)->createTextureUnitState(); 00117 tu->setTextureName(texture_->getTexture()->getName()); 00118 tu->setTextureFiltering( Ogre::TFO_NONE ); 00119 00120 Ogre::Rectangle2D* rect = new Ogre::Rectangle2D(true); 00121 rect->setCorners(-1.0f, 1.0f, 1.0f, -1.0f); 00122 rect->setMaterial(material->getName()); 00123 rect->setRenderQueueGroup(Ogre::RENDER_QUEUE_OVERLAY - 1); 00124 Ogre::AxisAlignedBox aabb; 00125 aabb.setInfinite(); 00126 rect->setBoundingBox(aabb); 00127 00128 Ogre::SceneNode* node = scene_manager_->getRootSceneNode()->createChildSceneNode(); 00129 node->attachObject(rect); 00130 node->setVisible(true); 00131 00132 render_window_->SetSize(texture_->getWidth(), texture_->getHeight()); 00133 00134 start_time_=false; 00135 num_resets_=0; 00136 setUpEventHandlers(); 00137 00138 } 00139 catch(Ogre::Exception& e) 00140 { 00141 ROS_ERROR("%s", e.what()); 00142 } 00143 00144 if (!nh->ok()) 00145 { 00146 Close(); 00147 } 00148 00149 render_window_->Refresh(); 00150 } 00151 00152 ObjectSegmentationUI::~ObjectSegmentationUI(){ 00153 delete render_window_; 00154 delete object_segmenter_; 00155 } 00156 00157 /* 00158 * Sets up event handlers for the mouse 00159 */ 00160 00161 void ObjectSegmentationUI::setUpEventHandlers(){ 00162 00163 // change the render window handler to use our event handlers when the user does something with the mouse 00164 00165 render_window_->Connect(wxEVT_MOTION,wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00166 render_window_->Connect(wxEVT_LEFT_DOWN,wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00167 render_window_->Connect(wxEVT_MIDDLE_DOWN,wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00168 render_window_->Connect(wxEVT_RIGHT_DOWN,wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00169 render_window_->Connect(wxEVT_LEFT_UP,wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00170 render_window_->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00171 render_window_->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00172 render_window_->Connect(wxEVT_MOUSEWHEEL, wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00173 render_window_->Connect(wxEVT_LEFT_DCLICK, wxMouseEventHandler( ObjectSegmentationUI::onRenderWindowMouseEvents ), NULL, this); 00174 00175 } 00176 00177 /* 00178 * Callback to handle the accept button in the interface - segments the selected region and then proceeds call function that will handle manipulation 00179 */ 00180 00181 void ObjectSegmentationUI::acceptButtonClicked( wxCommandEvent& ) 00182 { 00183 00184 // Fetch binary mask from GCApp object 00185 binary_mask_ = object_segmenter_->binaryMask(); 00186 00187 // reconstruct clusters 00188 reconstructAndClusterPointCloud(); 00189 00190 // get table parameters in 3d 00191 if(table_detector_.detectTable(current_point_cloud_, detection_call_.table)) 00192 detection_call_.result = detection_call_.SUCCESS; 00193 else 00194 detection_call_.result = detection_call_.NO_TABLE; 00195 00196 00197 ROS_INFO("ObjectSegmentation was successful."); 00198 00199 //Now that object segmentation has occurred direct arm to pick up the object and put it down 00200 RunRestOfPickAndPlace(); 00201 } 00202 00203 /* 00204 * 00205 * Callback for Cancel button 00206 * 00207 */ 00208 void ObjectSegmentationUI::cancelButtonClicked( wxCommandEvent& ) 00209 { 00210 cleanupAndQuit(); 00211 } 00212 /* 00213 *Callback for refresh button -> displays new image 00214 */ 00215 00216 void ObjectSegmentationUI::refreshButtonClicked(wxCommandEvent&) 00217 { 00218 GetSensorData(); 00219 display_image_=current_image_; 00220 updateView(); 00221 accept_button_->Enable(false); 00222 } 00223 00224 /* 00225 *Callback for the reset button -> resets the visualization 00226 */ 00227 void ObjectSegmentationUI::resetButtonClicked( wxCommandEvent& ) 00228 { 00229 num_resets_++; 00230 object_segmenter_->initializedIs(false); 00231 resetVars(); 00232 00233 00234 } 00235 00236 /* 00237 *Callback for the segment button -> uses 3d grab cut to segment the area within the box. 00238 */ 00239 void ObjectSegmentationUI::segmentButtonClicked( wxCommandEvent& ){ 00240 00241 if( object_segmenter_->rectState() == GrabCut3DObjectSegmenter::SET) 00242 { 00243 object_segmenter_->iterCountInc(); 00244 // update image overlay 00245 updateImageOverlay(); 00246 } 00247 else 00248 { ROS_INFO("Rectangle must be drawn first."); 00249 wxMessageBox(wxT("You need to draw a box with the mouse first. \n\n Left Mouse Button: Drag a rectangle around an object to segment it. \n\n\ 00250 SHIFT+Left Mouse Button: Mark pixel belonging to the object. \n\n CTRL+Left Mouse Button: Mark pixel belonging to the background."), wxT("Instructions"), wxOK|wxICON_INFORMATION , this); 00251 return; 00252 } 00253 // only if segmentation is ran once labeling can be accepted 00254 accept_button_->Enable(true); 00255 00256 } 00257 00258 00259 /* 00260 * set mouse events for the UI window 00261 */ 00262 void ObjectSegmentationUI::onRenderWindowMouseEvents( wxMouseEvent& event ) 00263 { 00264 if(!recording_time_) 00265 { 00266 //start timing the user interaction and set up the data collection site 00267 start_time_=time(0); 00268 struct tm *now =localtime(&start_time_); 00269 00270 stringstream data_string_stream; 00271 00272 data_string_stream<< data_location_<<"/"<< (now->tm_year+1900) << (now->tm_mon+1) << (now->tm_mday) << "_"<<now->tm_hour << "_" << now->tm_min << "_"<<now->tm_sec; 00273 data_string_=data_string_stream.str(); 00274 ROS_INFO_STREAM("path: "<< data_string_); 00275 00276 //create folder using date/time info 00277 mkdir(data_string_.c_str(), 0755); 00278 00279 recording_time_=true; 00280 } 00281 updateView(); 00282 int x = event.GetX(); 00283 int y = event.GetY(); 00284 //convert to coordinates in the original image resolution 00285 00286 x = floor(x * current_image_.width / texture_->getWidth()); 00287 y = floor(y * current_image_.height / texture_->getHeight()); 00288 00289 //make sure mouse events are handled by this code 00290 GrabCut3DObjectSegmenter::MouseEvent mouse_event; 00291 if (event.ButtonDown(wxMOUSE_BTN_LEFT)) 00292 { 00293 mouse_event = GrabCut3DObjectSegmenter::LEFT_BUTTON_DOWN; 00294 } 00295 else if (event.ButtonUp(wxMOUSE_BTN_LEFT)) 00296 { 00297 mouse_event = GrabCut3DObjectSegmenter::LEFT_BUTTON_UP; 00298 } 00299 else if (event.ButtonDown(wxMOUSE_BTN_RIGHT)) 00300 { 00301 mouse_event = GrabCut3DObjectSegmenter::RIGHT_BUTTON_DOWN; 00302 } 00303 else if (event.ButtonUp(wxMOUSE_BTN_RIGHT)) 00304 { 00305 mouse_event = GrabCut3DObjectSegmenter::RIGHT_BUTTON_UP; 00306 } 00307 else 00308 { 00309 mouse_event = GrabCut3DObjectSegmenter::MOUSE_MOVE; 00310 } 00311 00312 if(event.Dragging()) 00313 { 00314 mouse_event = GrabCut3DObjectSegmenter::MOUSE_MOVE; 00315 } 00316 00317 object_segmenter_->mouseClick(mouse_event, x, y, event.ControlDown(), event.ShiftDown()); 00318 00319 // update image overlay 00320 updateImageOverlay(); 00321 } 00322 00323 void ObjectSegmentationUI::cleanupAndQuit(){ 00324 delete pickup_client; 00325 delete place_client; 00326 Close(); 00327 } 00328 00329 /* 00330 * updates view in the display window 00331 */ 00332 void ObjectSegmentationUI::updateView(){ 00333 boost::shared_ptr<sensor_msgs::Image>temp_image_(new sensor_msgs::Image ()); 00334 *temp_image_ = display_image_; 00335 00336 int width = 0; 00337 int height = 0; 00338 ImagePanel->GetSize(&width, &height); 00339 00340 texture_->setNewImage(temp_image_); 00341 texture_->setSize( (uint32_t) width, (uint32_t) height ); 00342 //ROS_INFO( "Texture Size: %d x %d", texture_->getWidth(), texture_->getHeight() ); 00343 render_window_->SetSize(texture_->getWidth(), texture_->getHeight()); 00344 00345 root_->renderOneFrame(); 00346 } 00347 void ObjectSegmentationUI::update(float wall_dt, float ros_dt){ 00348 updateView(); 00349 } 00350 void ObjectSegmentationUI::updateImageOverlay() 00351 { 00352 sensor_msgs::Image new_display_image; 00353 convertMatToImageMessage(object_segmenter_->displayImage(), new_display_image); 00354 display_image_=new_display_image; 00355 updateView(); 00356 } 00357 00358 /* 00359 * Gets the image and point cloud data 00360 */ 00361 bool ObjectSegmentationUI::GetSensorData(){ 00362 00363 ros::Time start_time = ros::Time::now(); 00364 if (!rgbd_assembler_client_.call(rgbd_assembler_srv_)) 00365 { 00366 ROS_ERROR_STREAM("Call to rgbd assembler service failed"); 00367 return false; 00368 } 00369 ROS_INFO_STREAM("Detection backend: assembled data received after " << ros::Time::now() - start_time << " seconds"); 00370 if (rgbd_assembler_srv_.response.result != rgbd_assembler_srv_.response.SUCCESS) 00371 { 00372 std::ostringstream s; 00373 s << "RGB-D Assembler service returned error " << (int)rgbd_assembler_srv_.response.result; 00374 ROS_ERROR_STREAM( s.str() ); 00375 return false; 00376 } 00377 00378 current_image_ = rgbd_assembler_srv_.response.image; 00379 current_disparity_image_ = rgbd_assembler_srv_.response.disparity_image; 00380 current_camera_info_ = rgbd_assembler_srv_.response.camera_info; 00381 00382 fillRgbImage(current_image_, rgbd_assembler_srv_.response.point_cloud); 00383 transformPointCloud("/base_link", rgbd_assembler_srv_.response.point_cloud, current_point_cloud_ ); 00384 00385 getDepthImage(current_depth_image_); 00386 // initialize segmentation 00387 Mat image, depth_image; 00388 convertImageMessageToMat(current_image_, image); 00389 convertImageMessageToMat(current_depth_image_, depth_image); 00390 object_segmenter_->setImages(image, depth_image); 00391 return true; 00392 } 00393 00394 /* 00395 * transforms point cloud to new frame 00396 * @param target_frame - frame desired for point cloud to be in 00397 * @param cloud_in - the cloud you want transformed 00398 * @param cloud_out - the cloud in the target frame 00399 */ 00400 bool ObjectSegmentationUI::transformPointCloud(const std::string &target_frame, const sensor_msgs::PointCloud2& cloud_in, sensor_msgs::PointCloud2& cloud_out) 00401 { 00402 //convert cloud to processing frame 00403 sensor_msgs::PointCloud old_cloud,old_cloud_transformed; 00404 sensor_msgs::convertPointCloud2ToPointCloud (cloud_in, old_cloud); 00405 string err_msg; 00406 if (listener_.canTransform(target_frame.c_str(),cloud_in.header.frame_id.c_str(), ros::Time(0), &err_msg)) 00407 { 00408 try 00409 { 00410 listener_.transformPointCloud(target_frame, old_cloud, old_cloud_transformed); 00411 } 00412 catch (tf::TransformException ex) 00413 { 00414 ROS_ERROR("Failed to transform cloud from frame %s into frame %s: %s", old_cloud.header.frame_id.c_str(),target_frame.c_str(),ex.what()); 00415 return false; 00416 } 00417 } 00418 else 00419 { 00420 ROS_ERROR("Could not transform %s to %s: %s", cloud_in.header.frame_id.c_str(), target_frame.c_str(), err_msg.c_str()); 00421 return false; 00422 } 00423 sensor_msgs::convertPointCloudToPointCloud2 (old_cloud_transformed, cloud_out); 00424 ROS_INFO("Input cloud converted to %s frame", target_frame.c_str()); 00425 return true; 00426 } 00427 00428 00429 00430 void ObjectSegmentationUI::fillRgbImage(sensor_msgs::Image &rgb_img, 00431 const sensor_msgs::PointCloud2 &point_cloud) 00432 { 00433 00434 ROS_DEBUG("Width and Height: (%d %d)",point_cloud.height, point_cloud.width ); 00435 00436 rgb_img.header = point_cloud.header; 00437 rgb_img.height = point_cloud.height; 00438 rgb_img.width = point_cloud.width; 00439 rgb_img.encoding = enc::RGB8; 00440 rgb_img.is_bigendian = false; 00441 rgb_img.step = 3 * rgb_img.width; 00442 size_t size = rgb_img.step * rgb_img.height; 00443 rgb_img.data.resize(size); 00444 00445 for(unsigned int x=0; x<rgb_img.width; ++x) 00446 { 00447 for(unsigned int y=0; y<rgb_img.height; ++y) 00448 { 00449 int i = y * rgb_img.width + x; 00450 00451 float rgb; 00452 memcpy ( &rgb, &point_cloud.data[i * point_cloud.point_step + point_cloud.fields[3].offset], sizeof (float)); 00453 float r, g, b; 00454 transformRgb(rgb, r, g, b); 00455 00456 int wide_i = y * rgb_img.step + x*3; 00457 rgb_img.data[wide_i+0] = round(r*255.0f); 00458 rgb_img.data[wide_i+1] = round(g*255.0f); 00459 rgb_img.data[wide_i+2] = round(b*255.0f); 00460 00461 } 00462 } 00463 } 00464 00465 00466 /* 00467 * Gets depth image. Current topic is "/camera/depth/image" if a different topic is desired you should remap (http://www.ros.org/wiki/roslaunch/XML/remap) if a different camera topic is desired. 00468 */ 00469 bool ObjectSegmentationUI::getDepthImage(sensor_msgs::Image& image_msg) 00470 { 00471 // get image 00472 std::string image_topic = nh->resolveName("/camera/depth/image"); 00473 ROS_INFO("Waiting for image on topic %s", image_topic.c_str()); 00474 sensor_msgs::ImageConstPtr image_ptr = ros::topic::waitForMessage<sensor_msgs::Image>(image_topic, ros::Duration(30.0)); 00475 if(!image_ptr) { 00476 ROS_ERROR("Could not receive an image!"); 00477 return false; 00478 } 00479 ROS_INFO("Received image on topic %s", image_topic.c_str()); 00480 image_msg = *image_ptr; 00481 00482 float max_val = -FLT_MAX; 00483 float min_val = FLT_MAX; 00484 for(unsigned int x=0; x<image_msg.width; ++x) 00485 { 00486 for(unsigned int y=0; y<image_msg.height; ++y) 00487 { 00488 int index_src = y * image_ptr->step + x*4; 00489 float* val = (float*)(&image_ptr->data[index_src]); 00490 max_val = std::max(*val,max_val); 00491 min_val = std::min(*val,min_val); 00492 } 00493 } 00494 00495 image_msg.encoding = "bgr8"; 00496 image_msg.width = image_ptr->width; 00497 image_msg.height = image_ptr->height; 00498 image_msg.step = 3 * image_ptr->width; 00499 image_msg.data.resize(image_ptr->step * image_ptr->height); 00500 for(unsigned int x=0; x<image_msg.width; ++x) 00501 { 00502 for(unsigned int y=0; y<image_msg.height; ++y) 00503 { 00504 int index_src = y * image_ptr->step + x*4; 00505 float* val = (float*)(&image_ptr->data[index_src]); 00506 00507 int index_dest = y * image_msg.step + x*3; 00508 image_msg.data[index_dest+0] = round(*val); 00509 image_msg.data[index_dest+1] = round(*val); 00510 image_msg.data[index_dest+2] = round(*val); 00511 } 00512 } 00513 ROS_INFO("returning depth image %s", image_topic.c_str()); 00514 00515 return true; 00516 } 00517 00518 00519 00520 /* 00521 * Helper function to convert ROS sensor images to openCV mat images 00522 * @param image_msg - ROS sensor image 00523 * @param image - opencv Mat image 00524 * 00525 */ 00526 bool ObjectSegmentationUI::convertImageMessageToMat(const sensor_msgs::Image& image_msg, Mat& image) 00527 { 00528 // converts ROS images to OpenCV 00529 cv_bridge::CvImagePtr cv_ptr; 00530 try 00531 { 00532 cv_ptr = cv_bridge::toCvCopy(image_msg, sensor_msgs::image_encodings::BGR8); 00533 } 00534 catch (cv_bridge::Exception& e) 00535 { 00536 ROS_ERROR("cv_bridge exception: %s", e.what()); 00537 return false; 00538 } 00539 00540 image = cv_ptr->image; 00541 00542 return true; 00543 } 00544 00545 /* 00546 * Helper function to convert openCV mat images to ROS sensor images 00547 * @param image - opencv Mat image 00548 * @param image_msg - ROS sensor image 00549 */ 00550 bool ObjectSegmentationUI::convertMatToImageMessage(const Mat& image, sensor_msgs::Image& image_msg) 00551 { 00552 // converts OpenCV to ROS images 00553 cv_bridge::CvImage cv_image; 00554 cv_image.image = image; 00555 cv_image.encoding = "bgr8"; 00556 00557 try 00558 { 00559 cv_image.toImageMsg(image_msg); 00560 } 00561 catch (cv_bridge::Exception& e) 00562 { 00563 ROS_ERROR("cv_bridge exception: %s", e.what()); 00564 return false; 00565 } 00566 return true; 00567 } 00568 00569 00570 /* 00571 * Reconstructs clusters 00572 */ 00573 void ObjectSegmentationUI::reconstructAndClusterPointCloud() 00574 { 00575 clusters_.clear(); 00576 clusters_.resize(1); 00577 clusters_[0].header.frame_id = current_point_cloud_.header.frame_id; 00578 clusters_[0].header.stamp = ros::Time(0); 00579 clusters_[0].points.reserve(1000); 00580 00581 for(unsigned int x=0; x<current_point_cloud_.width; ++x) 00582 { 00583 for(unsigned int y=0; y<current_point_cloud_.height; ++y) 00584 { 00585 int i = y * current_point_cloud_.width + x; 00586 int mask_val = int(binary_mask_.at<unsigned char>(y, x)); 00587 float nan; 00588 memcpy (&nan, 00589 ¤t_point_cloud_.data[i * current_point_cloud_.point_step + current_point_cloud_.fields[0].offset], 00590 sizeof (float)); 00591 if(!isnan(nan)) 00592 { 00593 geometry_msgs::Point32 p; 00594 float x, y, z; 00595 memcpy (&x, 00596 ¤t_point_cloud_.data[i 00597 * current_point_cloud_.point_step 00598 + current_point_cloud_.fields[0].offset], 00599 sizeof (float)); 00600 memcpy (&y, 00601 ¤t_point_cloud_.data[i 00602 * current_point_cloud_.point_step 00603 + current_point_cloud_.fields[1].offset], 00604 sizeof (float)); 00605 memcpy (&z, 00606 ¤t_point_cloud_.data[i 00607 * current_point_cloud_.point_step 00608 + current_point_cloud_.fields[2].offset], 00609 sizeof (float)); 00610 p.x = x; 00611 p.y = y; 00612 p.z = z; 00613 00614 if (mask_val > 0) 00615 clusters_[0].points.push_back(p); 00616 } 00617 } 00618 } 00619 detection_call_.clusters = clusters_; 00620 } 00621 00622 void ObjectSegmentationUI::resetVars() 00623 { 00624 for (size_t i = 0; i < clusters_.size(); ++i) 00625 clusters_[i].points.clear(); 00626 00627 clusters_.clear(); 00628 GetSensorData(); 00629 00630 display_image_=current_image_; 00631 00632 accept_button_->Enable(false); 00633 display_image_=current_image_; 00634 updateView(); 00635 // updateImageOverlay(); 00636 00637 // only if segmentation is running labeling can be accepted 00638 accept_button_->Enable(false); 00639 00640 // only if segmentation is not running, it can be started 00641 segment_button_->Enable(true); 00642 } 00643 00644 /* 00645 * Saves the data 00646 */ 00647 void ObjectSegmentationUI::saveData() 00648 { 00649 //save data to the folder 00650 std::string filename_orig=data_string_ + "/original_image.jpg"; 00651 std::string filename_mask=data_string_ + "/segmented_image.jpg"; 00652 std::string filename_trial_data=data_string_ + "/trial_info.txt"; 00653 00654 cv_bridge::CvImagePtr cv_orig_ptr, cv_mask_ptr; 00655 00656 double diff_time=difftime(stop_time_, start_time_); 00657 ofstream file; 00658 file.open(filename_trial_data.c_str()); 00659 file << "Time with interface: " << diff_time<<endl; 00660 file << "Number of resets:" << num_resets_<<endl; 00661 file << "Grasp plan calculated " << object_grasp_; 00662 file.close(); 00663 00664 00665 //convert images to OpenCV so we can easily save them 00666 try{ 00667 cv_orig_ptr=cv_bridge::toCvCopy(current_image_); 00668 } 00669 catch(cv_bridge::Exception& e) 00670 { 00671 ROS_ERROR("Original image cv_bridge exception %s", e.what()); 00672 } 00673 00674 try{ 00675 cv_mask_ptr=cv_bridge::toCvCopy(display_image_); 00676 } 00677 catch(cv_bridge::Exception& e) 00678 { 00679 ROS_ERROR("BitMap image cv_bridge exception %s", e.what()); 00680 } 00681 00682 00683 //cv::namedWindow(WINDOW); 00684 //cv::imshow(WINDOW, cv_orig_ptr->image); 00685 00686 00687 //ROS_INFO_STREAM("mat info:" << cv_orig_ptr->image.rows << " " << cv_orig_ptr->image.cols); 00688 00689 cv::Mat original_bgr; 00690 cv::cvtColor(cv_orig_ptr->image, original_bgr, CV_RGB2BGR); 00691 if(!cv::imwrite(filename_orig.c_str(), original_bgr)) ROS_ERROR("Could not save original image"); 00692 if(!cv::imwrite(filename_mask.c_str(), cv_mask_ptr->image)) ROS_ERROR("Could not save mask image"); 00693 00694 } 00695 00700 void ObjectSegmentationUI::SetUpPickandPlaceApp() 00701 { 00702 COLLISION_PROCESSING_SERVICE_NAME = "/tabletop_collision_map_processing/tabletop_collision_map_processing"; 00703 PICKUP_ACTION_NAME = "/object_manipulator/object_manipulator_pickup"; 00704 PLACE_ACTION_NAME ="/object_manipulator/object_manipulator_place"; 00705 RGBD_ASSEMBLY_SERVICE_NAME="/rgbd_assembly"; 00706 ARM_ACTION_NAME="r_arm_controller/joint_trajectory_action"; 00707 //create service and action clients 00708 nh.reset(new ros::NodeHandle); 00709 chatter_pub= nh->advertise<tabletop_object_detector::TabletopDetectionResult>("chatter", 1000); 00710 00711 pickup_client= new actionlib::SimpleActionClient<object_manipulation_msgs::PickupAction>(PICKUP_ACTION_NAME, true); 00712 place_client= new actionlib::SimpleActionClient <object_manipulation_msgs::PlaceAction>(PLACE_ACTION_NAME, true); 00713 00714 00715 //wait for collision map processing client 00716 while ( !ros::service::waitForService(COLLISION_PROCESSING_SERVICE_NAME,ros::Duration(2.0)) && nh->ok() ) 00717 { 00718 ROS_INFO("Waiting for collision processing service to come up"); 00719 } 00720 if (!nh->ok()) exit(0); 00721 collision_processing_srv =nh->serviceClient <tabletop_collision_map_processing::TabletopCollisionMapProcessing> (COLLISION_PROCESSING_SERVICE_NAME, true); 00722 00723 while ( !ros::service::waitForService(RGBD_ASSEMBLY_SERVICE_NAME,ros::Duration(2.0)) && nh->ok() ) 00724 { 00725 ROS_INFO("Waiting for rgbd assembly service to come up"); 00726 } 00727 if (!nh->ok()) exit(0); 00728 rgbd_assembler_client_ =nh->serviceClient <rgbd_assembler::RgbdAssembly> (RGBD_ASSEMBLY_SERVICE_NAME, true); 00729 00730 //wait for pickup client 00731 while(!pickup_client->waitForServer(ros::Duration(2.0)) && nh->ok()) 00732 { 00733 ROS_INFO_STREAM("Waiting for action client " << PICKUP_ACTION_NAME); 00734 } 00735 if (!nh->ok()) exit(0); 00736 00737 //wait for place client 00738 while(!place_client->waitForServer(ros::Duration(2.0)) && nh->ok()) 00739 { 00740 ROS_INFO_STREAM("Waiting for action client " << PLACE_ACTION_NAME); 00741 } 00742 if (!nh->ok()) exit(0); 00743 00744 } 00745 00746 /* 00747 * Performs the manipulation after segmentation is complete 00748 */ 00749 00750 void ObjectSegmentationUI::RunRestOfPickAndPlace() 00751 { 00752 00753 stop_time_=time(0); 00754 ROS_INFO("publish publish"); 00755 ROS_INFO_STREAM("frameid " << detection_call_.table.x_max); 00756 ROS_INFO_STREAM("number of clusters" << detection_call_.clusters.size()); 00757 detection_call_.cluster_model_indices.push_back(0); 00758 detection_call_.models.push_back(household_objects_database_msgs::DatabaseModelPoseList()); 00759 00760 chatter_pub.publish(detection_call_); 00761 00762 if (detection_call_.result != 00763 detection_call_.SUCCESS) 00764 { 00765 ROS_ERROR("Tabletop detection returned error code %d", 00766 detection_call_.result); 00767 } 00768 if (detection_call_.clusters.empty() && 00769 detection_call_.models.empty() ) 00770 { 00771 ROS_ERROR("The tabletop detector detected the table, but found no objects"); 00772 00773 } 00774 //call collision map processing 00775 ROS_INFO("Calling collision map processing"); 00776 tabletop_collision_map_processing::TabletopCollisionMapProcessing processing_call; 00777 //pass the result of the tabletop detection 00778 processing_call.request.detection_result = detection_call_; 00779 //ask for the exising map and collision models to be reset 00780 //processing_call.request.reset_static_map = true; 00781 processing_call.request.reset_collision_models = true; 00782 processing_call.request.reset_attached_models = true; 00783 //ask for a new static collision map to be taken with the laser 00784 //after the new models are added to the environment 00785 //processing_call.request.take_static_collision_map = true; 00786 //ask for the results to be returned in base link frame 00787 processing_call.request.desired_frame = "/base_link"; 00788 if (!collision_processing_srv.call(processing_call)) 00789 { 00790 ROS_ERROR("Collision map processing service failed"); 00791 return; 00792 } 00793 //the collision map processor returns instances of graspable objects 00794 if (processing_call.response.graspable_objects.empty()) 00795 { 00796 ROS_ERROR("Collision map processing returned no graspable objects"); 00797 return; 00798 } 00799 00800 00801 //call object pickup 00802 ROS_INFO("Calling the pickup action"); 00803 object_manipulation_msgs::PickupGoal pickup_goal; 00804 //pass one of the graspable objects returned by the collission map processor 00805 pickup_goal.target = processing_call.response.graspable_objects.at(0); 00806 //pass the name that the object has in the collision environment 00807 //this name was also returned by the collision map processor 00808 pickup_goal.collision_object_name = 00809 processing_call.response.collision_object_names.at(0); 00810 //pass the collision name of the table, also returned by the collision 00811 //map processor 00812 pickup_goal.collision_support_surface_name = 00813 processing_call.response.collision_support_surface_name; 00814 //pick up the object with the right arm 00815 pickup_goal.arm_name = "right_arm"; 00816 00817 geometry_msgs::Vector3Stamped direction; 00818 direction.header.stamp = ros::Time::now(); 00819 direction.header.frame_id = "base_link"; 00820 direction.vector.x = 0; 00821 direction.vector.y = 0; 00822 direction.vector.z = 1; 00823 pickup_goal.lift.direction = direction; 00824 //request a vertical lift of 10cm after grasping the object 00825 pickup_goal.lift.desired_distance = 0.1; 00826 pickup_goal.lift.min_distance = 0.05; 00827 //do not use tactile-based grasping or tactile-based lift 00828 pickup_goal.use_reactive_lift = false; 00829 pickup_goal.use_reactive_execution = false; 00830 //send the goal 00831 pickup_client->sendGoal(pickup_goal); 00832 while (!pickup_client->waitForResult(ros::Duration(10.0))) 00833 { 00834 ROS_INFO("Waiting for the pickup action..."); 00835 } 00836 object_manipulation_msgs::PickupResult pickup_result = 00837 *(pickup_client->getResult()); 00838 if (pickup_client->getState() != actionlib::SimpleClientGoalState::SUCCEEDED) 00839 { 00840 ROS_ERROR("The pickup action has failed with result code %d", 00841 pickup_result.manipulation_result.value); 00842 00843 //object couldn't be grasped. 00844 00845 wxMessageBox(wxT("Sorry Alan can't grab that, try again!"), wxT("Grasp failure"), wxOK|wxICON_EXCLAMATION, this); 00846 saveData(); 00847 GetSensorData(); 00848 display_image_=current_image_; 00849 updateView(); 00850 accept_button_->Enable(false); 00851 object_grasp_=false; 00852 num_resets_=0; 00853 recording_time_=false; 00854 return; 00855 } 00856 object_grasp_=true; 00857 saveData(); 00858 00859 00860 //move arm up. 00861 tf::TransformListener listener; 00862 tf::StampedTransform transform; 00863 try 00864 { 00865 ros::Time now= ros::Time::now(); 00866 listener.waitForTransform("/base_link", "/r_wrist_roll_link", now, ros::Duration(3.0)); 00867 listener.lookupTransform("/base_link", "/r_wrist_roll_link", ros::Time(0), transform); 00868 geometry_msgs::PoseStamped newpose; 00869 newpose.header.frame_id="/base_link"; 00870 00871 newpose.pose.position.x=transform.getOrigin()[0]; 00872 newpose.pose.position.y=transform.getOrigin()[1]; 00873 newpose.pose.position.z=transform.getOrigin()[2]+.1; 00874 newpose.pose.orientation.x=transform.getRotation().getAxis()[0]; 00875 newpose.pose.orientation.y=transform.getRotation().getAxis()[1]; 00876 newpose.pose.orientation.z=transform.getRotation().getAxis()[2]; 00877 newpose.pose.orientation.w=transform.getRotation().getW(); 00878 00879 robot_.right_arm.moveWristRollLinktoPose(newpose ); 00880 } 00881 catch (tf::TransformException ex) 00882 { 00883 ROS_ERROR("Transform Error %s",ex.what()); 00884 } 00885 00886 //TODO: Find current /r_gripper_tool_frame (in base link) and then add to z 00887 00888 robot_.right_arm.moveGripperToPosition(tf::Vector3(0.55,-0.7, 1.03), 00889 "base_link", simple_robot_control::Arm::FROM_ABOVE); 00890 00891 robot_.right_arm.moveGripperToPosition(tf::Vector3(0.55,-0.7, 0.822), 00892 "base_link", simple_robot_control::Arm::FROM_ABOVE); 00893 00894 ROS_INFO("Publishing arm position"); 00895 00896 00897 00898 //open gripper 00899 robot_.right_gripper.open(-1); 00900 00901 00902 00903 //move arm back to initial ready position 00904 00905 robot_.right_arm.moveGripperToPosition(tf::Vector3(0.55,-0.7, 1.03), 00906 "base_link", simple_robot_control::Arm::FROM_ABOVE); 00907 00908 GetSensorData(); 00909 display_image_=current_image_; 00910 updateView(); 00911 accept_button_->Enable(false); 00912 num_resets_=0; 00913 recording_time_=false; 00914 } 00915 00916 00917 00918 }