image_view2.cpp
Go to the documentation of this file.
00001 // -*- tab-width: 8; indent-tabs-mode: nil; -*-
00002 /*********************************************************************
00003  * Software License Agreement (BSD License)
00004  *
00005  *  Copyright (c) 2008, Willow Garage, Inc.
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 Willow Garage 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 "image_view2.h"
00037 
00038 namespace image_view2{
00039   ImageView2::ImageView2() : marker_topic_("image_marker"), filename_format_(""), count_(0), mode_(MODE_RECTANGLE), times_(100), window_initialized_(false)
00040   {
00041   }
00042   
00043   ImageView2::ImageView2(ros::NodeHandle& nh)
00044     : marker_topic_("image_marker"), filename_format_(""), count_(0), mode_(MODE_RECTANGLE), times_(100), selecting_fg_(true),
00045       left_button_clicked_(false), continuous_ready_(false), window_initialized_(false)
00046   {
00047     std::string camera = nh.resolveName("image");
00048     std::string camera_info = nh.resolveName("camera_info");
00049     ros::NodeHandle local_nh("~");
00050     std::string format_string;
00051     std::string transport;
00052     image_transport::ImageTransport it(nh);
00053 
00054     point_pub_ = nh.advertise<geometry_msgs::PointStamped>(camera + "/screenpoint",100);
00055     point_array_pub_ = nh.advertise<sensor_msgs::PointCloud2>(camera + "/screenpoint_array",100);
00056     rectangle_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/screenrectangle",100);
00057     move_point_pub_ = nh.advertise<geometry_msgs::PointStamped>(camera + "/movepoint", 100);
00058     foreground_mask_pub_ = nh.advertise<sensor_msgs::Image>(camera + "/foreground", 100);
00059     background_mask_pub_ = nh.advertise<sensor_msgs::Image>(camera + "/background", 100);
00060     local_nh.param("window_name", window_name_, std::string("image_view2 [")+camera+std::string("]"));
00061     local_nh.param("skip_draw_rate", skip_draw_rate_, 0);
00062     local_nh.param("autosize", autosize_, false);
00063     local_nh.param("image_transport", transport, std::string("raw"));
00064     local_nh.param("blurry", blurry_mode_, false);
00065     local_nh.param("region_continuous_publish", region_continuous_publish_, false);
00066     local_nh.param("filename_format", format_string, std::string("frame%04i.jpg"));
00067     local_nh.param("use_window", use_window, true);
00068     local_nh.param("show_info", show_info_, false);
00069 
00070     double xx,yy;
00071     local_nh.param("resize_scale_x", xx, 1.0);
00072     local_nh.param("resize_scale_y", yy, 1.0);
00073     local_nh.param("tf_timeout", tf_timeout_, 1.0);
00074     
00075     std::string interaction_mode;
00076     local_nh.param("interaction_mode", interaction_mode, std::string("rectangle"));
00077     if (interaction_mode == "rectangle") {
00078       setMode(image_view2::ImageView2::MODE_RECTANGLE);
00079     }
00080     else if (interaction_mode == "freeform" ||
00081              interaction_mode == "series") {
00082       setMode(image_view2::ImageView2::MODE_SERIES);
00083     }
00084     else if (interaction_mode == "grabcut") {
00085       setMode(image_view2::ImageView2::MODE_SELECT_FORE_AND_BACK);
00086     }
00087     else if (interaction_mode == "grabcut_rect") {
00088       setMode(image_view2::ImageView2::MODE_SELECT_FORE_AND_BACK_RECT);
00089     }
00090     
00091     resize_x_ = 1.0/xx;
00092     resize_y_ = 1.0/yy;
00093     filename_format_.parse(format_string);
00094 
00095     if ( use_window ) {
00096       font_ = cv::FONT_HERSHEY_DUPLEX;
00097       window_selection_.x = window_selection_.y =
00098         window_selection_.height = window_selection_.width = 0;
00099     }
00100 
00101     image_sub_ = it.subscribe(camera, 1, &ImageView2::imageCb, this, transport);
00102     info_sub_ = nh.subscribe(camera_info, 1, &ImageView2::infoCb, this);
00103     marker_sub_ = nh.subscribe(marker_topic_, 10, &ImageView2::markerCb, this);
00104 
00105     image_pub_ = it.advertise("image_marked", 1);
00106   }
00107 
00108   ImageView2::~ImageView2()
00109   {
00110     if ( use_window ) {
00111       cv::destroyWindow(window_name_.c_str());
00112     }
00113   }
00114 
00115   void ImageView2::markerCb(const image_view2::ImageMarker2ConstPtr& marker)
00116   {
00117     ROS_DEBUG("markerCb");
00118     // convert lifetime to duration from Time(0)
00119     if(marker->lifetime != ros::Duration(0))
00120       boost::const_pointer_cast<image_view2::ImageMarker2>(marker)->lifetime = (ros::Time::now() - ros::Time(0)) + marker->lifetime;
00121     {
00122       boost::mutex::scoped_lock lock(queue_mutex_);
00123       marker_queue_.push_back(marker);
00124     }
00125     redraw();
00126   }
00127 
00128   void ImageView2::infoCb(const sensor_msgs::CameraInfoConstPtr& msg) {
00129     ROS_DEBUG("infoCb");
00130     boost::mutex::scoped_lock lock(info_mutex_);
00131     info_msg_ = msg;
00132   }
00133 
00134   bool ImageView2::lookupTransformation(
00135     std::string frame_id, ros::Time& acquisition_time,
00136     std::map<std::string, int>& tf_fail,
00137     tf::StampedTransform &transform)
00138   {
00139     ros::Duration timeout(tf_timeout_); // wait 0.5 sec
00140     try {
00141       ros::Time tm;
00142       tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00143       tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00144                                     acquisition_time, timeout);
00145       tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00146                                    acquisition_time, transform);
00147       tf_fail[frame_id]=0;
00148       return true;
00149     }
00150     catch (tf::TransformException& ex) {
00151       tf_fail[frame_id]++;
00152       if ( tf_fail[frame_id] < 5 ) {
00153         ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00154       } else {
00155         ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00156       }
00157       return false;
00158     }
00159   }
00160   
00161   void ImageView2::drawCircle(const image_view2::ImageMarker2::ConstPtr& marker)
00162   {
00163     cv::Point2d uv = cv::Point2d(marker->position.x, marker->position.y);
00164     if ( blurry_mode_ ) {
00165       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00166       CvScalar co = MsgToRGB(marker->outline_color);
00167       for (int s1 = s0*10; s1 >= s0; s1--) {
00168         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00169         cv::circle(draw_, uv,
00170                    (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale),
00171                    CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00172                    s1);
00173       }
00174     } else {
00175       cv::circle(draw_, uv,
00176                  (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale),
00177                  MsgToRGB(marker->outline_color),
00178                  (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00179       if (marker->filled) {
00180         cv::circle(draw_, uv,
00181                    (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale) - (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width) / 2.0,
00182                    MsgToRGB(marker->fill_color),
00183                    -1);
00184       }
00185     }
00186   }
00187 
00188   void ImageView2::drawLineStrip(const image_view2::ImageMarker2::ConstPtr& marker,
00189                                  std::vector<CvScalar>& colors,
00190                                  std::vector<CvScalar>::iterator& col_it)
00191   {
00192     cv::Point2d p0, p1;
00193     if ( blurry_mode_ ) {
00194       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00195       std::vector<CvScalar>::iterator col_it = colors.begin();
00196       CvScalar co = (*col_it);
00197       for (int s1 = s0*10; s1 >= s0; s1--) {
00198         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00199         std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00200         std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00201         p0 = cv::Point2d(it->x, it->y); it++;
00202         for ( ; it!= end; it++ ) {
00203           p1 = cv::Point2d(it->x, it->y);
00204           cv::line(draw_, p0, p1,
00205                    CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00206                    s1);
00207           p0 = p1;
00208           if(++col_it == colors.end()) col_it = colors.begin();
00209         }
00210       }
00211     } else {
00212       std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00213       std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00214       p0 = cv::Point2d(it->x, it->y); it++;
00215       for ( ; it!= end; it++ ) {
00216         p1 = cv::Point2d(it->x, it->y);
00217         cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00218         p0 = p1;
00219         if(++col_it == colors.end()) col_it = colors.begin();
00220       }
00221     }
00222   }
00223 
00224   void ImageView2::drawLineList(const image_view2::ImageMarker2::ConstPtr& marker,
00225                                 std::vector<CvScalar>& colors,
00226                                 std::vector<CvScalar>::iterator& col_it)
00227   {
00228     cv::Point2d p0, p1;
00229     if ( blurry_mode_ ) {
00230       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00231       std::vector<CvScalar>::iterator col_it = colors.begin();
00232       CvScalar co = (*col_it);
00233       for (int s1 = s0*10; s1 >= s0; s1--) {
00234         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00235         std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00236         std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00237         for ( ; it!= end; ) {
00238           p0 = cv::Point2d(it->x, it->y); it++;
00239           if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00240           cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00241           it++;
00242           if(++col_it == colors.end()) col_it = colors.begin();
00243         }
00244       }
00245     } else {
00246       std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00247       std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00248       for ( ; it!= end; ) {
00249         p0 = cv::Point2d(it->x, it->y); it++;
00250         if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00251         cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00252         it++;
00253         if(++col_it == colors.end()) col_it = colors.begin();
00254       }
00255     }
00256   }
00257 
00258   void ImageView2::drawPolygon(const image_view2::ImageMarker2::ConstPtr& marker,
00259                                std::vector<CvScalar>& colors,
00260                                std::vector<CvScalar>::iterator& col_it)
00261   {
00262     cv::Point2d p0, p1;
00263     if ( blurry_mode_ ) {
00264       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00265       std::vector<CvScalar>::iterator col_it = colors.begin();
00266       CvScalar co = (*col_it);
00267       for (int s1 = s0*10; s1 >= s0; s1--) {
00268         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00269         std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00270         std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00271         p0 = cv::Point2d(it->x, it->y); it++;
00272         for ( ; it!= end; it++ ) {
00273           p1 = cv::Point2d(it->x, it->y);
00274           cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00275           p0 = p1;
00276           if(++col_it == colors.end()) col_it = colors.begin();
00277         }
00278         it = marker->points.begin();
00279         p1 = cv::Point2d(it->x, it->y);
00280         cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00281       }
00282     } else {
00283       std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00284       std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00285       std::vector<cv::Point> points;
00286 
00287       if (marker->filled) {
00288         points.push_back(cv::Point(it->x, it->y));
00289       }
00290       p0 = cv::Point2d(it->x, it->y); it++;
00291       for ( ; it!= end; it++ ) {
00292         p1 = cv::Point2d(it->x, it->y);
00293         if (marker->filled) {
00294           points.push_back(cv::Point(it->x, it->y));
00295         }
00296         cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00297         p0 = p1;
00298         if(++col_it == colors.end()) col_it = colors.begin();
00299       }
00300       it = marker->points.begin();
00301       p1 = cv::Point2d(it->x, it->y);
00302       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00303       if (marker->filled) {
00304         cv::fillConvexPoly(draw_, points.data(), points.size(), MsgToRGB(marker->fill_color));
00305       }
00306     }
00307   }
00308 
00309   void ImageView2::drawPoints(const image_view2::ImageMarker2::ConstPtr& marker,
00310                               std::vector<CvScalar>& colors,
00311                               std::vector<CvScalar>::iterator& col_it)
00312   {
00313     BOOST_FOREACH(geometry_msgs::Point p, marker->points) {
00314       cv::Point2d uv = cv::Point2d(p.x, p.y);
00315       if ( blurry_mode_ ) {
00316         int s0 = (marker->scale == 0 ? 3 : marker->scale);
00317         CvScalar co = (*col_it);
00318         for (int s1 = s0*2; s1 >= s0; s1--) {
00319           double m = pow((1.0-((double)(s1 - s0))/s0),2);
00320           cv::circle(draw_, uv, s1,
00321                      CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00322                      -1);
00323         }
00324       } else {
00325         cv::circle(draw_, uv, (marker->scale == 0 ? 3 : marker->scale) , *col_it, -1);
00326       }
00327       if(++col_it == colors.end()) col_it = colors.begin();
00328     }
00329   }
00330 
00331   void ImageView2::drawFrames(const image_view2::ImageMarker2::ConstPtr& marker,
00332                               std::vector<CvScalar>& colors,
00333                               std::vector<CvScalar>::iterator& col_it)
00334   {
00335     static std::map<std::string, int> tf_fail;
00336     BOOST_FOREACH(std::string frame_id, marker->frames) {
00337       tf::StampedTransform transform;
00338       ros::Time acquisition_time = last_msg_->header.stamp;
00339       if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00340         return;
00341       }
00342       // center point
00343       tf::Point pt = transform.getOrigin();
00344       cv::Point3d pt_cv(pt.x(), pt.y(), pt.z());
00345       cv::Point2d uv;
00346       uv = cam_model_.project3dToPixel(pt_cv);
00347 
00348       static const int RADIUS = 3;
00349       cv::circle(draw_, uv, RADIUS, DEFAULT_COLOR, -1);
00350 
00351       // x, y, z
00352       cv::Point2d uv0, uv1, uv2;
00353       tf::Stamped<tf::Point> pin, pout;
00354 
00355       // x
00356       pin = tf::Stamped<tf::Point>(tf::Point(0.05, 0, 0), acquisition_time, frame_id);
00357       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00358       uv0 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00359       // y
00360       pin = tf::Stamped<tf::Point>(tf::Point(0, 0.05, 0), acquisition_time, frame_id);
00361       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00362       uv1 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00363 
00364       // z
00365       pin = tf::Stamped<tf::Point>(tf::Point(0, 0, 0.05), acquisition_time, frame_id);
00366       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00367       uv2 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00368 
00369       // draw
00370       if ( blurry_mode_ ) {
00371         int s0 = 2;
00372         CvScalar c0 = CV_RGB(255,0,0);
00373         CvScalar c1 = CV_RGB(0,255,0);
00374         CvScalar c2 = CV_RGB(0,0,255);
00375         for (int s1 = s0*10; s1 >= s0; s1--) {
00376           double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00377           cv::line(draw_, uv, uv0,
00378                    CV_RGB(c0.val[2] * m,c0.val[1] * m,c0.val[0] * m),
00379                    s1);
00380           cv::line(draw_, uv, uv1,
00381                    CV_RGB(c1.val[2] * m,c1.val[1] * m,c1.val[0] * m),
00382                    s1);
00383           cv::line(draw_, uv, uv2,
00384                    CV_RGB(c2.val[2] * m,c2.val[1] * m,c2.val[0] * m),
00385                    s1);
00386         }
00387       } else {
00388         cv::line(draw_, uv, uv0, CV_RGB(255,0,0), 2);
00389         cv::line(draw_, uv, uv1, CV_RGB(0,255,0), 2);
00390         cv::line(draw_, uv, uv2, CV_RGB(0,0,255), 2);
00391       }
00392 
00393       // index
00394       cv::Size text_size;
00395       int baseline;
00396       text_size = cv::getTextSize(frame_id.c_str(), font_, 1.0, 1.0, &baseline);
00397       cv::Point origin = cv::Point(uv.x - text_size.width / 2,
00398                                    uv.y - RADIUS - baseline - 3);
00399       cv::putText(draw_, frame_id.c_str(), origin, font_, 1.0, DEFAULT_COLOR, 1.5);
00400     }
00401   }
00402   
00403   void ImageView2::drawText(const image_view2::ImageMarker2::ConstPtr& marker,
00404                             std::vector<CvScalar>& colors,
00405                             std::vector<CvScalar>::iterator& col_it)
00406   {
00407     cv::Size text_size;
00408     int baseline;
00409     float scale = marker->scale;
00410     if ( scale == 0 ) scale = 1.0;
00411     text_size = cv::getTextSize(marker->text.c_str(), font_,
00412                                 scale, scale, &baseline);
00413     cv::Point origin = cv::Point(marker->position.x - text_size.width/2,
00414                                  marker->position.y - baseline-3);
00415     cv::putText(draw_, marker->text.c_str(), origin, font_, scale, DEFAULT_COLOR);
00416   }
00417 
00418   void ImageView2::drawLineStrip3D(const image_view2::ImageMarker2::ConstPtr& marker,
00419                                    std::vector<CvScalar>& colors,
00420                                    std::vector<CvScalar>::iterator& col_it)
00421   {
00422     static std::map<std::string, int> tf_fail;
00423     std::string frame_id = marker->points3D.header.frame_id;
00424     tf::StampedTransform transform;
00425     ros::Time acquisition_time = last_msg_->header.stamp;
00426     //ros::Time acquisition_time = msg->points3D.header.stamp;
00427     ros::Duration timeout(tf_timeout_); // wait 0.5 sec
00428     try {
00429       ros::Time tm;
00430       tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00431       ros::Duration diff = ros::Time::now() - tm;
00432       if ( diff > ros::Duration(1.0) ) { return; }
00433       tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00434                                     acquisition_time, timeout);
00435       tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00436                                    acquisition_time, transform);
00437       tf_fail[frame_id]=0;
00438     }
00439     catch (tf::TransformException& ex) {
00440       tf_fail[frame_id]++;
00441       if ( tf_fail[frame_id] < 5 ) {
00442         ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00443       } else {
00444         ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00445       }
00446       return;
00447     }
00448     std::vector<geometry_msgs::Point> points2D;
00449     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00450       tf::Point pt = transform.getOrigin();
00451       geometry_msgs::PointStamped pt_cam, pt_;
00452       pt_cam.header.frame_id = cam_model_.tfFrame();
00453       pt_cam.header.stamp = acquisition_time;
00454       pt_cam.point.x = pt.x();
00455       pt_cam.point.y = pt.y();
00456       pt_cam.point.z = pt.z();
00457       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00458 
00459       cv::Point2d uv;
00460       tf::Stamped<tf::Point> pin, pout;
00461       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);
00462       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00463       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00464       geometry_msgs::Point point2D;
00465       point2D.x = uv.x;
00466       point2D.y = uv.y;
00467       points2D.push_back(point2D);
00468     }
00469     cv::Point2d p0, p1;
00470     std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00471     std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00472     p0 = cv::Point2d(it->x, it->y); it++;
00473     for ( ; it!= end; it++ ) {
00474       p1 = cv::Point2d(it->x, it->y);
00475       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00476       p0 = p1;
00477       if(++col_it == colors.end()) col_it = colors.begin();
00478     }
00479   }
00480 
00481   void ImageView2::drawLineList3D(const image_view2::ImageMarker2::ConstPtr& marker,
00482                                   std::vector<CvScalar>& colors,
00483                                   std::vector<CvScalar>::iterator& col_it)
00484   {
00485     static std::map<std::string, int> tf_fail;
00486     std::string frame_id = marker->points3D.header.frame_id;
00487     tf::StampedTransform transform;
00488     ros::Time acquisition_time = last_msg_->header.stamp;
00489     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00490       return;
00491     }
00492     std::vector<geometry_msgs::Point> points2D;
00493     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00494       tf::Point pt = transform.getOrigin();
00495       geometry_msgs::PointStamped pt_cam, pt_;
00496       pt_cam.header.frame_id = cam_model_.tfFrame();
00497       pt_cam.header.stamp = acquisition_time;
00498       pt_cam.point.x = pt.x();
00499       pt_cam.point.y = pt.y();
00500       pt_cam.point.z = pt.z();
00501       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00502 
00503       cv::Point2d uv;
00504       tf::Stamped<tf::Point> pin, pout;
00505       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);
00506       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00507       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00508       geometry_msgs::Point point2D;
00509       point2D.x = uv.x;
00510       point2D.y = uv.y;
00511       points2D.push_back(point2D);
00512     }
00513     cv::Point2d p0, p1;
00514     std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00515     std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00516     for ( ; it!= end; ) {
00517       p0 = cv::Point2d(it->x, it->y); it++;
00518       if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00519       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00520       it++;
00521       if(++col_it == colors.end()) col_it = colors.begin();
00522     }
00523   }
00524   
00525   void ImageView2::drawPolygon3D(const image_view2::ImageMarker2::ConstPtr& marker,
00526                                  std::vector<CvScalar>& colors,
00527                                  std::vector<CvScalar>::iterator& col_it)
00528   {
00529     static std::map<std::string, int> tf_fail;
00530     std::string frame_id = marker->points3D.header.frame_id;
00531     tf::StampedTransform transform;
00532     ros::Time acquisition_time = last_msg_->header.stamp;
00533     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00534       return;
00535     }
00536     std::vector<geometry_msgs::Point> points2D;
00537     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00538       tf::Point pt = transform.getOrigin();
00539       geometry_msgs::PointStamped pt_cam, pt_;
00540       pt_cam.header.frame_id = cam_model_.tfFrame();
00541       pt_cam.header.stamp = acquisition_time;
00542       pt_cam.point.x = pt.x();
00543       pt_cam.point.y = pt.y();
00544       pt_cam.point.z = pt.z();
00545       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00546 
00547       cv::Point2d uv;
00548       tf::Stamped<tf::Point> pin, pout;
00549       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);
00550       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00551       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00552       geometry_msgs::Point point2D;
00553       point2D.x = uv.x;
00554       point2D.y = uv.y;
00555       points2D.push_back(point2D);
00556     }
00557     cv::Point2d p0, p1;
00558     std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00559     std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00560     std::vector<cv::Point> points;
00561 
00562     if (marker->filled) {
00563       points.push_back(cv::Point(it->x, it->y));
00564     }
00565     p0 = cv::Point2d(it->x, it->y); it++;
00566     for ( ; it!= end; it++ ) {
00567       p1 = cv::Point2d(it->x, it->y);
00568       if (marker->filled) {
00569         points.push_back(cv::Point(it->x, it->y));
00570       }
00571       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00572       p0 = p1;
00573       if(++col_it == colors.end()) col_it = colors.begin();
00574     }
00575     it = points2D.begin();
00576     p1 = cv::Point2d(it->x, it->y);
00577     cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00578     if (marker->filled) {
00579       cv::fillConvexPoly(draw_, points.data(), points.size(), MsgToRGB(marker->fill_color));
00580     }
00581   }
00582 
00583   void ImageView2::drawPoints3D(const image_view2::ImageMarker2::ConstPtr& marker,
00584                                 std::vector<CvScalar>& colors,
00585                                 std::vector<CvScalar>::iterator& col_it)
00586   {
00587     static std::map<std::string, int> tf_fail;
00588     std::string frame_id = marker->points3D.header.frame_id;
00589     tf::StampedTransform transform;
00590     ros::Time acquisition_time = last_msg_->header.stamp;
00591     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00592       return;
00593     }
00594     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00595       tf::Point pt = transform.getOrigin();
00596       geometry_msgs::PointStamped pt_cam, pt_;
00597       pt_cam.header.frame_id = cam_model_.tfFrame();
00598       pt_cam.header.stamp = acquisition_time;
00599       pt_cam.point.x = pt.x();
00600       pt_cam.point.y = pt.y();
00601       pt_cam.point.z = pt.z();
00602       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00603 
00604       cv::Point2d uv;
00605       tf::Stamped<tf::Point> pin, pout;
00606       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);
00607       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00608       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00609       cv::circle(draw_, uv, (marker->scale == 0 ? 3 : marker->scale) , *col_it, -1);
00610     }
00611   }
00612 
00613   void ImageView2::drawText3D(const image_view2::ImageMarker2::ConstPtr& marker,
00614                               std::vector<CvScalar>& colors,
00615                               std::vector<CvScalar>::iterator& col_it)
00616   {
00617     static std::map<std::string, int> tf_fail;
00618     std::string frame_id = marker->position3D.header.frame_id;
00619     tf::StampedTransform transform;
00620     ros::Time acquisition_time = last_msg_->header.stamp;
00621     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00622       return;
00623     }
00624     tf::Point pt = transform.getOrigin();
00625     geometry_msgs::PointStamped pt_cam, pt_;
00626     pt_cam.header.frame_id = cam_model_.tfFrame();
00627     pt_cam.header.stamp = acquisition_time;
00628     pt_cam.point.x = pt.x();
00629     pt_cam.point.y = pt.y();
00630     pt_cam.point.z = pt.z();
00631     tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00632 
00633     cv::Point2d uv;
00634     tf::Stamped<tf::Point> pin, pout;
00635     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);
00636     tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00637     uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00638     cv::Size text_size;
00639     int baseline;
00640     float scale = marker->scale;
00641     if ( scale == 0 ) scale = 1.0;
00642     text_size = cv::getTextSize(marker->text.c_str(), font_,
00643                                 scale, scale, &baseline);
00644     cv::Point origin = cv::Point(uv.x - text_size.width/2,
00645                                  uv.y - baseline-3);
00646     cv::putText(draw_, marker->text.c_str(), origin, font_, scale, CV_RGB(0,255,0),3);
00647   }
00648 
00649   void ImageView2::drawCircle3D(const image_view2::ImageMarker2::ConstPtr& marker,
00650                                 std::vector<CvScalar>& colors,
00651                                 std::vector<CvScalar>::iterator& col_it)
00652   {
00653     static std::map<std::string, int> tf_fail;
00654     std::string frame_id = marker->pose.header.frame_id;
00655     geometry_msgs::PoseStamped pose;
00656     ros::Time acquisition_time = last_msg_->header.stamp;
00657     ros::Duration timeout(tf_timeout_); // wait 0.5 sec
00658     try {
00659       ros::Time tm;
00660       tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00661       tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00662                                     acquisition_time, timeout);
00663       tf_listener_.transformPose(cam_model_.tfFrame(),
00664                                  acquisition_time, marker->pose, frame_id, pose);
00665       tf_fail[frame_id]=0;
00666     }
00667     catch (tf::TransformException& ex) {
00668       tf_fail[frame_id]++;
00669       if ( tf_fail[frame_id] < 5 ) {
00670         ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00671       } else {
00672         ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00673       }
00674       return;
00675     }
00676 
00677     tf::Quaternion q;
00678     tf::quaternionMsgToTF(pose.pose.orientation, q);
00679     tf::Matrix3x3 rot = tf::Matrix3x3(q);
00680     double angle = (marker->arc == 0 ? 360.0 :marker->angle);
00681     double scale = (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale);
00682     int N = 100;
00683     std::vector< std::vector<cv::Point2i> > ptss;
00684     std::vector<cv::Point2i> pts;
00685 
00686     for (int i=0; i<N; ++i) {
00687       double th = angle * i / N * TFSIMD_RADS_PER_DEG;
00688       tf::Vector3 v = rot * tf::Vector3(scale * tfCos(th), scale * tfSin(th),0);
00689       cv::Point2d pt = cam_model_.project3dToPixel(cv::Point3d(pose.pose.position.x + v.getX(), pose.pose.position.y + v.getY(), pose.pose.position.z + v.getZ()));
00690       pts.push_back(cv::Point2i((int)pt.x, (int)pt.y));
00691     }
00692     ptss.push_back(pts);
00693 
00694     cv::polylines(draw_, ptss, (marker->arc == 0 ? true : false), MsgToRGB(marker->outline_color), (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00695 
00696     if (marker->filled) {
00697       if(marker->arc != 0){
00698         cv::Point2d pt = cam_model_.project3dToPixel(cv::Point3d(pose.pose.position.x, pose.pose.position.y, pose.pose.position.z));
00699         pts.push_back(cv::Point2i((int)pt.x, (int)pt.y));
00700         ptss.clear();
00701         ptss.push_back(pts);
00702       }
00703       cv::fillPoly(draw_, ptss, MsgToRGB(marker->fill_color));
00704     }
00705   }
00706 
00707   void ImageView2::resolveLocalMarkerQueue()
00708   {
00709     {
00710       boost::mutex::scoped_lock lock(queue_mutex_);
00711 
00712       while ( ! marker_queue_.empty() ) {
00713         // remove marker by namespace and id
00714         V_ImageMarkerMessage::iterator new_msg = marker_queue_.begin();
00715         V_ImageMarkerMessage::iterator message_it = local_queue_.begin();
00716         for ( ; message_it < local_queue_.end(); ++message_it ) {
00717           if((*new_msg)->ns == (*message_it)->ns && (*new_msg)->id == (*message_it)->id)
00718             message_it = local_queue_.erase(message_it);
00719         }
00720         local_queue_.push_back(*new_msg);
00721         marker_queue_.erase(new_msg);
00722         // if action == REMOVE and id == -1, clear all marker_queue
00723         if ( (*new_msg)->action == image_view2::ImageMarker2::REMOVE &&
00724              (*new_msg)->id == -1 ) {
00725           local_queue_.clear();
00726         }
00727       }
00728     }
00729 
00730     // check lifetime and remove REMOVE-type marker msg
00731     for(V_ImageMarkerMessage::iterator it = local_queue_.begin(); it < local_queue_.end(); it++) {
00732       if((*it)->action == image_view2::ImageMarker2::REMOVE ||
00733          ((*it)->lifetime.toSec() != 0.0 && (*it)->lifetime.toSec() < ros::Time::now().toSec())) {
00734         it = local_queue_.erase(it);
00735       }
00736     }
00737   }
00738   
00739   void ImageView2::drawMarkers()
00740   {
00741     resolveLocalMarkerQueue();
00742     if ( !local_queue_.empty() )
00743     {
00744       V_ImageMarkerMessage::iterator message_it = local_queue_.begin();
00745       V_ImageMarkerMessage::iterator message_end = local_queue_.end();
00746       ROS_DEBUG("markers = %ld", local_queue_.size());
00747       //processMessage;
00748       for ( ; message_it != message_end; ++message_it )
00749       {
00750         image_view2::ImageMarker2::ConstPtr& marker = *message_it;
00751 
00752         ROS_DEBUG_STREAM("message type = " << marker->type << ", id " << marker->id);
00753 
00754         // outline colors
00755         std::vector<CvScalar> colors;
00756         BOOST_FOREACH(std_msgs::ColorRGBA color, marker->outline_colors) {
00757           colors.push_back(MsgToRGB(color));
00758         }
00759         if(colors.size() == 0) colors.push_back(DEFAULT_COLOR);
00760         std::vector<CvScalar>::iterator col_it = colors.begin();
00761 
00762         // check camera_info
00763         if( marker->type == image_view2::ImageMarker2::FRAMES ||
00764             marker->type == image_view2::ImageMarker2::LINE_STRIP3D ||
00765             marker->type == image_view2::ImageMarker2::LINE_LIST3D ||
00766             marker->type == image_view2::ImageMarker2::POLYGON3D ||
00767             marker->type == image_view2::ImageMarker2::POINTS3D ||
00768             marker->type == image_view2::ImageMarker2::TEXT3D ||
00769             marker->type == image_view2::ImageMarker2::CIRCLE3D) {
00770           {
00771             boost::mutex::scoped_lock lock(info_mutex_);
00772             if (!info_msg_) {
00773               ROS_WARN("[image_view2] camera_info could not found");
00774               continue;
00775             }
00776             cam_model_.fromCameraInfo(info_msg_);
00777           }
00778         }
00779         // CIRCLE, LINE_STRIP, LINE_LIST, POLYGON, POINTS
00780         switch ( marker->type ) {
00781         case image_view2::ImageMarker2::CIRCLE: {
00782           drawCircle(marker);
00783           break;
00784         }
00785         case image_view2::ImageMarker2::LINE_STRIP: {
00786           drawLineStrip(marker, colors, col_it);
00787           break;
00788         }
00789         case image_view2::ImageMarker2::LINE_LIST: {
00790           drawLineList(marker, colors, col_it);
00791           break;
00792         }
00793         case image_view2::ImageMarker2::POLYGON: {
00794           drawPolygon(marker, colors, col_it);
00795           break;
00796         }
00797         case image_view2::ImageMarker2::POINTS: {
00798           drawPoints(marker, colors, col_it);
00799           break;
00800         }
00801         case image_view2::ImageMarker2::FRAMES: {
00802           drawFrames(marker, colors, col_it);
00803           break;
00804         }
00805         case image_view2::ImageMarker2::TEXT: {
00806           drawText(marker, colors, col_it);
00807           break;
00808         }
00809         case image_view2::ImageMarker2::LINE_STRIP3D: {
00810           drawLineStrip3D(marker, colors, col_it);
00811           break;
00812         }
00813         case image_view2::ImageMarker2::LINE_LIST3D: {
00814           drawLineList3D(marker, colors, col_it);
00815           break;
00816         }
00817         case image_view2::ImageMarker2::POLYGON3D: {
00818           drawPolygon3D(marker, colors, col_it);
00819           break;
00820         }
00821         case image_view2::ImageMarker2::POINTS3D: {
00822           drawPoints3D(marker, colors, col_it);
00823           break;
00824         }
00825         case image_view2::ImageMarker2::TEXT3D: {
00826           drawText3D(marker, colors, col_it);
00827           break;
00828         }
00829         case image_view2::ImageMarker2::CIRCLE3D: {
00830           drawCircle3D(marker, colors, col_it);
00831           break;
00832         }
00833         default: {
00834           ROS_WARN("Undefined Marker type(%d)", marker->type);
00835           break;
00836         }
00837         }
00838       }
00839     }    
00840   }
00841 
00842   void ImageView2::drawInteraction()
00843   {
00844     if (mode_ == MODE_RECTANGLE) {
00845       cv::rectangle(draw_, cv::Point(window_selection_.x, window_selection_.y),
00846                     cv::Point(window_selection_.x + window_selection_.width,
00847                               window_selection_.y + window_selection_.height),
00848                     USER_ROI_COLOR, 3, 8, 0);
00849     }
00850     else if (mode_ == MODE_SERIES) {
00851       if (point_array_.size() > 1) {
00852         cv::Point2d from, to;
00853         from = point_array_[0];
00854         for (size_t i = 1; i < point_array_.size(); i++) {
00855           to = point_array_[i];
00856           cv::line(draw_, from, to, USER_ROI_COLOR, 2, 8, 0);
00857           from = to;
00858         }
00859       }
00860     }
00861     else if (mode_ == MODE_SELECT_FORE_AND_BACK) {
00862       boost::mutex::scoped_lock lock(point_array_mutex_);
00863       if (point_fg_array_.size() > 1) {
00864         cv::Point2d from, to;
00865         from = point_fg_array_[0];
00866         for (size_t i = 1; i < point_fg_array_.size(); i++) {
00867           to = point_fg_array_[i];
00868           cv::line(draw_, from, to, CV_RGB(255, 0, 0), 8, 8, 0);
00869           from = to;
00870         }
00871       }
00872       if (point_bg_array_.size() > 1) {
00873         cv::Point2d from, to;
00874         from = point_bg_array_[0];
00875         for (size_t i = 1; i < point_bg_array_.size(); i++) {
00876           to = point_bg_array_[i];
00877           cv::line(draw_, from, to, CV_RGB(0, 255, 0), 8, 8, 0);
00878           from = to;
00879         }
00880       }
00881     }
00882     else if (mode_ == MODE_SELECT_FORE_AND_BACK_RECT) {
00883       boost::mutex::scoped_lock lock(point_array_mutex_);
00884       if (rect_fg_.width != 0 && rect_fg_.height != 0) {
00885         cv::rectangle(draw_, rect_fg_, CV_RGB(255, 0, 0), 4);
00886       }
00887       if (rect_bg_.width != 0 && rect_bg_.height != 0) {
00888         cv::rectangle(draw_, rect_bg_, CV_RGB(0, 255, 0), 4);
00889       }
00890     }
00891   }
00892 
00893   void ImageView2::drawInfo(ros::Time& before_rendering)
00894   {
00895     static ros::Time last_time;
00896     static std::string info_str_1, info_str_2;
00897     // update info_str_1, info_str_2 if possible
00898     if ( show_info_ && times_.size() > 0 && ( before_rendering.toSec() - last_time.toSec() > 2 ) ) {
00899       int n = times_.size();
00900       double mean = 0, rate = 1.0, std_dev = 0.0, max_delta, min_delta;
00901 
00902       std::for_each( times_.begin(), times_.end(), (mean += boost::lambda::_1) );
00903       mean /= n;
00904       rate /= mean;
00905 
00906       std::for_each( times_.begin(), times_.end(), (std_dev += (boost::lambda::_1 - mean)*(boost::lambda::_1 - mean) ) );
00907       std_dev = sqrt(std_dev/n);
00908       min_delta = *std::min_element(times_.begin(), times_.end());
00909       max_delta = *std::max_element(times_.begin(), times_.end());
00910 
00911       std::stringstream f1, f2;
00912       f1.precision(3); f1 << std::fixed;
00913       f2.precision(3); f2 << std::fixed;
00914       f1 << "" << image_sub_.getTopic() << " : rate:" << rate;
00915       f2 << "min:" << min_delta << "s max: " << max_delta << "s std_dev: " << std_dev << "s n: " << n;
00916       info_str_1 = f1.str();
00917       info_str_2 = f2.str();
00918       ROS_INFO_STREAM(info_str_1 + " " + info_str_2);
00919       times_.clear();
00920       last_time = before_rendering;
00921     }
00922     if (!info_str_1.empty() && !info_str_2.empty()) {
00923       cv::putText(image_, info_str_1.c_str(), cv::Point(10,image_.rows-34), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar::all(255), 2);
00924       cv::putText(image_, info_str_2.c_str(), cv::Point(10,image_.rows-10), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar::all(255), 2);
00925     }
00926   }
00927   
00928   void ImageView2::redraw()
00929   {
00930     if (original_image_.empty()) {
00931       ROS_WARN("no image is available yet");
00932       return;
00933     }
00934     ros::Time before_rendering = ros::Time::now();
00935     original_image_.copyTo(image_);
00936     // Draw Section
00937     if ( blurry_mode_ ) {
00938       draw_ = cv::Mat(image_.size(), image_.type(), CV_RGB(0,0,0));
00939     } else {
00940       draw_ = image_;
00941     }
00942     drawMarkers();
00943     drawInteraction();
00944 
00945     if ( blurry_mode_ ) cv::addWeighted(image_, 0.9, draw_, 1.0, 0.0, image_);
00946     if ( use_window ) {
00947       if (show_info_) {
00948         drawInfo(before_rendering);
00949       }
00950     }
00951     cv_bridge::CvImage out_msg;
00952     out_msg.header   = last_msg_->header;
00953     out_msg.encoding = "bgr8";
00954     out_msg.image    = image_;
00955     image_pub_.publish(out_msg.toImageMsg());
00956   }
00957   
00958   void ImageView2::imageCb(const sensor_msgs::ImageConstPtr& msg)
00959   {
00960     ROS_DEBUG("imageCb");
00961     static int count = 0;
00962     if (count < skip_draw_rate_) {
00963       count++;
00964       return;
00965     }
00966     else {
00967       count = 0;
00968     }
00969     static ros::Time old_time;
00970     times_.push_front(ros::Time::now().toSec() - old_time.toSec());
00971     old_time = ros::Time::now();
00972 
00973     if(old_time.toSec() - ros::Time::now().toSec() > 0) {
00974       ROS_WARN("TF Cleared for old time");
00975     }
00976     {
00977       boost::mutex::scoped_lock lock(image_mutex_);
00978       if (msg->encoding.find("bayer") != std::string::npos) {
00979         original_image_ = cv::Mat(msg->height, msg->width, CV_8UC1,
00980                                   const_cast<uint8_t*>(&msg->data[0]), msg->step);
00981       } else {
00982         try {
00983           original_image_ = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8)->image;
00984         } catch (cv_bridge::Exception& e) {
00985           ROS_ERROR("Unable to convert %s image to bgr8", msg->encoding.c_str());
00986           return;
00987         }
00988       }
00989       // Hang on to message pointer for sake of mouseCb
00990       last_msg_ = msg;
00991       redraw();
00992     }
00993     if (region_continuous_publish_ &&  continuous_ready_) {
00994       publishMouseInteractionResult();
00995     }
00996   }
00997 
00998   void ImageView2::drawImage() {
00999     if (image_.rows > 0 && image_.cols > 0) {
01000       redraw();
01001     }
01002   }
01003 
01004   void ImageView2::addPoint(int x, int y)
01005   {
01006     cv::Point2d p;
01007     p.x = x;
01008     p.y = y;
01009     {
01010       boost::mutex::scoped_lock lock(point_array_mutex_);
01011       point_array_.push_back(p);
01012     }
01013   }
01014 
01015   void ImageView2::setRegionWindowPoint(int x, int y)
01016   {
01017     boost::mutex::scoped_lock lock(point_array_mutex_);
01018     ROS_DEBUG("setRegionWindowPoint");
01019     if (selecting_fg_) {
01020       rect_fg_.x = x;
01021       rect_fg_.y = y;
01022     }
01023     else {
01024       rect_bg_.x = x;
01025       rect_bg_.y = y;
01026     }
01027   }
01028 
01029   void ImageView2::updateRegionWindowSize(int x, int y)
01030   {
01031     ROS_DEBUG("updateRegionWindowPoint");
01032     boost::mutex::scoped_lock lock(point_array_mutex_);
01033     if (selecting_fg_) {
01034       rect_fg_.width = x - rect_fg_.x;
01035       rect_fg_.height = y - rect_fg_.y;
01036     }
01037     else {
01038       rect_bg_.width = x - rect_bg_.x;
01039       rect_bg_.height = y - rect_bg_.y;
01040     }
01041   }
01042   
01043   void ImageView2::addRegionPoint(int x, int y)
01044   {
01045     cv::Point2d p;
01046     p.x = x;
01047     p.y = y;
01048     {
01049       boost::mutex::scoped_lock lock(point_array_mutex_);
01050       if (selecting_fg_) {
01051         point_fg_array_.push_back(p);
01052       }
01053       else {
01054         point_bg_array_.push_back(p);
01055       }
01056     }
01057   }
01058 
01059   void ImageView2::clearPointArray()
01060   {
01061     boost::mutex::scoped_lock lock(point_array_mutex_);
01062     point_fg_array_.clear();
01063     point_bg_array_.clear();
01064     point_array_.clear();
01065   }
01066 
01067   void ImageView2::publishPointArray()
01068   {
01069     pcl::PointCloud<pcl::PointXY> pcl_cloud;
01070     for (size_t i = 0; i < point_array_.size(); i++) {
01071       pcl::PointXY p;
01072       p.x = point_array_[i].x;
01073       p.y = point_array_[i].y;
01074       pcl_cloud.points.push_back(p);
01075     }
01076     sensor_msgs::PointCloud2::Ptr ros_cloud(new sensor_msgs::PointCloud2);
01077     pcl::toROSMsg(pcl_cloud, *ros_cloud);
01078     ros_cloud->header.stamp = ros::Time::now();
01079     
01080     point_array_pub_.publish(ros_cloud);
01081   }
01082     
01083   
01084   void ImageView2::setMode(KEY_MODE mode)
01085   {
01086     mode_ = mode;
01087   }
01088 
01089   ImageView2::KEY_MODE ImageView2::getMode()
01090   {
01091     return mode_;
01092   }
01093 
01094   bool ImageView2::toggleSelection()
01095   {
01096     boost::mutex::scoped_lock lock(point_array_mutex_);
01097     selecting_fg_ = !selecting_fg_;
01098     return selecting_fg_;
01099   }
01100 
01101   void ImageView2::pointArrayToMask(std::vector<cv::Point2d>& points,
01102                                     cv::Mat& mask)
01103   {
01104     cv::Point2d from, to;
01105     if (points.size() > 1) {
01106       from = points[0];
01107       for (size_t i = 1; i < points.size(); i++) {
01108         to = points[i];
01109         cv::line(mask, from, to, cv::Scalar(255), 8, 8, 0);
01110         from = to;
01111       }
01112     }
01113   }
01114 
01115   void ImageView2::publishMonoImage(ros::Publisher& pub,
01116                                     cv::Mat& image,
01117                                     const std_msgs::Header& header)
01118   {
01119     cv_bridge::CvImage image_bridge(
01120       header, sensor_msgs::image_encodings::MONO8, image);
01121     pub.publish(image_bridge.toImageMsg());
01122   }
01123   
01124   void ImageView2::publishForegroundBackgroundMask()
01125   {
01126     boost::mutex::scoped_lock lock2(point_array_mutex_);
01127     cv::Mat foreground_mask
01128       = cv::Mat::zeros(last_msg_->height, last_msg_->width, CV_8UC1);
01129     cv::Mat background_mask
01130       = cv::Mat::zeros(last_msg_->height, last_msg_->width, CV_8UC1);
01131     if (getMode() == MODE_SELECT_FORE_AND_BACK) {
01132       pointArrayToMask(point_fg_array_, foreground_mask);
01133       pointArrayToMask(point_bg_array_, background_mask);
01134     }
01135     else if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01136       cv::rectangle(foreground_mask, rect_fg_, cv::Scalar(255), CV_FILLED);
01137       cv::rectangle(background_mask, rect_bg_, cv::Scalar(255), CV_FILLED);
01138     }
01139     publishMonoImage(foreground_mask_pub_, foreground_mask, last_msg_->header);
01140     publishMonoImage(background_mask_pub_, background_mask, last_msg_->header);
01141   }
01142 
01143   void ImageView2::publishMouseInteractionResult()
01144   {
01145     if (getMode() == MODE_SERIES) {
01146       publishPointArray();
01147     }
01148     else if (getMode() == MODE_SELECT_FORE_AND_BACK ||
01149              getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01150       publishForegroundBackgroundMask();
01151     }
01152     else {
01153       cv::Point2f Pt_1(window_selection_.x, window_selection_.y);
01154       cv::Point2f Pt(button_up_pos_);
01155       std::cout << "PT_1" << Pt_1 << std::endl;
01156       std::cout << "Pt" << Pt << std::endl;
01157       if (!isValidMovement(Pt_1, Pt)) {
01158         geometry_msgs::PointStamped screen_msg;
01159         screen_msg.point.x = window_selection_.x * resize_x_;
01160         screen_msg.point.y = window_selection_.y * resize_y_;
01161         screen_msg.point.z = 0;
01162         screen_msg.header.stamp = last_msg_->header.stamp;
01163         ROS_INFO("Publish screen point %s (%f %f)", point_pub_.getTopic().c_str(), screen_msg.point.x, screen_msg.point.y);
01164         point_pub_.publish(screen_msg);
01165       } else {
01166         geometry_msgs::PolygonStamped screen_msg;
01167         screen_msg.polygon.points.resize(2);
01168         screen_msg.polygon.points[0].x = window_selection_.x * resize_x_;
01169         screen_msg.polygon.points[0].y = window_selection_.y * resize_y_;
01170         screen_msg.polygon.points[1].x = (window_selection_.x + window_selection_.width) * resize_x_;
01171         screen_msg.polygon.points[1].y = (window_selection_.y + window_selection_.height) * resize_y_;
01172         screen_msg.header.stamp = last_msg_->header.stamp;
01173         ROS_INFO("Publish rectangle point %s (%f %f %f %f)", rectangle_pub_.getTopic().c_str(),
01174                  screen_msg.polygon.points[0].x, screen_msg.polygon.points[0].y,
01175                  screen_msg.polygon.points[1].x, screen_msg.polygon.points[1].y);
01176         rectangle_pub_.publish(screen_msg);
01177         continuous_ready_ = true;
01178       }
01179     }
01180   }
01181     
01182   
01183   bool ImageView2::isValidMovement(const cv::Point2f& start_point,
01184                                    const cv::Point2f& end_point)
01185   {
01186     double dist_px = cv::norm(cv::Mat(start_point), cv::Mat(end_point));
01187     return dist_px > 3.0;
01188   }
01189 
01190   void ImageView2::processLeftButtonDown(int x, int y)
01191   {
01192     ROS_DEBUG("processLeftButtonDown");
01193     left_button_clicked_ = true;
01194     continuous_ready_ = false;
01195     window_selection_.x = x;
01196     window_selection_.y = y;
01197     window_selection_.width = window_selection_.height = 0;
01198     if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01199       setRegionWindowPoint(x, y);
01200     }
01201   }
01202 
01203   void ImageView2::processMove(int x, int y)
01204   {
01205     if (left_button_clicked_) {
01206       cv::Point2f Pt_1(window_selection_.x, window_selection_.y);
01207       cv::Point2f Pt(x, y);
01208       if (isValidMovement(Pt_1, Pt)) {
01209         if (getMode() == MODE_RECTANGLE) {
01210           window_selection_.width  = x - window_selection_.x;
01211           window_selection_.height = y - window_selection_.y;
01212         }
01213         else if (getMode() == MODE_SERIES) {
01214           addPoint(x, y);
01215         }
01216         else if (getMode() == MODE_SELECT_FORE_AND_BACK) {
01217           addRegionPoint(x, y);
01218         }
01219         else if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01220           updateRegionWindowSize(x, y);
01221         }
01222       }
01223       // publish the points
01224       geometry_msgs::PointStamped move_point;
01225       move_point.header.stamp = ros::Time::now();
01226       move_point.point.x = x;
01227       move_point.point.y = y;
01228       move_point.point.z = 0;
01229       move_point_pub_.publish(move_point);
01230     }
01231   }
01232 
01233   void ImageView2::processLeftButtonUp(int x, int y)
01234   {
01235     if (!left_button_clicked_) {
01236       return;
01237     }
01238     if (getMode() == MODE_SERIES) {
01239       publishMouseInteractionResult();
01240       clearPointArray();
01241     }
01242     else if (getMode() == MODE_SELECT_FORE_AND_BACK ||
01243              getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01244       bool fgp = toggleSelection();
01245       if (fgp) {
01246         publishMouseInteractionResult();
01247         continuous_ready_ = true;
01248         //clearPointArray();
01249       }
01250     }
01251     else if (getMode() == MODE_RECTANGLE) {
01252       // store x and y
01253       button_up_pos_ = cv::Point2f(x, y);
01254       publishMouseInteractionResult();
01255       
01256     }
01257     left_button_clicked_ = false;
01258   }
01259   
01260   void ImageView2::processMouseEvent(int event, int x, int y, int flags, void* param)
01261   {
01262     checkMousePos(x, y);
01263     switch (event){
01264     case CV_EVENT_MOUSEMOVE: {
01265       processMove(x, y);
01266       break;
01267     }
01268     case CV_EVENT_LBUTTONDOWN:  // click
01269       processLeftButtonDown(x, y);
01270       break;
01271     case CV_EVENT_LBUTTONUP:
01272       processLeftButtonUp(x, y);
01273       break;
01274     case CV_EVENT_RBUTTONDOWN:
01275     {
01276       boost::mutex::scoped_lock lock(image_mutex_);
01277       if (!image_.empty()) {
01278         std::string filename = (filename_format_ % count_).str();
01279         cv::imwrite(filename.c_str(), image_);
01280         ROS_INFO("Saved image %s", filename.c_str());
01281         count_++;
01282       } else {
01283         ROS_WARN("Couldn't save image, no data!");
01284       }
01285       break;
01286     }
01287     }
01288     {
01289       boost::mutex::scoped_lock lock2(image_mutex_);
01290       drawImage();
01291     }
01292     return;
01293   }
01294   
01295   void ImageView2::mouseCb(int event, int x, int y, int flags, void* param)
01296   {
01297     ROS_DEBUG("mouseCB");
01298     ImageView2 *iv = (ImageView2*)param;
01299     iv->processMouseEvent(event, x, y, flags, param);
01300     return;
01301   }
01302 
01303   void ImageView2::pressKey(int key)
01304   {
01305     if (key != -1) {
01306       if (getMode() == MODE_SELECT_FORE_AND_BACK) {
01307         // only grabcut works here
01308         switch (key) {
01309         case 27: {
01310           boost::mutex::scoped_lock lock(point_array_mutex_);
01311           point_fg_array_.clear();
01312           point_bg_array_.clear();
01313           selecting_fg_ = true;
01314           break;
01315         }
01316         }
01317       }
01318       if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01319         // only grabcut works here
01320         switch (key) {
01321         case 27: {
01322           boost::mutex::scoped_lock lock(point_array_mutex_);
01323           rect_fg_.width = rect_fg_.height = 0;
01324           rect_bg_.width = rect_bg_.height = 0;
01325           selecting_fg_ = true;
01326           break;
01327         }
01328         }
01329       }
01330     }
01331   }
01332 
01333   void ImageView2::showImage()
01334   {
01335     if (use_window) {
01336       if (!window_initialized_) {
01337         cv::setMouseCallback(window_name_.c_str(), &ImageView2::mouseCb, this);
01338         cv::namedWindow(window_name_.c_str(), autosize_ ? CV_WINDOW_AUTOSIZE : 0);
01339         window_initialized_ = false;
01340       }
01341       if(!image_.empty()) {
01342         cv::imshow(window_name_.c_str(), image_);
01343       }
01344     }
01345   }
01346 
01347   void ImageView2::checkMousePos(int& x, int& y)
01348   {
01349     if (last_msg_) {
01350       x = std::max(std::min(x, (int)last_msg_->width), 0);
01351       y = std::max(std::min(y, (int)last_msg_->height), 0);
01352     }
01353   }
01354 }
01355 
01356 
01357 
01358 int main(int argc, char **argv)
01359 {
01360   //ros::init(argc, argv, "image_view2", ros::init_options::AnonymousName);
01361   ros::init(argc, argv, "image_view2");
01362   ros::NodeHandle n;
01363 
01364   if ( n.resolveName("image") == "/image") {
01365     ROS_WARN("image_view: image has not been remapped! Typical command-line usage:\n"
01366              "\t$ ./image_view image:=<image topic> [transport]");
01367   }
01368   ros::AsyncSpinner spinner(1);
01369   image_view2::ImageView2 view(n);
01370   spinner.start();
01371   while (ros::ok()) {
01372     int key = cv::waitKey(1000 / 30);
01373     view.pressKey(key);
01374     view.showImage();
01375   }
01376   return 0;
01377 }


image_view2
Author(s): Kei Okada
autogenerated on Sun Jan 25 2015 12:38:01