00001 #include <blort_ros/tracker_node.h>
00002 #include <boost/foreach.hpp>
00003 #include <sstream>
00004
00005 TrackerNode::TrackerNode(std::string root)
00006 : nh_("blort_tracker"), it_(nh_), pose_seq(0), camera_frame_id("0"), root_(root), tracker(0)
00007 {
00008 nh_.param<std::string>("launch_mode", launch_mode, "tracking");
00009 detection_result = nh_.advertise<blort_msgs::TrackerResults>("detection_result", 100);
00010 confidences_pub = nh_.advertise<blort_msgs::TrackerConfidences>("confidences", 100);
00011 image_pub = it_.advertise("image_result", 1);
00012
00013 if(launch_mode == "tracking")
00014 {
00015 mode = new TrackingMode(this);
00016 }else if(launch_mode == "singleshot")
00017 {
00018 mode = new SingleShotMode(this);
00019 } else {
00020 ROS_FATAL("Invalid launch_mode parameter passed to blort_tracker.");
00021 }
00022 }
00023
00024 TrackerNode::~TrackerNode()
00025 {
00026 if(tracker != 0)
00027 delete(tracker);
00028 delete mode;
00029 }
00030
00031 void TrackerNode::setCameraFrameID(const std::string & id)
00032 {
00033 camera_frame_id = id;
00034 }
00035
00036 void TrackerNode::imageCb(const sensor_msgs::ImageConstPtr& detectorImgMsg,
00037 const sensor_msgs::ImageConstPtr& trackerImgMsg )
00038 {
00039 if(tracker != 0)
00040 {
00041 cv_bridge::CvImagePtr cv_detector_ptr, cv_tracker_ptr;
00042 try
00043 {
00044 cv_detector_ptr = cv_bridge::toCvCopy(detectorImgMsg, sensor_msgs::image_encodings::BGR8);
00045 cv_tracker_ptr = cv_bridge::toCvCopy(trackerImgMsg, sensor_msgs::image_encodings::BGR8);
00046 }
00047 catch (cv_bridge::Exception& e)
00048 {
00049 ROS_ERROR("cv_bridge exception: %s", e.what());
00050 return;
00051 }
00052
00053 bool should_process = false;
00054 std::vector<std::string> lost_ids;
00055 BOOST_FOREACH(const blort::ObjectEntry& obj, tracker->getObjects())
00056 {
00057 if(obj.is_tracked)
00058 {
00059 if(tracker->getMode(obj.name) == blort_ros::TRACKER_RECOVERY_MODE)
00060 {
00061 if(recovery_answers.count(obj.name))
00062 {
00063 tracker->resetWithPose(obj.name, recovery_answers[obj.name]);
00064 recovery_answers.erase(obj.name);
00065 }
00066 else
00067 {
00068 lost_ids.push_back(obj.name);
00069 }
00070 }
00071 else
00072 {
00073 should_process = true;
00074 }
00075 }
00076 }
00077 if(!lost_ids.empty())
00078 {
00079 boost::mutex::scoped_lock lock(recovery_mutex, boost::try_to_lock);
00080 if(lock)
00081 {
00082
00083 recovery_th = boost::thread(boost::bind(&TrackerNode::recovery, this, mode->getRecoveryCall(lost_ids, detectorImgMsg)));
00084 }
00085 }
00086 if(should_process)
00087 {
00088 ROS_INFO("----------------------------------------------");
00089 ROS_INFO("TrackerNode::imageCb: calling tracker->process");
00090 tracker->process(cv_tracker_ptr->image);
00091 BOOST_FOREACH(const blort::ObjectEntry& obj, tracker->getObjects())
00092 {
00093 if(tracker->getMode(obj.name) != blort_ros::TRACKER_RECOVERY_MODE && obj.is_tracked)
00094 {
00095
00096 if(tracker->getConfidence(obj.name) == blort_ros::TRACKER_CONF_GOOD ||
00097 (tracker->getConfidence(obj.name) == blort_ros::TRACKER_CONF_FAIR &&
00098 tracker->getPublishMode() == blort_ros::TRACKER_PUBLISH_GOOD_AND_FAIR) )
00099 {
00100 blort_msgs::TrackerResults msg;
00101 msg.obj_name.data = obj.name;
00102 msg.pose.header.seq = pose_seq++;
00103 msg.pose.header.stamp = ros::Time::now();
00104 msg.pose.header.frame_id = camera_frame_id;
00105 msg.pose.pose = blort_ros::blortPosesToRosPose(tracker->getCameraReferencePose(),
00106 tracker->getDetections()[obj.name]);
00107 detection_result.publish(msg);
00108 }
00109 }
00110 cv_bridge::CvImage out_msg;
00111 out_msg.header = trackerImgMsg->header;
00112 out_msg.header.stamp = ros::Time::now();
00113 out_msg.encoding = sensor_msgs::image_encodings::BGR8;
00114 out_msg.image = tracker->getImage();
00115 image_pub.publish(out_msg.toImageMsg());
00116 }
00117 }
00118 }
00119 }
00120
00121 void TrackerNode::recovery(blort_msgs::RecoveryCall srv)
00122 {
00123 boost::mutex::scoped_lock lock(recovery_mutex);
00124 ros::Time before = ros::Time::now();
00125 {
00126 std::stringstream ss;
00127 ss << "tracker_node calling detector_node recovery service for object(s): ";
00128 for(size_t i = 0; i < srv.request.object_ids.size();++i)
00129 {
00130 ss << srv.request.object_ids[i] << ", ";
00131 }
00132 ROS_WARN_STREAM(ss.str());
00133 }
00134 if(recovery_client.call(srv))
00135 {
00136 for(size_t i = 0; i < srv.response.Poses.size(); ++i)
00137 {
00138 if(srv.response.object_founds[i])
00139 {
00140 recovery_answers[srv.response.object_ids[i]] = srv.response.Poses[i];
00141 }
00142 }
00143 }
00144 else
00145 {
00146 ROS_WARN("Detector not confident enough.");
00147 }
00148 ROS_INFO_STREAM("Recovery call took " << (ros::Time::now() - before));
00149 }
00150
00151 bool TrackerNode::trackerControlServiceCb(blort_msgs::TrackerCommand::Request &req,
00152 blort_msgs::TrackerCommand::Response &)
00153 {
00154 if(tracker != 0)
00155 {
00156 tracker->trackerControl(req.code, req.param);
00157 return true;
00158 } else {
00159 ROS_WARN("Please publish camera_info for the tracker initialization.");
00160 return false;
00161 }
00162 }
00163
00164
00165
00166 TrackerNode::TrackingMode::TrackingMode(TrackerNode* parent) : parent_(parent)
00167 {
00168 ROS_INFO("Blort tracker launched in tracking mode.");
00169 cam_info_sub = parent_->nh_.subscribe("/detector_camera_info", 10,
00170 &TrackerNode::TrackingMode::cam_info_callback, this);
00171 }
00172
00173 void TrackerNode::TrackingMode::reconf_callback(blort_ros::TrackerConfig &config, uint32_t level)
00174 {
00175 if(parent_->tracker != 0)
00176 {
00177 parent_->tracker->reconfigure(config);
00178 } else {
00179 ROS_WARN("Please publish camera_info for the tracker initialization.");
00180 }
00181 }
00182
00183 blort_msgs::RecoveryCall TrackerNode::TrackingMode::getRecoveryCall(std::vector<std::string> & ids,
00184 const sensor_msgs::ImageConstPtr& msg)
00185 {
00186 blort_msgs::RecoveryCall srv;
00187 srv.request.object_ids.resize(ids.size());
00188 for(size_t i = 0; i < ids.size(); ++i)
00189 {
00190 srv.request.object_ids[i] = ids[i];
00191 }
00192 srv.request.Image = *msg;
00193 return srv;
00194 }
00195
00196
00197 void TrackerNode::TrackingMode::cam_info_callback(const sensor_msgs::CameraInfo &msg)
00198 {
00199 if(parent_->tracker == 0)
00200 {
00201 ROS_INFO("Camera parameters received, ready to run.");
00202 parent_->setCameraFrameID(msg.header.frame_id);
00203
00204 cam_info_sub.shutdown();
00205 parent_->tracker = new blort_ros::GLTracker(msg, parent_->root_, true);
00206 parent_->tracker->setVisualizeObjPose(true);
00207 parent_->tracker->enableAllTracking(true);
00208
00209 image_transport::TransportHints transportHint("raw");
00210
00211 detector_image_sub.reset(new image_transport::SubscriberFilter(
00212 parent_->it_, "/detector_image", 1, transportHint));
00213 tracker_image_sub.reset(new image_transport::SubscriberFilter(
00214 parent_->it_, "/tracker_image", 1, transportHint));
00215
00216 imageSynchronizer.reset( new message_filters::TimeSynchronizer<sensor_msgs::Image,
00217 sensor_msgs::Image>(*detector_image_sub, *tracker_image_sub, 1) );
00218
00219 imageSynchronizer->registerCallback(boost::bind(&TrackerNode::imageCb, parent_, _1, _2));
00220
00221 parent_->control_service = parent_->nh_.advertiseService(
00222 "tracker_control", &TrackerNode::trackerControlServiceCb, parent_);
00223 parent_->server_ = std::auto_ptr<dynamic_reconfigure::Server<blort_ros::TrackerConfig> >
00224 (new dynamic_reconfigure::Server<blort_ros::TrackerConfig>());
00225 parent_->f_ = boost::bind(&TrackerNode::TrackingMode::reconf_callback, this, _1, _2);
00226 parent_->server_->setCallback(parent_->f_);
00227 parent_->recovery_client = parent_->nh_.serviceClient<blort_msgs::RecoveryCall>("/blort_detector/pose_service");
00228 }
00229 }
00230
00231 TrackerNode::SingleShotMode::SingleShotMode(TrackerNode* parent)
00232 : as_(parent->nh_, "recognize_object", false)
00233 , parent_(parent)
00234 {
00235 ROS_INFO("Blort tracker launched in singleshot mode.");
00236 detector_set_caminfo_service = parent_->nh_.serviceClient<blort_msgs::SetCameraInfo>("/blort_detector/set_camera_info");
00237 singleshot_service = parent_->nh_.advertiseService("singleshot_service", &TrackerNode::SingleShotMode::singleShotService, this);
00238
00239 parent_->control_service = parent_->nh_.advertiseService("tracker_control", &TrackerNode::trackerControlServiceCb, parent_);
00240 parent_->server_ = std::auto_ptr<dynamic_reconfigure::Server<blort_ros::TrackerConfig> >
00241 (new dynamic_reconfigure::Server<blort_ros::TrackerConfig>());
00242 parent_->f_ = boost::bind(&SingleShotMode::reconf_callback, this, _1, _2);
00243 parent_->server_->setCallback(parent_->f_);
00244
00245 time_to_run_singleshot = 10.;
00246 inServiceCall = false;
00247 parent->nh_.param<double>("conf_threshold", conf_treshold_, 0.3);
00248
00249 as_.registerGoalCallback(boost::bind(&TrackerNode::SingleShotMode::goalCb, this, _1));
00250 as_.start();
00251 }
00252
00253 void TrackerNode::SingleShotMode::reconf_callback(blort_ros::TrackerConfig &config, uint32_t level)
00254 {
00255 time_to_run_singleshot = config.time_to_run_singleshot;
00256 }
00257
00258 blort_msgs::RecoveryCall TrackerNode::SingleShotMode::getRecoveryCall(std::vector<std::string> & ids,
00259 const sensor_msgs::ImageConstPtr& msg)
00260 {
00261 blort_msgs::RecoveryCall srv;
00262 if(!inServiceCall)
00263 {
00264 srv.request.object_ids.resize(ids.size());
00265 for(size_t i = 0; i < ids.size(); ++i)
00266 {
00267 ROS_WARN_STREAM("TrackerNode::SingleShotMode::getRecoveryCall: " << ids[i]);
00268 srv.request.object_ids[i] = ids[i];
00269 }
00270 srv.request.Image = *msg;
00271
00272
00273 inServiceCall = true;
00274 }
00275 return srv;
00276 }
00277
00278
00279
00280 bool TrackerNode::SingleShotMode::singleShotService(blort_msgs::EstimatePose::Request &req,
00281 blort_msgs::EstimatePose::Response &resp)
00282 {
00283 lastImage.reset();
00284 lastImage = ros::topic::waitForMessage<sensor_msgs::Image>("/detector_image", parent_->nh_, ros::Duration(1.0));
00285 lastCameraInfo.reset();
00286 lastCameraInfo = ros::topic::waitForMessage<sensor_msgs::CameraInfo>("/detector_camera_info", parent_->nh_, ros::Duration(1.0));
00287
00288 if(lastImage.use_count() < 1 && lastCameraInfo.use_count() < 1)
00289 {
00290 ROS_ERROR("Service called but there was no data on the input topics!");
00291 return false;
00292 }
00293 else
00294 {
00295 ROS_INFO("Singleshot service has been called with a timeout of %f seconds.", time_to_run_singleshot);
00296 results_list.clear();
00297
00298 if(parent_->tracker == 0)
00299 {
00300 parent_->tracker = new blort_ros::GLTracker(*lastCameraInfo, parent_->root_, true);
00301 parent_->recovery_client = parent_->nh_.serviceClient<blort_msgs::RecoveryCall>("/blort_detector/pose_service");
00302 }
00303 else
00304 {
00305 parent_->tracker->reset();
00306 parent_->recovery_answers.clear();
00307 }
00308
00309 parent_->tracker->enableAllTracking(false);
00310 parent_->tracker->setTracked("Pringles", true);
00311
00312 parent_->tracker->setPublishMode(blort_ros::TRACKER_PUBLISH_GOOD);
00313 parent_->tracker->setVisualizeObjPose(true);
00314 blort_msgs::SetCameraInfo camera_info;
00315 camera_info.request.CameraInfo = *lastCameraInfo;
00316 if(!detector_set_caminfo_service.call(camera_info))
00317 ROS_ERROR("blort_tracker failed to call blort_detector/set_camera_info service");
00318
00319 double start_secs = ros::Time::now().toSec();
00320 while(ros::Time::now().toSec()-start_secs < time_to_run_singleshot)
00321 {
00322 ROS_INFO("Remaining time %f", time_to_run_singleshot+start_secs-ros::Time::now().toSec());
00323 parent_->imageCb(lastImage, lastImage);
00324 if(parent_->tracker->getConfidence("Pringles") == blort_ros::TRACKER_CONF_FAIR)
00325 {
00326
00327
00328 results_list.push_back(parent_->tracker->getDetections()["Pringles"]);
00329 }
00330 else if(parent_->tracker->getConfidence("Pringles") == blort_ros::TRACKER_CONF_LOST)
00331 {
00332 results_list.clear();
00333 }
00334 }
00335
00336 inServiceCall = false;
00337 if(!results_list.empty())
00338 {
00339
00340
00341 resp.Pose = blort_ros::blortPosesToRosPose(parent_->tracker->getCameraReferencePose(),
00342 results_list.back());
00343
00344
00345 ROS_INFO_STREAM("PUBLISHED POSE:" << std::endl << resp.Pose.position << std::endl <<
00346 blort_ros::quaternionTo3x3cvMat(resp.Pose.orientation) << std::endl);
00347 return true;
00348 }
00349 else
00350 {
00351
00352 return false;
00353 }
00354 }
00355 }
00356
00357 void TrackerNode::SingleShotMode::goalCb(AcServer::GoalHandle gh)
00358 {
00359 AcServer::GoalConstPtr goal = gh.getGoal();
00360 gh.setAccepted();
00361 result_.recognized_objects.objects.clear();
00362
00363 if(goal->objects.empty())
00364 {
00365 gh.setSucceeded(result_);
00366 return;
00367 }
00368
00369 lastImage.reset();
00370 lastImage = ros::topic::waitForMessage<sensor_msgs::Image>("/detector_image", parent_->nh_, ros::Duration(3.0));
00371 sensor_msgs::ImageConstPtr lastDepth = ros::topic::waitForMessage<sensor_msgs::Image>("/depth_image", parent_->nh_, ros::Duration(3.0));
00372 lastCameraInfo.reset();
00373 lastCameraInfo = ros::topic::waitForMessage<sensor_msgs::CameraInfo>("/detector_camera_info", parent_->nh_, ros::Duration(3.0));
00374 if(lastImage.use_count() < 1 && lastCameraInfo.use_count() < 1)
00375 {
00376 ROS_ERROR("Action called but there was no data on the input topics!");
00377 gh.setAborted();
00378 return;
00379 }
00380
00381 if(goal->refine_pose_time <= 0)
00382 {
00383 ROS_ERROR("Refine pose time must be positive.");
00384 gh.setRejected();
00385 return;
00386 }
00387
00388
00389
00390
00391 if(parent_->tracker != 0)
00392 delete parent_->tracker;
00393
00394 parent_->tracker = new blort_ros::GLTracker(*lastCameraInfo, parent_->root_, true);
00395 parent_->recovery_client = parent_->nh_.serviceClient<blort_msgs::RecoveryCall>("/blort_detector/pose_service");
00396 parent_->recovery_answers.clear();
00397 parent_->tracker->enableAllTracking(false);
00398
00399
00400 BOOST_FOREACH(const object_recognition_msgs::ObjectType& obj_type, goal->objects)
00401 {
00402 bool found = false;
00403 BOOST_FOREACH(const blort::ObjectEntry& obj, parent_->tracker->getObjects())
00404 {
00405 if(obj.name == obj_type.key)
00406 {
00407 found = true;
00408 break;
00409 }
00410 }
00411 if(!found)
00412 {
00413 ROS_ERROR_STREAM("Unknown object called: " << obj_type.key);
00414 gh.setAborted();
00415 return;
00416 }
00417 }
00418
00419 std::stringstream ss;
00420 BOOST_FOREACH(const object_recognition_msgs::ObjectType& obj_type, goal->objects)
00421 {
00422 parent_->tracker->setTracked(obj_type.key, true);
00423 ss << obj_type.key << ",";
00424 }
00425 ROS_INFO_STREAM("TrackerNode::SingleShotMode::goalCb(): Received request to recognize '"
00426 << ss.str() <<"' in " << goal->refine_pose_time << "seconds.");
00427
00428
00429 parent_->tracker->setPublishMode(blort_ros::TRACKER_PUBLISH_GOOD_AND_FAIR);
00430 parent_->tracker->setVisualizeObjPose(true);
00431 blort_msgs::SetCameraInfo camera_info;
00432 camera_info.request.CameraInfo = *lastCameraInfo;
00433 if(!detector_set_caminfo_service.call(camera_info))
00434 ROS_ERROR("blort_tracker failed to call blort_detector/set_camera_info service");
00435
00436 std::map< std::string, std::vector<geometry_msgs::Pose> > results;
00437 double start_secs = ros::Time::now().toSec();
00438 while(ros::Time::now().toSec()-start_secs < goal->refine_pose_time)
00439 {
00440
00441 feedback_.time_left = goal->refine_pose_time+start_secs-ros::Time::now().toSec();
00442 gh.publishFeedback(feedback_);
00443 ROS_INFO("Remaining time %f", feedback_.time_left);
00444
00445 parent_->imageCb(lastImage, lastImage);
00446
00447 BOOST_FOREACH(const blort::ObjectEntry& obj, parent_->tracker->getObjects())
00448 {
00449 bool found = false;
00450 BOOST_FOREACH(const object_recognition_msgs::ObjectType& obj_type, goal->objects)
00451 {
00452 found = found || (obj.name == obj_type.key);
00453 }
00454 if(found)
00455 {
00456 ROS_ERROR_STREAM(obj.name << " with confidence " << obj.edgeConf
00457 << ", when threshold is " << conf_treshold_);
00458
00459
00460
00461 if(obj.edgeConf > conf_treshold_ &&
00462 !(parent_->tracker->getDetections()[obj.name].position.x == 0 &&
00463 parent_->tracker->getDetections()[obj.name].position.y == 0 &&
00464 parent_->tracker->getDetections()[obj.name].position.z == 0) )
00465 {
00466
00467
00468 results[obj.name].push_back(parent_->tracker->getDetections()[obj.name]);
00469 }
00470 else
00471 {
00472 results[obj.name].clear();
00473 }
00474 }
00475 }
00476 }
00477 inServiceCall = false;
00478
00479
00480 BOOST_FOREACH(const object_recognition_msgs::ObjectType& obj, goal->objects)
00481 {
00482 if(!results[obj.key].empty())
00483 {
00484 object_recognition_msgs::RecognizedObject r_obj;
00485
00486 r_obj.pose.header.frame_id = lastCameraInfo->header.frame_id;
00487 r_obj.pose.header.stamp = ros::Time::now();
00488 r_obj.type.key = obj.key;
00489
00490
00491 r_obj.pose.pose.pose = blort_ros::blortPosesToRosPose(parent_->tracker->getCameraReferencePose(),
00492 results[obj.key].back());
00493
00494 if(lastDepth.use_count() > 0)
00495 {
00496 r_obj.pose.pose.pose.position.z = getDistance(lastDepth,
00497 r_obj.pose.pose.pose.position.x,
00498 r_obj.pose.pose.pose.position.y,
00499 r_obj.pose.pose.pose.position.z);
00500 }
00501 result_.recognized_objects.objects.push_back(r_obj);
00502
00503
00504
00505
00506 }
00507 }
00508 gh.setSucceeded(result_);
00509 }
00510
00511 double TrackerNode::SingleShotMode::getDistance(const sensor_msgs::ImageConstPtr& img, double x, double y, double z)
00512 {
00513 double u = (lastCameraInfo->P[0]*x)/z + lastCameraInfo->P[2];
00514 double v = (lastCameraInfo->P[5]*y)/z + lastCameraInfo->P[6];
00515
00516 cv_bridge::CvImagePtr depth_ptr;
00517 try
00518 {
00519 depth_ptr = cv_bridge::toCvCopy(img, sensor_msgs::image_encodings::TYPE_32FC1);
00520 ROS_WARN_STREAM("[x,y,z] : " << "[" << x << "," << y << "," << z << "] --- " <<
00521 "[u,v] : [" << u << "," << v << "] in an image of [" << depth_ptr->image.rows << "," << depth_ptr->image.cols << "]");
00522 }
00523 catch (cv_bridge::Exception& e)
00524 {
00525 ROS_ERROR("cv_bridge exception: %s", e.what());
00526 return 0.0;
00527 }
00528
00529
00530 float arr[] = {depth_ptr->image.at<float>(round(v)-1, round(u)-1), depth_ptr->image.at<float>(round(v)-1, round(u)),
00531 depth_ptr->image.at<float>(round(v)-1, round(u)+1), depth_ptr->image.at<float>(round(v), round(u)-1),
00532 depth_ptr->image.at<float>(round(v), round(u)), depth_ptr->image.at<float>(round(v), round(u)+1),
00533 depth_ptr->image.at<float>(round(v)+1, round(u)-1), depth_ptr->image.at<float>(round(v)+1, round(u)),
00534 depth_ptr->image.at<float>(round(v)+1, round(u)+1)};
00535 std::nth_element(arr, arr+5, arr+9);
00536
00537
00538
00539
00540
00541
00542
00543 ROS_WARN_STREAM("Median is " << arr[5]);
00544
00545 return arr[5];
00546 }
00547
00548
00549 int main(int argc, char *argv[] )
00550 {
00551 if(argc < 2)
00552 {
00553 ROS_ERROR("The first command line argument should be the package root!");
00554 return -1;
00555 }
00556 ros::init(argc, argv, "blort_tracker");
00557
00558
00559 blort_ros::GLXHidingWindow window(656, 492, "Tracker");
00560
00561 TrackerNode node(argv[1]);
00562 ros::spin();
00563 return 0;
00564 }
00565