tracker_node.cpp
Go to the documentation of this file.
00001 /*
00002  * Software License Agreement (Modified BSD License)
00003  *
00004  *  Copyright (c) 2012, PAL Robotics, S.L.
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions
00009  *  are met:
00010  *
00011  *   * Redistributions of source code must retain the above copyright
00012  *     notice, this list of conditions and the following disclaimer.
00013  *   * Redistributions in binary form must reproduce the above
00014  *     copyright notice, this list of conditions and the following
00015  *     disclaimer in the documentation and/or other materials provided
00016  *     with the distribution.
00017  *   * Neither the name of PAL Robotics, S.L. nor the names of its
00018  *     contributors may be used to endorse or promote products derived
00019  *     from this software without specific prior written permission.
00020  *
00021  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00022  *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00023  *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00024  *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00025  *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00026  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00027  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00028  *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
00029  *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00030  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
00031  *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00032  *  POSSIBILITY OF SUCH DAMAGE. 
00033  *
00034  * @file tracker_node.cpp
00035  * @author Bence Magyar
00036  * @date May 2012
00037  * @version 0.2
00038  * @brief Main file of BLORT tracker node for ROS.
00039  */
00040 
00041 #include <ros/ros.h>
00042 #include <opencv2/core/core.hpp>
00043 #include <ros/duration.h>
00044 #include <ros/time.h>
00045 
00046 #include <image_transport/image_transport.h>
00047 #include <image_transport/subscriber_filter.h>
00048 #include <message_filters/time_synchronizer.h>
00049 #include <cv_bridge/cv_bridge.h>
00050 #include <sensor_msgs/image_encodings.h>
00051 #include <geometry_msgs/Pose.h>
00052 #include <dynamic_reconfigure/server.h>
00053 
00054 #include <blort_ros/TrackerConfig.h>
00055 #include <blort_ros/TrackerCommand.h>
00056 #include <blort_ros/RecoveryCall.h>
00057 #include <blort_ros/EstimatePose.h>
00058 #include <blort_ros/SetCameraInfo.h>
00059 #include <blort/GLWindow/glxhidingwindow.h>
00060 #include <blort/blort/pal_util.h>
00061 #include "../gltracker.h"
00062 #include <boost/noncopyable.hpp>
00063 
00064 class TrackerNode : boost::noncopyable
00065 {
00066 private:
00067     class Mode;
00068     class TrackingMode;
00069     class SingleShotMode;
00070 
00071 private:
00072     ros::NodeHandle nh_;
00073     image_transport::ImageTransport it_;
00074     image_transport::Publisher image_pub;
00075     image_transport::Publisher image_debug_pub;
00076     ros::Publisher detection_result;
00077     ros::Publisher confidences_pub;
00078 
00079     //sensor_msgs::CameraInfo _msg;
00080 
00081     const std::string root_;
00082     ros::ServiceServer control_service;
00083     std::auto_ptr<dynamic_reconfigure::Server<blort_ros::TrackerConfig> > server_;
00084     dynamic_reconfigure::Server<blort_ros::TrackerConfig>::CallbackType f_;
00085     ros::ServiceClient recovery_client;
00086     blort_ros::GLTracker* tracker;
00087     std::string launch_mode;
00088 
00089     Mode* mode;
00090 public:
00091     
00092     TrackerNode(std::string root = ".")
00093         : nh_("blort_tracker"), it_(nh_), root_(root), tracker(0)
00094     {
00095         nh_.param<std::string>("launch_mode", launch_mode, "tracking");
00096         detection_result = nh_.advertise<geometry_msgs::Pose>("detection_result", 100);
00097         confidences_pub = nh_.advertise<blort_ros::TrackerConfidences>("confidences", 100);
00098         image_pub = it_.advertise("image_result", 1);
00099 
00100         if(launch_mode == "tracking")
00101         {
00102             mode = new TrackingMode(this);
00103         }else if(launch_mode == "singleshot")
00104         {
00105             mode = new SingleShotMode(this);
00106         } else {
00107             ROS_FATAL("Invalid launch_mode parameter passed to blort_tracker.");
00108         }
00109     }
00110     
00111     ~TrackerNode()
00112     {
00113         if(tracker != 0)
00114             delete(tracker);
00115         delete mode;
00116     }
00117     
00118     void imageCb(const sensor_msgs::ImageConstPtr& detectorImgMsg, const sensor_msgs::ImageConstPtr& trackerImgMsg )
00119     {
00120         if(tracker != 0)
00121         {
00122             cv_bridge::CvImagePtr cv_detector_ptr, cv_tracker_ptr;
00123             try
00124             {
00125                 cv_detector_ptr = cv_bridge::toCvCopy(detectorImgMsg, sensor_msgs::image_encodings::BGR8);
00126                 cv_tracker_ptr  = cv_bridge::toCvCopy(trackerImgMsg,  sensor_msgs::image_encodings::BGR8);
00127             }
00128             catch (cv_bridge::Exception& e)
00129             {
00130                 ROS_ERROR("cv_bridge exception: %s", e.what());
00131                 return;
00132             }
00133 
00134             if(tracker->getMode() == blort_ros::TRACKER_RECOVERY_MODE)
00135             {              
00136                 blort_ros::RecoveryCall srv = mode->recovery(detectorImgMsg);
00137 
00138                 ROS_INFO("tracker_node in TRACKER_RECOVERY_MODE: calling detector_node recovery service ...");
00139                 if(recovery_client.call(srv))
00140                 {
00141                   //tracker = new blort_ros::GLTracker(_msg, root_, true);
00142                   ROS_INFO("reseting tracker with pose from detector\n");
00143                   tracker->resetWithPose(srv.response.Pose);
00144                   ROS_INFO("AFTER reseting tracker with pose from detector\n");
00145                 }
00146                 else
00147                 {
00148                     ROS_WARN("Detector not confident enough.\n");
00149                 }
00150             }
00151             else //TRACKER_TRACKING_MODE or TRACKER_LOCKED_MODE
00152             {
00153               ROS_INFO("\n----------------------------------------------\n");
00154               ROS_INFO("TrackerNode::imageCb: calling tracker->process");
00155                 tracker->process(cv_tracker_ptr->image);
00156 
00157                 confidences_pub.publish(tracker->getConfidences());
00158                 if(tracker->getConfidence() == blort_ros::TRACKER_CONF_GOOD)
00159                 {
00160                     geometry_msgs::Pose target_pose = pal_blort::blortPosesToRosPose(tracker->getCameraReferencePose(),
00161                                                                                      tracker->getDetections()[0]);
00162 
00163                     detection_result.publish(target_pose);
00164                 }
00165 
00166                 cv_bridge::CvImage out_msg;
00167                 out_msg.header = trackerImgMsg->header;
00168                 out_msg.header.stamp = ros::Time::now();
00169                 //out_msg.encoding = sensor_msgs::image_encodings::TYPE_8UC3;
00170                 out_msg.encoding = sensor_msgs::image_encodings::BGR8;
00171                 out_msg.image = tracker->getImage();
00172                 image_pub.publish(out_msg.toImageMsg());
00173             }
00174         }
00175     }
00176     
00177     bool trackerControlServiceCb(blort_ros::TrackerCommand::Request &req,
00178                                  blort_ros::TrackerCommand::Response &)
00179     {
00180         if(tracker != 0)
00181         {
00182             tracker->trackerControl(req.code, req.param);
00183             return true;
00184         } else {
00185             ROS_WARN("Please publish camera_info for the tracker initialization.");
00186             return false;
00187         }
00188     }
00189 
00190     // STATE DESIGN PATTERN
00191     // to implement the different tracker modes
00192 private:
00193     class Mode
00194     {
00195     public:
00196         virtual void reconf_callback(blort_ros::TrackerConfig &config, uint32_t level) = 0;
00197         virtual blort_ros::RecoveryCall recovery(const sensor_msgs::ImageConstPtr& msg) = 0;
00198     };
00199 
00200     class TrackingMode : public Mode
00201     {
00202     private:
00203         ros::Subscriber cam_info_sub;        
00204         boost::shared_ptr<image_transport::SubscriberFilter> detector_image_sub, tracker_image_sub;
00205         boost::shared_ptr< message_filters::TimeSynchronizer<sensor_msgs::Image, sensor_msgs::Image > > imageSynchronizer;
00206         TrackerNode* parent_;
00207     public:
00208         TrackingMode(TrackerNode* parent) : parent_(parent)
00209         {
00210             ROS_INFO("Blort tracker launched in tracking mode.");
00211             cam_info_sub = parent_->nh_.subscribe("/detector_camera_info", 10, &TrackerNode::TrackingMode::cam_info_callback, this);
00212         }
00213 
00214         virtual void reconf_callback(blort_ros::TrackerConfig &config, uint32_t level)
00215         {
00216             if(parent_->tracker != 0)
00217             {
00218                 parent_->tracker->reconfigure(config);
00219             } else {
00220                 ROS_WARN("Please publish camera_info for the tracker initialization.");
00221             }
00222         }
00223 
00224         virtual blort_ros::RecoveryCall recovery(const sensor_msgs::ImageConstPtr& msg)
00225         {
00226             blort_ros::RecoveryCall srv;
00227             srv.request.Image = *msg;
00228             return srv;
00229         }
00230 
00231         // The real initialization is being done after receiving the camerainfo.
00232         void cam_info_callback(const sensor_msgs::CameraInfo &msg)
00233         {
00234             if(parent_->tracker == 0)
00235             {
00236                 ROS_INFO("Camera parameters received, ready to run.");
00237                 //parent_->_msg = msg; //2012-11-27 Jordi: keep a copy to reset the tracker when necessary
00238                 cam_info_sub.shutdown();
00239                 parent_->tracker = new blort_ros::GLTracker(msg, parent_->root_, true);
00240                 parent_->tracker->setVisualizeObjPose(true);
00241 
00242                 image_transport::TransportHints transportHint("raw");
00243 
00244                 detector_image_sub.reset( new image_transport::SubscriberFilter(parent_->it_, "/detector_image",   1, transportHint) );
00245                 tracker_image_sub.reset( new image_transport::SubscriberFilter(parent_->it_, "/tracker_image",   1, transportHint) );
00246 
00247                 imageSynchronizer.reset( new message_filters::TimeSynchronizer<sensor_msgs::Image,
00248                                                                                sensor_msgs::Image>(*detector_image_sub, *tracker_image_sub, 1) );
00249 
00250                 imageSynchronizer->registerCallback(boost::bind(&TrackerNode::imageCb, parent_, _1, _2));
00251 
00252                 parent_->control_service = parent_->nh_.advertiseService("tracker_control", &TrackerNode::trackerControlServiceCb, parent_);
00253                 parent_->server_ = std::auto_ptr<dynamic_reconfigure::Server<blort_ros::TrackerConfig> >
00254                                    (new dynamic_reconfigure::Server<blort_ros::TrackerConfig>());
00255                 parent_->f_ = boost::bind(&TrackerNode::TrackingMode::reconf_callback, this, _1, _2);
00256                 parent_->server_->setCallback(parent_->f_);
00257                 parent_->recovery_client = parent_->nh_.serviceClient<blort_ros::RecoveryCall>("/blort_detector/pose_service");
00258             }
00259         }
00260     };
00261 
00262     class SingleShotMode : public Mode
00263     {
00264     private:
00265         ros::ServiceServer singleshot_service;
00266         double time_to_run_singleshot;
00267         ros::ServiceClient detector_set_caminfo_service;
00268         bool inServiceCall;
00269         TrackerNode* parent_;
00270         std::list<geometry_msgs::Pose> results;
00271 
00272         ros::Subscriber cam_info_sub;
00273         image_transport::Subscriber image_sub;
00274         sensor_msgs::ImageConstPtr lastImage;
00275         sensor_msgs::CameraInfoConstPtr lastCameraInfo;
00276     public:
00277         SingleShotMode(TrackerNode* parent) : parent_(parent)
00278         {
00279             ROS_INFO("Blort tracker launched in singleshot mode.");
00280             detector_set_caminfo_service = parent_->nh_.serviceClient<blort_ros::SetCameraInfo>("/blort_detector/set_camera_info");
00281             singleshot_service = parent_->nh_.advertiseService("singleshot_service", &TrackerNode::SingleShotMode::singleShotService, this);
00282             image_sub = parent_->it_.subscribe("/blort_image_rect_masked", 10, &TrackerNode::SingleShotMode::imageCallback, this);
00283             cam_info_sub = parent_->nh_.subscribe("/detector_camera_info", 10, &TrackerNode::SingleShotMode::cameraCallback, this);
00284 
00285             parent_->control_service = parent_->nh_.advertiseService("tracker_control", &TrackerNode::trackerControlServiceCb, parent_);
00286             parent_->server_ = std::auto_ptr<dynamic_reconfigure::Server<blort_ros::TrackerConfig> >
00287                                (new dynamic_reconfigure::Server<blort_ros::TrackerConfig>());
00288             parent_->f_ = boost::bind(&SingleShotMode::reconf_callback, this, _1, _2);
00289             parent_->server_->setCallback(parent_->f_);
00290             
00291             time_to_run_singleshot = 10.;
00292             inServiceCall = false;
00293         }
00294 
00295         void imageCallback(const sensor_msgs::ImageConstPtr &image)
00296         {
00297             if(!inServiceCall)
00298             {
00299                 // if there is no ongoing servicecall, we can receive the new infos
00300                 // if we are in an ongoing servicecall, these fields should be constant
00301                 lastImage = image;
00302             }
00303         }
00304 
00305         void cameraCallback(const sensor_msgs::CameraInfoConstPtr &camera_info)
00306         {
00307             if(!inServiceCall)
00308             {
00309                 // if there is no ongoing servicecall, we can receive the new infos
00310                 // if we are in an ongoing servicecall, these fields should be constant
00311                 lastCameraInfo = camera_info;
00312             }
00313         }
00314 
00315         virtual void reconf_callback(blort_ros::TrackerConfig &config, uint32_t level)
00316         {
00317             time_to_run_singleshot =  config.time_to_run_singleshot;
00318         }
00319 
00320         virtual blort_ros::RecoveryCall recovery(const sensor_msgs::ImageConstPtr& msg)
00321         {
00322             blort_ros::RecoveryCall srv;
00323             if(!inServiceCall)
00324             {
00325                 srv.request.Image = *msg;
00326                 // we step into the service call "state" with the first recoverycall made
00327                 // no new images are accepted until the end of the singleShotServiceCall
00328                 inServiceCall = true;
00329             }
00330             return srv;
00331         }
00332 
00333         bool singleShotService(blort_ros::EstimatePose::Request &req,
00334                                blort_ros::EstimatePose::Response &resp)
00335         {
00336             if(lastImage.use_count() < 1 && lastCameraInfo.use_count() < 1)
00337             {
00338                 ROS_ERROR("Service called but there was no data on the input topics!");
00339                 return false;
00340             } else {
00341 
00342                 ROS_INFO("Singleshot service has been called with a timeout of %f seconds.", time_to_run_singleshot);
00343                 results.clear();
00344 
00345                 if(parent_->tracker == 0)
00346                 {
00347                     parent_->tracker = new blort_ros::GLTracker(*lastCameraInfo, parent_->root_, true);
00348                     parent_->recovery_client = parent_->nh_.serviceClient<blort_ros::RecoveryCall>("/blort_detector/poseService");
00349                 } else {
00350                     parent_->tracker->reset();
00351                 }
00352                 parent_->tracker->setPublisMode(blort_ros::TRACKER_PUBLISH_GOOD);
00353                 parent_->tracker->setVisualizeObjPose(true);
00354                 blort_ros::SetCameraInfo camera_info;
00355                 camera_info.request.CameraInfo = *lastCameraInfo;
00356                 if(!detector_set_caminfo_service.call(camera_info))
00357                     ROS_ERROR("blort_tracker failed to call blort_detector/set_camera_info service");
00358 
00359                 double start_secs = ros::Time::now().toSec();
00360                 while(ros::Time::now().toSec()-start_secs < time_to_run_singleshot)
00361                 {
00362                     ROS_INFO("Remaining time %f", time_to_run_singleshot+start_secs-ros::Time::now().toSec());
00363                     parent_->imageCb(lastImage, lastImage);
00364                     if(parent_->tracker->getConfidence() == blort_ros::TRACKER_CONF_GOOD)
00365                     {
00366                         // instead of returning right away let's store the result
00367                         // to see if the tracker can get better
00368                         results.push_back(parent_->tracker->getDetections()[0]);
00369                     } else if(parent_->tracker->getConfidence() == blort_ros::TRACKER_CONF_LOST)
00370                     {
00371                         results.clear();
00372                     }
00373                 }
00374                 // we are out of the service call now, the results will be published
00375                 inServiceCall = false;
00376                 if(!results.empty())
00377                 {
00378                     //convert results to a tf style transform and multiply them
00379                     //to get the camera-to-target transformation
00380                     resp.Pose = pal_blort::blortPosesToRosPose(parent_->tracker->getCameraReferencePose(),
00381                                                                results.back());
00382                     //NOTE: check the pose in vec3 location + mat3x3 rotation could be added here
00383                     // if we have any previous knowledge of the given scene
00384                     ROS_INFO_STREAM("PUBLISHED POSE: \n" << resp.Pose.position << "\n" <<
00385                                     pal_blort::quaternionTo3x3cvMat(resp.Pose.orientation) << "\n");
00386                     return true;
00387                 } else {
00388                     //if the time was not enough to get a good detection, make the whole thing fail
00389                     return false;
00390                 }
00391             }
00392         }
00393     };
00394 };
00395 
00396 int main(int argc, char *argv[] )
00397 {
00398     if(argc < 2)
00399     {
00400         ROS_ERROR("The first command line argument should be the package root!");
00401         return -1;
00402     }
00403     ros::init(argc, argv, "blort_tracker");
00404     //FIXME: hardcoded size, 1x1 is not good, renders the tracker unfunctional in runtime
00405     // size should be not smaller the image size, too big size is also wrong
00406     pal_blort::GLXHidingWindow window(656, 492, "Tracker"); // a window which should hide itself after start
00407     //blortGLWindow::GLWindow window(640  , 480, "Window"); // a normal opengl window
00408     TrackerNode node(argv[1]);
00409     ros::spin();
00410     return 0;
00411 }
00412 


blort_ros
Author(s): Bence Magyar
autogenerated on Thu Jan 2 2014 11:39:13