00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <opencv/cv.h>
00036 #include <opencv/highgui.h>
00037
00038 #include <ros/ros.h>
00039 #include <sensor_msgs/Image.h>
00040 #include <cv_bridge/cv_bridge.h>
00041 #include <sensor_msgs/image_encodings.h>
00042 #include <image_transport/image_transport.h>
00043 #include <image_geometry/pinhole_camera_model.h>
00044 #include <tf/transform_listener.h>
00045
00046 #include <image_view2/ImageMarker2.h>
00047 #include <geometry_msgs/PointStamped.h>
00048 #include <geometry_msgs/PolygonStamped.h>
00049 #include <std_msgs/Empty.h>
00050
00051 #include <boost/thread.hpp>
00052 #include <boost/format.hpp>
00053 #include <boost/foreach.hpp>
00054
00055
00056 typedef std::vector<image_view2::ImageMarker2::ConstPtr> V_ImageMarkerMessage;
00057
00058 #define DEFAULT_COLOR CV_RGB(255,0,0)
00059 #define USER_ROI_COLOR CV_RGB(255,0,0)
00060 #define DEFAULT_CIRCLE_SCALE 20
00061 #define LINE_WIDTH 3
00062
00063 inline CvScalar MsgToRGB(const std_msgs::ColorRGBA &color){
00064 if(color.a == 0.0 && color.r == 0.0 && color.g == 0.0 && color.b == 0.0)
00065 return DEFAULT_COLOR;
00066 else
00067 return CV_RGB(color.r*255, color.g*255, color.b*255);
00068 }
00069
00070
00071 class ImageView2
00072 {
00073 private:
00074 image_transport::Subscriber image_sub_;
00075 ros::Subscriber info_sub_;
00076 ros::Subscriber marker_sub_;
00077 std::string marker_topic_;
00078
00079 image_transport::Publisher image_pub_;
00080
00081 V_ImageMarkerMessage marker_queue_;
00082 boost::mutex queue_mutex_;
00083
00084 sensor_msgs::ImageConstPtr last_msg_;
00085 sensor_msgs::CameraInfoConstPtr info_msg_;
00086 cv_bridge::CvImage img_bridge_;
00087 boost::mutex image_mutex_;
00088 cv::Mat image_, draw_;
00089
00090 tf::TransformListener tf_listener_;
00091 image_geometry::PinholeCameraModel cam_model_;
00092 std::vector<std::string> frame_ids_;
00093 boost::mutex info_mutex_;
00094
00095 std::string window_name_;
00096 boost::format filename_format_;
00097 int font_;
00098 static CvRect window_selection_;
00099 int count_;
00100 bool blurry_mode;
00101 bool use_window;
00102
00103 ros::Publisher point_pub_;
00104 ros::Publisher rectangle_pub_;
00105
00106 public:
00107 ImageView2() : marker_topic_("image_marker"), filename_format_(""), count_(0)
00108 {
00109 }
00110 ImageView2(ros::NodeHandle& nh, const std::string& transport)
00111 : marker_topic_("image_marker"), filename_format_(""), count_(0)
00112 {
00113 std::string camera = nh.resolveName("image");
00114 std::string camera_info = nh.resolveName("camera_info");
00115 ros::NodeHandle local_nh("~");
00116 bool autosize;
00117 std::string format_string;
00118 image_transport::ImageTransport it(nh);
00119
00120 point_pub_ = nh.advertise<geometry_msgs::PointStamped>(camera + "/screenpoint",100);
00121 rectangle_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/screenrectangle",100);
00122
00123 local_nh.param("window_name", window_name_, std::string("image_view2 [")+camera+std::string("]"));
00124
00125 local_nh.param("autosize", autosize, false);
00126
00127 local_nh.param("blurry", blurry_mode, false);
00128
00129 local_nh.param("filename_format", format_string, std::string("frame%04i.jpg"));
00130 local_nh.param("use_window", use_window, true);
00131
00132 filename_format_.parse(format_string);
00133
00134 if ( use_window ) {
00135 cvNamedWindow(window_name_.c_str(), autosize ? CV_WINDOW_AUTOSIZE : 0);
00136 cvSetMouseCallback(window_name_.c_str(), &ImageView2::mouse_cb, this);
00137 font_ = cv::FONT_HERSHEY_DUPLEX;
00138 window_selection_.x = window_selection_.y =
00139 window_selection_.height = window_selection_.width = 0;
00140 cvStartWindowThread();
00141 }
00142
00143 image_sub_ = it.subscribe(camera, 1, &ImageView2::image_cb, this, transport);
00144 info_sub_ = nh.subscribe(camera_info, 1, &ImageView2::info_cb, this);
00145 marker_sub_ = nh.subscribe(marker_topic_, 10, &ImageView2::marker_cb, this);
00146
00147 image_pub_ = it.advertise("image_marked", 1);
00148 }
00149
00150 ~ImageView2()
00151 {
00152 if ( use_window ) {
00153 cvDestroyWindow(window_name_.c_str());
00154 }
00155 }
00156
00157 void marker_cb(const image_view2::ImageMarker2ConstPtr& marker)
00158 {
00159 ROS_DEBUG("marker_cb");
00160
00161 if(marker->lifetime != ros::Duration(0))
00162 boost::const_pointer_cast<image_view2::ImageMarker2>(marker)->lifetime = (ros::Time::now() - ros::Time(0)) + marker->lifetime;
00163 boost::mutex::scoped_lock lock(queue_mutex_);
00164
00165 marker_queue_.push_back(marker);
00166
00167 }
00168
00169 void info_cb(const sensor_msgs::CameraInfoConstPtr& msg) {
00170 ROS_DEBUG("info_cb");
00171 boost::mutex::scoped_lock lock(info_mutex_);
00172 info_msg_ = msg;
00173 }
00174
00175 void image_cb(const sensor_msgs::ImageConstPtr& msg)
00176 {
00177 static ros::Time old_time;
00178 ROS_DEBUG("image_cb");
00179 if(old_time.toSec() - ros::Time::now().toSec() > 0) {
00180 ROS_WARN("TF Cleared for old time");
00181 }
00182
00183 if (msg->encoding.find("bayer") != std::string::npos) {
00184 image_ = cv::Mat(msg->height, msg->width, CV_8UC1,
00185 const_cast<uint8_t*>(&msg->data[0]), msg->step);
00186 } else {
00187 try {
00188 image_ = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8)->image;
00189 } catch (cv_bridge::Exception& e) {
00190 ROS_ERROR("Unable to convert %s image to bgr8", msg->encoding.c_str());
00191 return;
00192 }
00193 }
00194 boost::lock_guard<boost::mutex> guard(image_mutex_);
00195
00196 last_msg_ = msg;
00197
00198 static V_ImageMarkerMessage local_queue;
00199 {
00200 boost::mutex::scoped_lock lock(queue_mutex_);
00201
00202 while ( ! marker_queue_.empty() ) {
00203
00204 V_ImageMarkerMessage::iterator new_msg = marker_queue_.begin();
00205 V_ImageMarkerMessage::iterator message_it = local_queue.begin();
00206 for ( ; message_it < local_queue.end(); ++message_it ) {
00207 if((*new_msg)->ns == (*message_it)->ns && (*new_msg)->id == (*message_it)->id)
00208 message_it = local_queue.erase(message_it);
00209 }
00210 local_queue.push_back(*new_msg);
00211 marker_queue_.erase(new_msg);
00212
00213 if ( (*new_msg)->action == image_view2::ImageMarker2::REMOVE &&
00214 (*new_msg)->id == -1 ) {
00215 local_queue.clear();
00216 }
00217 }
00218 }
00219
00220
00221 for(V_ImageMarkerMessage::iterator it = local_queue.begin(); it < local_queue.end(); it++) {
00222 if((*it)->action == image_view2::ImageMarker2::REMOVE ||
00223 ((*it)->lifetime.toSec() != 0.0 && (*it)->lifetime.toSec() < ros::Time::now().toSec())) {
00224 it = local_queue.erase(it);
00225 }
00226 }
00227
00228
00229 if ( blurry_mode ) {
00230 draw_ = cv::Mat(image_.size(), image_.type(), CV_RGB(0,0,0));
00231 } else {
00232 draw_ = image_;
00233 }
00234 if ( !local_queue.empty() )
00235 {
00236 V_ImageMarkerMessage::iterator message_it = local_queue.begin();
00237 V_ImageMarkerMessage::iterator message_end = local_queue.end();
00238 ROS_DEBUG("markers = %ld", local_queue.size());
00239
00240 for ( ; message_it != message_end; ++message_it )
00241 {
00242 image_view2::ImageMarker2::ConstPtr& marker = *message_it;
00243
00244 ROS_DEBUG_STREAM("message type = " << marker->type << ", id " << marker->id);
00245
00246
00247 std::vector<CvScalar> colors;
00248 BOOST_FOREACH(std_msgs::ColorRGBA color, marker->outline_colors) {
00249 colors.push_back(MsgToRGB(color));
00250 }
00251 if(colors.size() == 0) colors.push_back(DEFAULT_COLOR);
00252 std::vector<CvScalar>::iterator col_it = colors.begin();
00253
00254
00255 if( marker->type == image_view2::ImageMarker2::FRAMES ||
00256 marker->type == image_view2::ImageMarker2::LINE_STRIP3D ||
00257 marker->type == image_view2::ImageMarker2::LINE_LIST3D ||
00258 marker->type == image_view2::ImageMarker2::POLYGON3D ||
00259 marker->type == image_view2::ImageMarker2::POINTS3D ||
00260 marker->type == image_view2::ImageMarker2::TEXT3D) {
00261 {
00262 boost::mutex::scoped_lock lock(info_mutex_);
00263 if (!info_msg_) {
00264 ROS_WARN("[image_view2] camera_info could not found");
00265 continue;
00266 }
00267 cam_model_.fromCameraInfo(info_msg_);
00268 }
00269 }
00270
00271 switch ( marker->type ) {
00272 case image_view2::ImageMarker2::CIRCLE: {
00273 cv::Point2d uv = cv::Point2d(marker->position.x, marker->position.y);
00274 if ( blurry_mode ) {
00275 int s0 = LINE_WIDTH;
00276 CvScalar co = MsgToRGB(marker->outline_color);
00277 for (int s1 = s0*10; s1 >= s0; s1--) {
00278 double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00279 cv::circle(draw_, uv,
00280 (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale),
00281 CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00282 s1);
00283 }
00284 } else {
00285 cv::circle(draw_, uv, (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale), MsgToRGB(marker->outline_color), LINE_WIDTH);
00286 }
00287 break;
00288 }
00289 case image_view2::ImageMarker2::LINE_STRIP: {
00290 cv::Point2d p0, p1;
00291 if ( blurry_mode ) {
00292 int s0 = LINE_WIDTH;
00293 std::vector<CvScalar>::iterator col_it = colors.begin();
00294 CvScalar co = (*col_it);
00295 for (int s1 = s0*10; s1 >= s0; s1--) {
00296 double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00297 std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00298 std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00299 p0 = cv::Point2d(it->x, it->y); it++;
00300 for ( ; it!= end; it++ ) {
00301 p1 = cv::Point2d(it->x, it->y);
00302 cv::line(draw_, p0, p1,
00303 CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00304 s1);
00305 p0 = p1;
00306 if(++col_it == colors.end()) col_it = colors.begin();
00307 }
00308 }
00309 } else {
00310 std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00311 std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00312 p0 = cv::Point2d(it->x, it->y); it++;
00313 for ( ; it!= end; it++ ) {
00314 p1 = cv::Point2d(it->x, it->y);
00315 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00316 p0 = p1;
00317 if(++col_it == colors.end()) col_it = colors.begin();
00318 }
00319 }
00320 break;
00321 }
00322 case image_view2::ImageMarker2::LINE_LIST: {
00323 cv::Point2d p0, p1;
00324 if ( blurry_mode ) {
00325 int s0 = LINE_WIDTH;
00326 std::vector<CvScalar>::iterator col_it = colors.begin();
00327 CvScalar co = (*col_it);
00328 for (int s1 = s0*10; s1 >= s0; s1--) {
00329 double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00330 std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00331 std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00332 for ( ; it!= end; ) {
00333 p0 = cv::Point2d(it->x, it->y); it++;
00334 if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00335 cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00336 it++;
00337 if(++col_it == colors.end()) col_it = colors.begin();
00338 }
00339 }
00340 } else {
00341 std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00342 std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00343 for ( ; it!= end; ) {
00344 p0 = cv::Point2d(it->x, it->y); it++;
00345 if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00346 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00347 it++;
00348 if(++col_it == colors.end()) col_it = colors.begin();
00349 }
00350 }
00351 break;
00352 }
00353 case image_view2::ImageMarker2::POLYGON: {
00354 cv::Point2d p0, p1;
00355 if ( blurry_mode ) {
00356 int s0 = LINE_WIDTH;
00357 std::vector<CvScalar>::iterator col_it = colors.begin();
00358 CvScalar co = (*col_it);
00359 for (int s1 = s0*10; s1 >= s0; s1--) {
00360 double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00361 std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00362 std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00363 p0 = cv::Point2d(it->x, it->y); it++;
00364 for ( ; it!= end; it++ ) {
00365 p1 = cv::Point2d(it->x, it->y);
00366 cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00367 p0 = p1;
00368 if(++col_it == colors.end()) col_it = colors.begin();
00369 }
00370 it = marker->points.begin();
00371 p1 = cv::Point2d(it->x, it->y);
00372 cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00373 }
00374 } else {
00375 std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00376 std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00377 p0 = cv::Point2d(it->x, it->y); it++;
00378 for ( ; it!= end; it++ ) {
00379 p1 = cv::Point2d(it->x, it->y);
00380 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00381 p0 = p1;
00382 if(++col_it == colors.end()) col_it = colors.begin();
00383 }
00384 it = marker->points.begin();
00385 p1 = cv::Point2d(it->x, it->y);
00386 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00387 }
00388 break;
00389 }
00390 case image_view2::ImageMarker2::POINTS: {
00391 BOOST_FOREACH(geometry_msgs::Point p, marker->points) {
00392 cv::Point2d uv = cv::Point2d(p.x, p.y);
00393 if ( blurry_mode ) {
00394 int s0 = (marker->scale == 0 ? 3 : marker->scale);
00395 CvScalar co = (*col_it);
00396 for (int s1 = s0*2; s1 >= s0; s1--) {
00397 double m = pow((1.0-((double)(s1 - s0))/s0),2);
00398 cv::circle(draw_, uv, s1,
00399 CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00400 -1);
00401 }
00402 } else {
00403 cv::circle(draw_, uv, (marker->scale == 0 ? 3 : marker->scale) , *col_it, -1);
00404 }
00405 if(++col_it == colors.end()) col_it = colors.begin();
00406 }
00407 break;
00408 }
00409 case image_view2::ImageMarker2::FRAMES: {
00410 static std::map<std::string, int> tf_fail;
00411 BOOST_FOREACH(std::string frame_id, marker->frames) {
00412 tf::StampedTransform transform;
00413 ros::Time acquisition_time = msg->header.stamp;
00414 ros::Duration timeout(1.0 / 2);
00415 try {
00416 ros::Time tm;
00417 tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00418 ros::Duration diff = ros::Time::now() - tm;
00419 if ( diff > ros::Duration(1.0) ) { break; }
00420
00421 tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00422 acquisition_time, timeout);
00423 tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00424 acquisition_time, transform);
00425 tf_fail[frame_id]=0;
00426 }
00427 catch (tf::TransformException& ex) {
00428 tf_fail[frame_id]++;
00429 if ( tf_fail[frame_id] < 5 ) {
00430 ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00431 } else {
00432 ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00433 }
00434 break;
00435 }
00436
00437 tf::Point pt = transform.getOrigin();
00438 cv::Point3d pt_cv(pt.x(), pt.y(), pt.z());
00439 cv::Point2d uv;
00440 uv = cam_model_.project3dToPixel(pt_cv);
00441
00442 static const int RADIUS = 3;
00443 cv::circle(draw_, uv, RADIUS, DEFAULT_COLOR, -1);
00444
00445
00446 cv::Point2d uv0, uv1, uv2;
00447 tf::Stamped<tf::Point> pin, pout;
00448
00449
00450 pin = tf::Stamped<tf::Point>(tf::Point(0.05, 0, 0), acquisition_time, frame_id);
00451 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00452 uv0 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00453
00454 pin = tf::Stamped<tf::Point>(tf::Point(0, 0.05, 0), acquisition_time, frame_id);
00455 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00456 uv1 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00457
00458
00459 pin = tf::Stamped<tf::Point>(tf::Point(0, 0, 0.05), acquisition_time, frame_id);
00460 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00461 uv2 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00462
00463
00464 if ( blurry_mode ) {
00465 int s0 = 2;
00466 CvScalar c0 = CV_RGB(255,0,0);
00467 CvScalar c1 = CV_RGB(0,255,0);
00468 CvScalar c2 = CV_RGB(0,0,255);
00469 for (int s1 = s0*10; s1 >= s0; s1--) {
00470 double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00471 cv::line(draw_, uv, uv0,
00472 CV_RGB(c0.val[2] * m,c0.val[1] * m,c0.val[0] * m),
00473 s1);
00474 cv::line(draw_, uv, uv1,
00475 CV_RGB(c1.val[2] * m,c1.val[1] * m,c1.val[0] * m),
00476 s1);
00477 cv::line(draw_, uv, uv2,
00478 CV_RGB(c2.val[2] * m,c2.val[1] * m,c2.val[0] * m),
00479 s1);
00480 }
00481 } else {
00482 cv::line(draw_, uv, uv0, CV_RGB(255,0,0), 2);
00483 cv::line(draw_, uv, uv1, CV_RGB(0,255,0), 2);
00484 cv::line(draw_, uv, uv2, CV_RGB(0,0,255), 2);
00485 }
00486
00487
00488 cv::Size text_size;
00489 int baseline;
00490 text_size = cv::getTextSize(frame_id.c_str(), font_, 1.0, 1.0, &baseline);
00491 cv::Point origin = cv::Point(uv.x - text_size.width / 2,
00492 uv.y - RADIUS - baseline - 3);
00493 cv::putText(draw_, frame_id.c_str(), origin, font_, 1.0, DEFAULT_COLOR, 1.5);
00494 }
00495 break;
00496 }
00497 case image_view2::ImageMarker2::TEXT: {
00498
00499 cv::Size text_size;
00500 int baseline;
00501 float scale = marker->scale;
00502 if ( scale == 0 ) scale = 1.0;
00503 text_size = cv::getTextSize(marker->text.c_str(), font_,
00504 scale, scale, &baseline);
00505 cv::Point origin = cv::Point(marker->position.x - text_size.width/2,
00506 marker->position.y - baseline-3);
00507 cv::putText(draw_, marker->text.c_str(), origin, font_, scale, DEFAULT_COLOR);
00508 break;
00509 }
00510
00511 case image_view2::ImageMarker2::LINE_STRIP3D: {
00512 static std::map<std::string, int> tf_fail;
00513 std::string frame_id = marker->points3D.header.frame_id;
00514 tf::StampedTransform transform;
00515 ros::Time acquisition_time = msg->header.stamp;
00516
00517 ros::Duration timeout(1.0 / 2);
00518 try {
00519 ros::Time tm;
00520 tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00521 ros::Duration diff = ros::Time::now() - tm;
00522 if ( diff > ros::Duration(1.0) ) { break; }
00523 tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00524 acquisition_time, timeout);
00525 tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00526 acquisition_time, transform);
00527 tf_fail[frame_id]=0;
00528 }
00529 catch (tf::TransformException& ex) {
00530 tf_fail[frame_id]++;
00531 if ( tf_fail[frame_id] < 5 ) {
00532 ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00533 } else {
00534 ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00535 }
00536 break;
00537 }
00538 std::vector<geometry_msgs::Point> points2D;
00539 BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00540 tf::Point pt = transform.getOrigin();
00541 geometry_msgs::PointStamped pt_cam, pt_;
00542 pt_cam.header.frame_id = cam_model_.tfFrame();
00543 pt_cam.header.stamp = acquisition_time;
00544 pt_cam.point.x = pt.x();
00545 pt_cam.point.y = pt.y();
00546 pt_cam.point.z = pt.z();
00547 tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00548
00549 cv::Point2d uv;
00550 tf::Stamped<tf::Point> pin, pout;
00551 pin = tf::Stamped<tf::Point>(tf::Point(pt_.point.x + p.x, pt_.point.y + p.y, pt_.point.z + p.z), acquisition_time, frame_id);
00552 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00553 uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00554 geometry_msgs::Point point2D;
00555 point2D.x = uv.x;
00556 point2D.y = uv.y;
00557 points2D.push_back(point2D);
00558 }
00559 cv::Point2d p0, p1;
00560 std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00561 std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00562 p0 = cv::Point2d(it->x, it->y); it++;
00563 for ( ; it!= end; it++ ) {
00564 p1 = cv::Point2d(it->x, it->y);
00565 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00566 p0 = p1;
00567 if(++col_it == colors.end()) col_it = colors.begin();
00568 }
00569 break;
00570 }
00571 case image_view2::ImageMarker2::LINE_LIST3D: {
00572 static std::map<std::string, int> tf_fail;
00573 std::string frame_id = marker->points3D.header.frame_id;
00574 tf::StampedTransform transform;
00575 ros::Time acquisition_time = msg->header.stamp;
00576
00577 ros::Duration timeout(1.0 / 2);
00578 try {
00579 ros::Time tm;
00580 tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00581 ros::Duration diff = ros::Time::now() - tm;
00582 if ( diff > ros::Duration(1.0) ) { break; }
00583 tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00584 acquisition_time, timeout);
00585 tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00586 acquisition_time, transform);
00587 tf_fail[frame_id]=0;
00588 }
00589 catch (tf::TransformException& ex) {
00590 tf_fail[frame_id]++;
00591 if ( tf_fail[frame_id] < 5 ) {
00592 ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00593 } else {
00594 ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00595 }
00596 break;
00597 }
00598 std::vector<geometry_msgs::Point> points2D;
00599 BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00600 tf::Point pt = transform.getOrigin();
00601 geometry_msgs::PointStamped pt_cam, pt_;
00602 pt_cam.header.frame_id = cam_model_.tfFrame();
00603 pt_cam.header.stamp = acquisition_time;
00604 pt_cam.point.x = pt.x();
00605 pt_cam.point.y = pt.y();
00606 pt_cam.point.z = pt.z();
00607 tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00608
00609 cv::Point2d uv;
00610 tf::Stamped<tf::Point> pin, pout;
00611 pin = tf::Stamped<tf::Point>(tf::Point(pt_.point.x + p.x, pt_.point.y + p.y, pt_.point.z + p.z), acquisition_time, frame_id);
00612 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00613 uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00614 geometry_msgs::Point point2D;
00615 point2D.x = uv.x;
00616 point2D.y = uv.y;
00617 points2D.push_back(point2D);
00618 }
00619 cv::Point2d p0, p1;
00620 std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00621 std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00622 for ( ; it!= end; ) {
00623 p0 = cv::Point2d(it->x, it->y); it++;
00624 if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00625 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00626 it++;
00627 if(++col_it == colors.end()) col_it = colors.begin();
00628 }
00629 break;
00630 }
00631 case image_view2::ImageMarker2::POLYGON3D: {
00632 static std::map<std::string, int> tf_fail;
00633 std::string frame_id = marker->points3D.header.frame_id;
00634 tf::StampedTransform transform;
00635 ros::Time acquisition_time = msg->header.stamp;
00636
00637 ros::Duration timeout(1.0 / 2);
00638 try {
00639 ros::Time tm;
00640 tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00641 ros::Duration diff = ros::Time::now() - tm;
00642 if ( diff > ros::Duration(1.0) ) { break; }
00643 tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00644 acquisition_time, timeout);
00645 tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00646 acquisition_time, transform);
00647 tf_fail[frame_id]=0;
00648 }
00649 catch (tf::TransformException& ex) {
00650 tf_fail[frame_id]++;
00651 if ( tf_fail[frame_id] < 5 ) {
00652 ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00653 } else {
00654 ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00655 }
00656 break;
00657 }
00658 std::vector<geometry_msgs::Point> points2D;
00659 BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00660 tf::Point pt = transform.getOrigin();
00661 geometry_msgs::PointStamped pt_cam, pt_;
00662 pt_cam.header.frame_id = cam_model_.tfFrame();
00663 pt_cam.header.stamp = acquisition_time;
00664 pt_cam.point.x = pt.x();
00665 pt_cam.point.y = pt.y();
00666 pt_cam.point.z = pt.z();
00667 tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00668
00669 cv::Point2d uv;
00670 tf::Stamped<tf::Point> pin, pout;
00671 pin = tf::Stamped<tf::Point>(tf::Point(pt_.point.x + p.x, pt_.point.y + p.y, pt_.point.z + p.z), acquisition_time, frame_id);
00672 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00673 uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00674 geometry_msgs::Point point2D;
00675 point2D.x = uv.x;
00676 point2D.y = uv.y;
00677 points2D.push_back(point2D);
00678 }
00679 cv::Point2d p0, p1;
00680 std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00681 std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00682 p0 = cv::Point2d(it->x, it->y); it++;
00683 for ( ; it!= end; it++ ) {
00684 p1 = cv::Point2d(it->x, it->y);
00685 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00686 p0 = p1;
00687 if(++col_it == colors.end()) col_it = colors.begin();
00688 }
00689 it = points2D.begin();
00690 p1 = cv::Point2d(it->x, it->y);
00691 cv::line(draw_, p0, p1, *col_it, LINE_WIDTH);
00692 break;
00693 }
00694 case image_view2::ImageMarker2::POINTS3D: {
00695 static std::map<std::string, int> tf_fail;
00696 std::string frame_id = marker->points3D.header.frame_id;
00697 tf::StampedTransform transform;
00698 ros::Time acquisition_time = msg->header.stamp;
00699
00700 ros::Duration timeout(1.0 / 2);
00701 try {
00702 ros::Time tm;
00703 tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00704 ros::Duration diff = ros::Time::now() - tm;
00705 if ( diff > ros::Duration(1.0) ) { break; }
00706 tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00707 acquisition_time, timeout);
00708 tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00709 acquisition_time, transform);
00710 tf_fail[frame_id]=0;
00711 }
00712 catch (tf::TransformException& ex) {
00713 tf_fail[frame_id]++;
00714 if ( tf_fail[frame_id] < 5 ) {
00715 ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00716 } else {
00717 ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00718 }
00719 break;
00720 }
00721 BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00722 tf::Point pt = transform.getOrigin();
00723 geometry_msgs::PointStamped pt_cam, pt_;
00724 pt_cam.header.frame_id = cam_model_.tfFrame();
00725 pt_cam.header.stamp = acquisition_time;
00726 pt_cam.point.x = pt.x();
00727 pt_cam.point.y = pt.y();
00728 pt_cam.point.z = pt.z();
00729 tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00730
00731 cv::Point2d uv;
00732 tf::Stamped<tf::Point> pin, pout;
00733 pin = tf::Stamped<tf::Point>(tf::Point(pt_.point.x + p.x, pt_.point.y + p.y, pt_.point.z + p.z), acquisition_time, frame_id);
00734 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00735 uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00736 cv::circle(draw_, uv, (marker->scale == 0 ? 3 : marker->scale) , *col_it, -1);
00737 }
00738 break;
00739 }
00740 case image_view2::ImageMarker2::TEXT3D: {
00741 static std::map<std::string, int> tf_fail;
00742 std::string frame_id = marker->position3D.header.frame_id;
00743 tf::StampedTransform transform;
00744 ros::Time acquisition_time = msg->header.stamp;
00745
00746 ros::Duration timeout(1.0 / 2);
00747 try {
00748 ros::Time tm;
00749 tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00750 ros::Duration diff = ros::Time::now() - tm;
00751 if ( diff > ros::Duration(1.0) ) { break; }
00752 tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00753 acquisition_time, timeout);
00754 tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00755 acquisition_time, transform);
00756 tf_fail[frame_id]=0;
00757 }
00758 catch (tf::TransformException& ex) {
00759 tf_fail[frame_id]++;
00760 if ( tf_fail[frame_id] < 5 ) {
00761 ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00762 } else {
00763 ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00764 }
00765 break;
00766 }
00767 tf::Point pt = transform.getOrigin();
00768 geometry_msgs::PointStamped pt_cam, pt_;
00769 pt_cam.header.frame_id = cam_model_.tfFrame();
00770 pt_cam.header.stamp = acquisition_time;
00771 pt_cam.point.x = pt.x();
00772 pt_cam.point.y = pt.y();
00773 pt_cam.point.z = pt.z();
00774 tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00775
00776 cv::Point2d uv;
00777 tf::Stamped<tf::Point> pin, pout;
00778 pin = tf::Stamped<tf::Point>(tf::Point(pt_.point.x + marker->position3D.point.x, pt_.point.y + marker->position3D.point.y, pt_.point.z + marker->position3D.point.z), acquisition_time, frame_id);
00779 tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00780 uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00781 cv::Size text_size;
00782 int baseline;
00783 float scale = marker->scale;
00784 if ( scale == 0 ) scale = 1.0;
00785 text_size = cv::getTextSize(marker->text.c_str(), font_,
00786 scale, scale, &baseline);
00787 cv::Point origin = cv::Point(uv.x - text_size.width/2,
00788 uv.y - baseline-3);
00789 cv::putText(draw_, marker->text.c_str(), origin, font_, scale, CV_RGB(0,255,0),3);
00790 break;
00791 }
00792 default: {
00793 ROS_WARN("Undefined Marker type(%d)", marker->type);
00794 break;
00795 }
00796 }
00797 }
00798 }
00799 cv::rectangle(draw_, cv::Point(window_selection_.x, window_selection_.y),
00800 cv::Point(window_selection_.x + window_selection_.width,
00801 window_selection_.y + window_selection_.height),
00802 USER_ROI_COLOR, 3, 8, 0);
00803
00804 if ( blurry_mode ) cv::addWeighted(image_, 0.9, draw_, 1.0, 0.0, image_);
00805 if ( use_window ) {
00806 cv::imshow(window_name_.c_str(), image_);
00807 }
00808 cv_bridge::CvImage out_msg;
00809 out_msg.header = msg->header;
00810 out_msg.encoding = "bgr8";
00811 out_msg.image = image_;
00812 image_pub_.publish(out_msg.toImageMsg());
00813 old_time = ros::Time::now();
00814 }
00815
00816 static void mouse_cb(int event, int x, int y, int flags, void* param)
00817 {
00818 ImageView2 *iv = (ImageView2*)param;
00819 static ros::Time left_buttondown_time(0);
00820 switch (event){
00821 case CV_EVENT_MOUSEMOVE:
00822 if ( ( left_buttondown_time.toSec() > 0 &&
00823 ros::Time::now().toSec() - left_buttondown_time.toSec() ) >= 1.0 ) {
00824 window_selection_.width = x - window_selection_.x;
00825 window_selection_.height = y - window_selection_.y;
00826 }
00827 break;
00828 case CV_EVENT_LBUTTONDOWN:
00829 left_buttondown_time = ros::Time::now();
00830 window_selection_.x = x;
00831 window_selection_.y = y;
00832 break;
00833 case CV_EVENT_LBUTTONUP:
00834 if ( ( ros::Time::now().toSec() - left_buttondown_time.toSec() ) < 1.0 ) {
00835 geometry_msgs::PointStamped screen_msg;
00836 screen_msg.point.x = window_selection_.x;
00837 screen_msg.point.y = window_selection_.y;
00838 screen_msg.point.z = 0;
00839 screen_msg.header.stamp = ros::Time::now();
00840 ROS_INFO("Publish screen point %s (%d %d)", iv->point_pub_.getTopic().c_str(), x, y);
00841 iv->point_pub_.publish(screen_msg);
00842 } else {
00843 geometry_msgs::PolygonStamped screen_msg;
00844 screen_msg.polygon.points.resize(2);
00845 screen_msg.polygon.points[0].x = window_selection_.x;
00846 screen_msg.polygon.points[0].y = window_selection_.y;
00847 screen_msg.polygon.points[1].x = window_selection_.x + window_selection_.width;
00848 screen_msg.polygon.points[1].y = window_selection_.y + window_selection_.height;
00849 screen_msg.header.stamp = ros::Time::now();
00850 ROS_INFO("Publish rectangle point %s (%d %d %d %d)", iv->rectangle_pub_.getTopic().c_str(), window_selection_.y, window_selection_.y, window_selection_.width, window_selection_.height);
00851 iv->rectangle_pub_.publish(screen_msg);
00852 }
00853 window_selection_.x = window_selection_.y =
00854 window_selection_.width = window_selection_.height = 0;
00855 left_buttondown_time.fromSec(0);
00856 break;
00857 case CV_EVENT_RBUTTONDOWN:
00858 boost::lock_guard<boost::mutex> guard(iv->image_mutex_);
00859 if (!iv->image_.empty()) {
00860 std::string filename = (iv->filename_format_ % iv->count_).str();
00861 cv::imwrite(filename.c_str(), iv->image_);
00862 ROS_INFO("Saved image %s", filename.c_str());
00863 iv->count_++;
00864 } else {
00865 ROS_WARN("Couldn't save image, no data!");
00866 }
00867 break;
00868 }
00869 return;
00870 }
00871 };
00872
00873 int main(int argc, char **argv)
00874 {
00875
00876 ros::init(argc, argv, "image_view2");
00877 ros::NodeHandle n;
00878
00879 if ( n.resolveName("image") == "/image") {
00880 ROS_WARN("image_view: image has not been remapped! Typical command-line usage:\n"
00881 "\t$ ./image_view image:=<image topic> [transport]");
00882 }
00883
00884 ImageView2 view(n, "raw");
00885
00886 ros::spin();
00887
00888 return 0;
00889 }
00890
00891 CvRect ImageView2::window_selection_;