00001 #include <cstdlib>
00002 #include <fstream>
00003 #include <sstream>
00004
00005 #include <boost/bind.hpp>
00006 #include <boost/filesystem.hpp>
00007 #include <boost/filesystem/fstream.hpp>
00008 #include <boost/filesystem/path.hpp>
00009 #include <boost/format.hpp>
00010 #include <boost/optional.hpp>
00011
00012 #include <ros/ros.h>
00013 #include <ros/param.h>
00014 #include <image_transport/image_transport.h>
00015
00016 #include <visp/vpDisplayX.h>
00017
00018 #include "conversion.hh"
00019 #include "callbacks.hh"
00020 #include "file.hh"
00021 #include "names.hh"
00022
00023 #include "tracker-viewer.hh"
00024
00025 namespace visp_tracker
00026 {
00027 namespace
00028 {
00029 static void increment(unsigned int* value)
00030 {
00031 ++(*value);
00032 }
00033 }
00034
00035 TrackerViewer::TrackerViewer(ros::NodeHandle& nh,
00036 ros::NodeHandle& privateNh,
00037 volatile bool& exiting,
00038 unsigned queueSize)
00039 : exiting_ (exiting),
00040 queueSize_(queueSize),
00041 nodeHandle_(nh),
00042 nodeHandlePrivate_(privateNh),
00043 imageTransport_(nodeHandle_),
00044 rectifiedImageTopic_(),
00045 cameraInfoTopic_(),
00046 checkInputs_(nodeHandle_, ros::this_node::getName()),
00047 tracker_(),
00048 cameraParameters_(),
00049 image_(),
00050 info_(),
00051 cMo_(boost::none),
00052 sites_(),
00053 imageSubscriber_(),
00054 cameraInfoSubscriber_(),
00055 trackingResultSubscriber_(),
00056 movingEdgeSitesSubscriber_(),
00057 kltPointsSubscriber_(),
00058 synchronizer_(syncPolicy_t(queueSize_)),
00059 timer_(),
00060 countAll_(0u),
00061 countImages_(0u),
00062 countCameraInfo_(0u),
00063 countTrackingResult_(0u),
00064 countMovingEdgeSites_(0u),
00065 countKltPoints_(0u)
00066 {
00067
00068 std::string cameraPrefix;
00069
00070 ros::Rate rate (1);
00071 while (cameraPrefix.empty ())
00072 {
00073 if (!nodeHandle_.getParam ("camera_prefix", cameraPrefix))
00074 {
00075 ROS_WARN
00076 ("the camera_prefix parameter does not exist.\n"
00077 "This may mean that:\n"
00078 "- the tracker is not launched,\n"
00079 "- the tracker and viewer are not running in the same namespace."
00080 );
00081 }
00082 else if (cameraPrefix.empty ())
00083 {
00084 ROS_INFO
00085 ("tracker is not yet initialized, waiting...\n"
00086 "You may want to launch the client to initialize the tracker.");
00087 }
00088 if (this->exiting())
00089 return;
00090 rate.sleep ();
00091 }
00092
00093 rectifiedImageTopic_ =
00094 ros::names::resolve(cameraPrefix + "/image_rect");
00095 cameraInfoTopic_ =
00096 ros::names::resolve(cameraPrefix + "/camera_info");
00097
00098 boost::filesystem::ofstream modelStream;
00099 std::string path;
00100
00101 while (!nodeHandle_.hasParam(visp_tracker::model_description_param))
00102 {
00103 if (!nodeHandle_.hasParam(visp_tracker::model_description_param))
00104 {
00105 ROS_WARN
00106 ("the model_description parameter does not exist.\n"
00107 "This may mean that:\n"
00108 "- the tracker is not launched or not initialized,\n"
00109 "- the tracker and viewer are not running in the same namespace."
00110 );
00111 }
00112 if (this->exiting())
00113 return;
00114 rate.sleep ();
00115 }
00116
00117 if (!makeModelFile(modelStream, path))
00118 throw std::runtime_error
00119 ("failed to load the model from the parameter server");
00120 ROS_INFO_STREAM("Model loaded from the parameter server.");
00121 vrmlPath_ = path;
00122
00123 initializeTracker();
00124 if (this->exiting())
00125 return;
00126
00127 checkInputs();
00128 if (this->exiting())
00129 return;
00130
00131
00132 imageSubscriber_.subscribe
00133 (imageTransport_, rectifiedImageTopic_, queueSize_);
00134 cameraInfoSubscriber_.subscribe
00135 (nodeHandle_, cameraInfoTopic_, queueSize_);
00136 trackingResultSubscriber_.subscribe
00137 (nodeHandle_, visp_tracker::object_position_covariance_topic,
00138 queueSize_);
00139 movingEdgeSitesSubscriber_.subscribe
00140 (nodeHandle_, visp_tracker::moving_edge_sites_topic, queueSize_);
00141 kltPointsSubscriber_.subscribe
00142 (nodeHandle_, visp_tracker::klt_points_topic, queueSize_);
00143
00144 synchronizer_.connectInput
00145 (imageSubscriber_, cameraInfoSubscriber_,
00146 trackingResultSubscriber_, movingEdgeSitesSubscriber_, kltPointsSubscriber_);
00147 synchronizer_.registerCallback(boost::bind(&TrackerViewer::callback,
00148 this, _1, _2, _3, _4, _5));
00149
00150
00151 synchronizer_.registerCallback(boost::bind(increment, &countAll_));
00152 imageSubscriber_.registerCallback(boost::bind(increment, &countImages_));
00153 cameraInfoSubscriber_.registerCallback
00154 (boost::bind(increment, &countCameraInfo_));
00155 trackingResultSubscriber_.registerCallback
00156 (boost::bind(increment, &countTrackingResult_));
00157 movingEdgeSitesSubscriber_.registerCallback
00158 (boost::bind(increment, &countMovingEdgeSites_));
00159 kltPointsSubscriber_.registerCallback
00160 (boost::bind(increment, &countKltPoints_));
00161
00162 timer_ = nodeHandle_.createWallTimer
00163 (ros::WallDuration(30.),
00164 boost::bind(&TrackerViewer::timerCallback, this));
00165
00166
00167 waitForImage();
00168 if (this->exiting())
00169 return;
00170 if (!image_.getWidth() || !image_.getHeight())
00171 throw std::runtime_error("failed to retrieve image");
00172
00173
00174 initializeVpCameraFromCameraInfo(cameraParameters_, info_);
00175 tracker_.setCameraParameters(cameraParameters_);
00176 }
00177
00178 void
00179 TrackerViewer::spin()
00180 {
00181 boost::format fmtWindowTitle ("ViSP MBT tracker viewer - [ns: %s]");
00182 fmtWindowTitle % ros::this_node::getNamespace ();
00183
00184 vpDisplayX d(image_,
00185 image_.getWidth(), image_.getHeight(),
00186 fmtWindowTitle.str().c_str());
00187 vpImagePoint point (10, 10);
00188 vpImagePoint pointTime (22, 10);
00189 vpImagePoint pointCameraTopic (34, 10);
00190 ros::Rate loop_rate(80);
00191
00192 boost::format fmt("tracking (x=%f y=%f z=%f)");
00193 boost::format fmtTime("time = %f");
00194
00195 boost::format fmtCameraTopic("camera topic = %s");
00196 fmtCameraTopic % rectifiedImageTopic_;
00197 while (!exiting())
00198 {
00199 vpDisplay::display(image_);
00200 displayMovingEdgeSites();
00201 displayKltPoints();
00202 if (cMo_)
00203 {
00204 try
00205 {
00206 tracker_.initFromPose(image_, *cMo_);
00207 tracker_.display(image_, *cMo_,
00208 cameraParameters_, vpColor::red);
00209 }
00210 catch(...)
00211 {
00212 ROS_DEBUG_STREAM_THROTTLE(10, "failed to display cmo");
00213 }
00214
00215 ROS_DEBUG_STREAM_THROTTLE(10, "cMo viewer:\n" << *cMo_);
00216
00217 fmt % (*cMo_)[0][3] % (*cMo_)[1][3] % (*cMo_)[2][3];
00218 vpDisplay::displayCharString
00219 (image_, point, fmt.str().c_str(), vpColor::red);
00220 fmtTime % info_->header.stamp.toSec();
00221 vpDisplay::displayCharString
00222 (image_, pointTime, fmtTime.str().c_str(), vpColor::red);
00223 vpDisplay::displayCharString
00224 (image_, pointCameraTopic, fmtCameraTopic.str().c_str(),
00225 vpColor::red);
00226 }
00227 else
00228 vpDisplay::displayCharString
00229 (image_, point, "tracking failed", vpColor::red);
00230 vpDisplay::flush(image_);
00231 ros::spinOnce();
00232 loop_rate.sleep();
00233 }
00234 }
00235
00236 void
00237 TrackerViewer::waitForImage()
00238 {
00239 ros::Rate loop_rate(10);
00240 while (!exiting()
00241 && (!image_.getWidth() || !image_.getHeight()))
00242 {
00243 ROS_INFO_THROTTLE(1, "waiting for a rectified image...");
00244 ros::spinOnce();
00245 loop_rate.sleep();
00246 }
00247 }
00248
00249 void
00250 TrackerViewer::checkInputs()
00251 {
00252 ros::V_string topics;
00253 topics.push_back(rectifiedImageTopic_);
00254 topics.push_back(cameraInfoTopic_);
00255 topics.push_back(visp_tracker::object_position_topic);
00256 topics.push_back(visp_tracker::moving_edge_sites_topic);
00257 topics.push_back(visp_tracker::klt_points_topic);
00258 checkInputs_.start(topics, 60.0);
00259 }
00260
00261 void
00262 TrackerViewer::initializeTracker()
00263 {
00264 try
00265 {
00266 ROS_DEBUG_STREAM("Trying to load the model " << vrmlPath_);
00267 tracker_.loadModel(vrmlPath_.external_file_string().c_str());
00268 }
00269 catch(...)
00270 {
00271 boost::format fmt("failed to load the model %1%");
00272 fmt % vrmlPath_;
00273 throw std::runtime_error(fmt.str());
00274 }
00275 ROS_INFO("Model has been successfully loaded.");
00276 }
00277
00278 void
00279 TrackerViewer::callback
00280 (const sensor_msgs::ImageConstPtr& image,
00281 const sensor_msgs::CameraInfoConstPtr& info,
00282 const geometry_msgs::PoseWithCovarianceStamped::ConstPtr& trackingResult,
00283 const visp_tracker::MovingEdgeSites::ConstPtr& sites,
00284 const visp_tracker::KltPoints::ConstPtr& klt)
00285 {
00286
00287 try
00288 {
00289 rosImageToVisp(image_, image);
00290 }
00291 catch(std::exception& e)
00292 {
00293 ROS_ERROR_STREAM("dropping frame: " << e.what());
00294 }
00295
00296
00297 info_ = info;
00298 sites_ = sites;
00299 klt_ = klt;
00300
00301
00302 cMo_ = vpHomogeneousMatrix();
00303 transformToVpHomogeneousMatrix(*cMo_, trackingResult->pose.pose);
00304 }
00305
00306 void
00307 TrackerViewer::displayMovingEdgeSites()
00308 {
00309 if (!sites_)
00310 return;
00311 for (unsigned i = 0; i < sites_->moving_edge_sites.size(); ++i)
00312 {
00313 double x = sites_->moving_edge_sites[i].x;
00314 double y = sites_->moving_edge_sites[i].y;
00315 int suppress = sites_->moving_edge_sites[i].suppress;
00316 vpColor color = vpColor::black;
00317
00318 switch(suppress)
00319 {
00320 case 0:
00321 color = vpColor::green;
00322 break;
00323 case 1:
00324 color = vpColor::blue;
00325 break;
00326 case 2:
00327 color = vpColor::purple;
00328 break;
00329 case 4:
00330 color = vpColor::red;
00331 break;
00332 default:
00333 ROS_ERROR_THROTTLE(10, "bad suppress value");
00334 }
00335
00336 vpDisplay::displayCross(image_, vpImagePoint(x, y), 3, color, 1);
00337 }
00338 }
00339
00340
00341 void
00342 TrackerViewer::displayKltPoints()
00343 {
00344 if (!klt_)
00345 return;
00346 vpImagePoint pos;
00347
00348 for (unsigned i = 0; i < klt_->klt_points_positions.size(); ++i)
00349 {
00350 double ii = klt_->klt_points_positions[i].i;
00351 double jj = klt_->klt_points_positions[i].j;
00352 int id = klt_->klt_points_positions[i].id;
00353 vpColor color = vpColor::red;
00354
00355 vpDisplay::displayCross(image_, vpImagePoint(ii, jj), 15, color, 1);
00356
00357 pos.set_i( vpMath::round( ii + 7 ) );
00358 pos.set_j( vpMath::round( jj + 7 ) );
00359 char ide[10];
00360 sprintf(ide, "%d", id);
00361 vpDisplay::displayCharString(image_, pos, ide, vpColor::red);
00362 }
00363 }
00364
00365 void
00366 TrackerViewer::timerCallback()
00367 {
00368 const unsigned threshold = 3 * countAll_;
00369
00370 if (countImages_ < threshold
00371 || countCameraInfo_ < threshold
00372 || countTrackingResult_ < threshold
00373 || countMovingEdgeSites_ < threshold
00374 || countKltPoints_ < threshold)
00375 {
00376 boost::format fmt
00377 ("[visp_tracker] Low number of synchronized tuples received.\n"
00378 "Images: %d\n"
00379 "Camera info: %d\n"
00380 "Tracking result: %d\n"
00381 "Moving edge sites: %d\n"
00382 "Synchronized tuples: %d\n"
00383 "Possible issues:\n"
00384 "\t* The network is too slow.");
00385 fmt % countImages_ % countCameraInfo_
00386 % countTrackingResult_ % countMovingEdgeSites_ % countAll_;
00387 ROS_WARN_STREAM_THROTTLE(10, fmt.str());
00388 }
00389 }
00390 }