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 #include <exception>
00038 namespace image_view2{
00039   ImageView2::ImageView2() : marker_topic_("image_marker"), filename_format_(""), count_(0), mode_(MODE_RECTANGLE), times_(100), window_initialized_(false),space_(10)
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       line_select_start_point_(true), line_selected_(false), poly_selecting_done_(true)
00047   {
00048     std::string camera = nh.resolveName("image");
00049     std::string camera_info = nh.resolveName("camera_info");
00050     ros::NodeHandle local_nh("~");
00051     std::string format_string;
00052     std::string transport;
00053     image_transport::ImageTransport it(nh);
00054     image_transport::ImageTransport local_it(camera);
00055 
00056     point_pub_ = nh.advertise<geometry_msgs::PointStamped>(camera + "/screenpoint",100);
00057     point_array_pub_ = nh.advertise<sensor_msgs::PointCloud2>(camera + "/screenpoint_array",100);
00058     rectangle_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/screenrectangle",100);
00059     rectangle_img_pub_ = nh.advertise<sensor_msgs::Image>(camera + "/screenrectangle_image", 100);
00060     move_point_pub_ = nh.advertise<geometry_msgs::PointStamped>(camera + "/movepoint", 100);
00061     foreground_mask_pub_ = nh.advertise<sensor_msgs::Image>(camera + "/foreground", 100);
00062     background_mask_pub_ = nh.advertise<sensor_msgs::Image>(camera + "/background", 100);
00063     foreground_rect_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/foreground_rect", 100);
00064     background_rect_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/background_rect", 100);
00065     line_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/line", 100);
00066     poly_pub_ = nh.advertise<geometry_msgs::PolygonStamped>(camera + "/poly", 100);
00067     local_nh.param("window_name", window_name_, std::string("image_view2 [")+camera+std::string("]"));
00068     local_nh.param("skip_draw_rate", skip_draw_rate_, 0);
00069     local_nh.param("autosize", autosize_, false);
00070     local_nh.param("image_transport", transport, std::string("raw"));
00071     local_nh.param("draw_grid", draw_grid_, false);
00072     local_nh.param("blurry", blurry_mode_, false);
00073     local_nh.param("region_continuous_publish", region_continuous_publish_, false);
00074     local_nh.param("filename_format", format_string, std::string("frame%04i.jpg"));
00075     local_nh.param("use_window", use_window, true);
00076     local_nh.param("show_info", show_info_, false);
00077 
00078     double xx,yy;
00079     local_nh.param("resize_scale_x", xx, 1.0);
00080     local_nh.param("resize_scale_y", yy, 1.0);
00081     local_nh.param("tf_timeout", tf_timeout_, 1.0);
00082     
00083     std::string interaction_mode;
00084     local_nh.param("interaction_mode", interaction_mode, std::string("rectangle"));
00085     setMode(stringToMode(interaction_mode));
00086     resize_x_ = 1.0/xx;
00087     resize_y_ = 1.0/yy;
00088     filename_format_.parse(format_string);
00089 
00090     font_ = cv::FONT_HERSHEY_DUPLEX;
00091     window_selection_.x = window_selection_.y =
00092       window_selection_.height = window_selection_.width = 0;
00093 
00094     image_pub_ = it.advertise("image_marked", 1);
00095     local_image_pub_ = local_it.advertise("marked", 1);
00096     
00097     image_sub_ = it.subscribe(camera, 1, &ImageView2::imageCb, this, transport);
00098     info_sub_ = nh.subscribe(camera_info, 1, &ImageView2::infoCb, this);
00099     marker_sub_ = nh.subscribe(marker_topic_, 10, &ImageView2::markerCb, this);
00100     event_sub_ = local_nh.subscribe(camera + "/event", 100, &ImageView2::eventCb, this);
00101     
00102     change_mode_srv_ = local_nh.advertiseService(
00103       "change_mode", &ImageView2::changeModeServiceCallback, this);
00104     rectangle_mode_srv_ = local_nh.advertiseService(
00105       "rectangle_mode", &ImageView2::rectangleModeServiceCallback, this);
00106     grabcut_mode_srv_ = local_nh.advertiseService(
00107       "grabcut_mode", &ImageView2::grabcutModeServiceCallback, this);
00108     grabcut_rect_mode_srv_ = local_nh.advertiseService(
00109       "grabcut_rect_mode", &ImageView2::grabcutRectModeServiceCallback, this);
00110     line_mode_srv_ = local_nh.advertiseService(
00111       "line_mode", &ImageView2::lineModeServiceCallback, this);
00112     poly_mode_srv_ = local_nh.advertiseService(
00113       "poly_mode", &ImageView2::polyModeServiceCallback, this);
00114     none_mode_srv_ = local_nh.advertiseService(
00115       "none_mode", &ImageView2::noneModeServiceCallback, this);
00116 
00117     srv_ = boost::make_shared <dynamic_reconfigure::Server<Config> >(local_nh);
00118     dynamic_reconfigure::Server<Config>::CallbackType f =
00119       boost::bind(&ImageView2::config_callback, this, _1, _2);
00120     srv_->setCallback(f);
00121   }
00122 
00123   ImageView2::~ImageView2()
00124   {
00125     if ( use_window ) {
00126       cv::destroyWindow(window_name_.c_str());
00127     }
00128   }
00129 
00130   void ImageView2::config_callback(Config &config, uint32_t level)
00131   {
00132     draw_grid_ = config.grid;
00133     fisheye_mode_ = config.fisheye_mode;
00134     div_u_ = config.div_u;
00135     div_v_ = config.div_v;
00136 
00137     grid_red_ = config.grid_red;
00138     grid_blue_ = config.grid_blue;
00139     grid_green_ = config.grid_green;
00140     grid_thickness_ = config.grid_thickness;
00141     space_  = config.grid_space;
00142   }
00143 
00144   void ImageView2::markerCb(const image_view2::ImageMarker2ConstPtr& marker)
00145   {
00146     ROS_DEBUG("markerCb");
00147     // convert lifetime to duration from Time(0)
00148     if(marker->lifetime != ros::Duration(0))
00149       boost::const_pointer_cast<image_view2::ImageMarker2>(marker)->lifetime = (ros::Time::now() - ros::Time(0)) + marker->lifetime;
00150     {
00151       boost::mutex::scoped_lock lock(queue_mutex_);
00152       marker_queue_.push_back(marker);
00153     }
00154     redraw();
00155   }
00156 
00157   void ImageView2::infoCb(const sensor_msgs::CameraInfoConstPtr& msg) {
00158     ROS_DEBUG("infoCb");
00159     boost::mutex::scoped_lock lock(info_mutex_);
00160     info_msg_ = msg;
00161   }
00162 
00163   bool ImageView2::lookupTransformation(
00164     std::string frame_id, ros::Time& acquisition_time,
00165     std::map<std::string, int>& tf_fail,
00166     tf::StampedTransform &transform)
00167   {
00168     ros::Duration timeout(tf_timeout_); // wait 0.5 sec
00169     try {
00170       ros::Time tm;
00171       tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00172       tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00173                                     acquisition_time, timeout);
00174       tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00175                                    acquisition_time, transform);
00176       tf_fail[frame_id]=0;
00177       return true;
00178     }
00179     catch (tf::TransformException& ex) {
00180       tf_fail[frame_id]++;
00181       if ( tf_fail[frame_id] < 5 ) {
00182         ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00183       } else {
00184         ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00185       }
00186       return false;
00187     }
00188   }
00189   
00190   void ImageView2::drawCircle(const image_view2::ImageMarker2::ConstPtr& marker)
00191   {
00192     cv::Point2d uv = cv::Point2d(marker->position.x, marker->position.y);
00193     if ( blurry_mode_ ) {
00194       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00195       CvScalar co = MsgToRGB(marker->outline_color);
00196       for (int s1 = s0*10; s1 >= s0; s1--) {
00197         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00198         cv::circle(draw_, uv,
00199                    (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale),
00200                    CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00201                    s1);
00202       }
00203     } else {
00204       cv::circle(draw_, uv,
00205                  (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale),
00206                  MsgToRGB(marker->outline_color),
00207                  (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00208       if (marker->filled) {
00209         cv::circle(draw_, uv,
00210                    (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale) - (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width) / 2.0,
00211                    MsgToRGB(marker->fill_color),
00212                    -1);
00213       }
00214     }
00215   }
00216 
00217   void ImageView2::drawLineStrip(const image_view2::ImageMarker2::ConstPtr& marker,
00218                                  std::vector<CvScalar>& colors,
00219                                  std::vector<CvScalar>::iterator& col_it)
00220   {
00221     cv::Point2d p0, p1;
00222     if ( blurry_mode_ ) {
00223       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00224       std::vector<CvScalar>::iterator col_it = colors.begin();
00225       CvScalar co = (*col_it);
00226       for (int s1 = s0*10; s1 >= s0; s1--) {
00227         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00228         std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00229         std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00230         p0 = cv::Point2d(it->x, it->y); it++;
00231         for ( ; it!= end; it++ ) {
00232           p1 = cv::Point2d(it->x, it->y);
00233           cv::line(draw_, p0, p1,
00234                    CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00235                    s1);
00236           p0 = p1;
00237           if(++col_it == colors.end()) col_it = colors.begin();
00238         }
00239       }
00240     } else {
00241       std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00242       std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00243       p0 = cv::Point2d(it->x, it->y); it++;
00244       for ( ; it!= end; it++ ) {
00245         p1 = cv::Point2d(it->x, it->y);
00246         cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00247         p0 = p1;
00248         if(++col_it == colors.end()) col_it = colors.begin();
00249       }
00250     }
00251   }
00252 
00253   void ImageView2::drawLineList(const image_view2::ImageMarker2::ConstPtr& marker,
00254                                 std::vector<CvScalar>& colors,
00255                                 std::vector<CvScalar>::iterator& col_it)
00256   {
00257     cv::Point2d p0, p1;
00258     if ( blurry_mode_ ) {
00259       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00260       std::vector<CvScalar>::iterator col_it = colors.begin();
00261       CvScalar co = (*col_it);
00262       for (int s1 = s0*10; s1 >= s0; s1--) {
00263         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00264         std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00265         std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00266         for ( ; it!= end; ) {
00267           p0 = cv::Point2d(it->x, it->y); it++;
00268           if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00269           cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00270           it++;
00271           if(++col_it == colors.end()) col_it = colors.begin();
00272         }
00273       }
00274     } else {
00275       std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00276       std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00277       for ( ; it!= end; ) {
00278         p0 = cv::Point2d(it->x, it->y); it++;
00279         if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00280         cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00281         it++;
00282         if(++col_it == colors.end()) col_it = colors.begin();
00283       }
00284     }
00285   }
00286 
00287   void ImageView2::drawPolygon(const image_view2::ImageMarker2::ConstPtr& marker,
00288                                std::vector<CvScalar>& colors,
00289                                std::vector<CvScalar>::iterator& col_it)
00290   {
00291     cv::Point2d p0, p1;
00292     if ( blurry_mode_ ) {
00293       int s0 = (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width);
00294       std::vector<CvScalar>::iterator col_it = colors.begin();
00295       CvScalar co = (*col_it);
00296       for (int s1 = s0*10; s1 >= s0; s1--) {
00297         double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00298         std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00299         std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00300         p0 = cv::Point2d(it->x, it->y); it++;
00301         for ( ; it!= end; it++ ) {
00302           p1 = cv::Point2d(it->x, it->y);
00303           cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00304           p0 = p1;
00305           if(++col_it == colors.end()) col_it = colors.begin();
00306         }
00307         it = marker->points.begin();
00308         p1 = cv::Point2d(it->x, it->y);
00309         cv::line(draw_, p0, p1, CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m), s1);
00310       }
00311     } else {
00312       std::vector<geometry_msgs::Point>::const_iterator it = marker->points.begin();
00313       std::vector<geometry_msgs::Point>::const_iterator end = marker->points.end();
00314       std::vector<cv::Point> points;
00315 
00316       if (marker->filled) {
00317         points.push_back(cv::Point(it->x, it->y));
00318       }
00319       p0 = cv::Point2d(it->x, it->y); it++;
00320       for ( ; it!= end; it++ ) {
00321         p1 = cv::Point2d(it->x, it->y);
00322         if (marker->filled) {
00323           points.push_back(cv::Point(it->x, it->y));
00324         }
00325         cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00326         p0 = p1;
00327         if(++col_it == colors.end()) col_it = colors.begin();
00328       }
00329       it = marker->points.begin();
00330       p1 = cv::Point2d(it->x, it->y);
00331       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00332       if (marker->filled) {
00333         cv::fillConvexPoly(draw_, points.data(), points.size(), MsgToRGB(marker->fill_color));
00334       }
00335     }
00336   }
00337 
00338   void ImageView2::drawPoints(const image_view2::ImageMarker2::ConstPtr& marker,
00339                               std::vector<CvScalar>& colors,
00340                               std::vector<CvScalar>::iterator& col_it)
00341   {
00342     BOOST_FOREACH(geometry_msgs::Point p, marker->points) {
00343       cv::Point2d uv = cv::Point2d(p.x, p.y);
00344       if ( blurry_mode_ ) {
00345         int s0 = (marker->scale == 0 ? 3 : marker->scale);
00346         CvScalar co = (*col_it);
00347         for (int s1 = s0*2; s1 >= s0; s1--) {
00348           double m = pow((1.0-((double)(s1 - s0))/s0),2);
00349           cv::circle(draw_, uv, s1,
00350                      CV_RGB(co.val[2] * m,co.val[1] * m,co.val[0] * m),
00351                      -1);
00352         }
00353       } else {
00354         cv::circle(draw_, uv, (marker->scale == 0 ? 3 : marker->scale) , *col_it, -1);
00355       }
00356       if(++col_it == colors.end()) col_it = colors.begin();
00357     }
00358   }
00359 
00360   void ImageView2::drawFrames(const image_view2::ImageMarker2::ConstPtr& marker,
00361                               std::vector<CvScalar>& colors,
00362                               std::vector<CvScalar>::iterator& col_it)
00363   {
00364     static std::map<std::string, int> tf_fail;
00365     BOOST_FOREACH(std::string frame_id, marker->frames) {
00366       tf::StampedTransform transform;
00367       ros::Time acquisition_time = last_msg_->header.stamp;
00368       if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00369         return;
00370       }
00371       // center point
00372       tf::Point pt = transform.getOrigin();
00373       cv::Point3d pt_cv(pt.x(), pt.y(), pt.z());
00374       cv::Point2d uv;
00375       uv = cam_model_.project3dToPixel(pt_cv);
00376 
00377       static const int RADIUS = 3;
00378       cv::circle(draw_, uv, RADIUS, DEFAULT_COLOR, -1);
00379 
00380       // x, y, z
00381       cv::Point2d uv0, uv1, uv2;
00382       tf::Stamped<tf::Point> pin, pout;
00383 
00384       // x
00385       pin = tf::Stamped<tf::Point>(tf::Point(0.05, 0, 0), acquisition_time, frame_id);
00386       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00387       uv0 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00388       // y
00389       pin = tf::Stamped<tf::Point>(tf::Point(0, 0.05, 0), acquisition_time, frame_id);
00390       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00391       uv1 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00392 
00393       // z
00394       pin = tf::Stamped<tf::Point>(tf::Point(0, 0, 0.05), acquisition_time, frame_id);
00395       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00396       uv2 = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00397 
00398       // draw
00399       if ( blurry_mode_ ) {
00400         int s0 = 2;
00401         CvScalar c0 = CV_RGB(255,0,0);
00402         CvScalar c1 = CV_RGB(0,255,0);
00403         CvScalar c2 = CV_RGB(0,0,255);
00404         for (int s1 = s0*10; s1 >= s0; s1--) {
00405           double m = pow((1.0-((double)(s1 - s0))/(s0*9)),2);
00406           cv::line(draw_, uv, uv0,
00407                    CV_RGB(c0.val[2] * m,c0.val[1] * m,c0.val[0] * m),
00408                    s1);
00409           cv::line(draw_, uv, uv1,
00410                    CV_RGB(c1.val[2] * m,c1.val[1] * m,c1.val[0] * m),
00411                    s1);
00412           cv::line(draw_, uv, uv2,
00413                    CV_RGB(c2.val[2] * m,c2.val[1] * m,c2.val[0] * m),
00414                    s1);
00415         }
00416       } else {
00417         cv::line(draw_, uv, uv0, CV_RGB(255,0,0), 2);
00418         cv::line(draw_, uv, uv1, CV_RGB(0,255,0), 2);
00419         cv::line(draw_, uv, uv2, CV_RGB(0,0,255), 2);
00420       }
00421 
00422       // index
00423       cv::Size text_size;
00424       int baseline;
00425       text_size = cv::getTextSize(frame_id.c_str(), font_, 1.0, 1.0, &baseline);
00426       cv::Point origin = cv::Point(uv.x - text_size.width / 2,
00427                                    uv.y - RADIUS - baseline - 3);
00428       cv::putText(draw_, frame_id.c_str(), origin, font_, 1.0, DEFAULT_COLOR, 1.5);
00429     }
00430   }
00431 
00432   cv::Point ImageView2::ratioPoint(double x, double y)
00433   {
00434     if (last_msg_) {
00435       return cv::Point(last_msg_->width * x,
00436                        last_msg_->height * y);
00437     }
00438     else {
00439       return cv::Point(0, 0);
00440     }
00441   }
00442   
00443   void ImageView2::drawText(const image_view2::ImageMarker2::ConstPtr& marker,
00444                             std::vector<CvScalar>& colors,
00445                             std::vector<CvScalar>::iterator& col_it)
00446   {
00447     cv::Size text_size;
00448     int baseline;
00449     float scale = marker->scale;
00450     if ( scale == 0 ) scale = 1.0;
00451     text_size = cv::getTextSize(marker->text.c_str(), font_,
00452                                 scale, scale, &baseline);
00453     // fix scale
00454     if (marker->ratio_scale) {
00455       cv::Size a_size = cv::getTextSize("A", font_, 1.0, 1.0, &baseline);
00456       int height_size = a_size.height;
00457       double desired_size = last_msg_->height * scale;
00458       scale = desired_size / height_size;
00459       ROS_DEBUG("text scale: %f", scale);
00460     }
00461       
00462     cv::Point origin;
00463     if (marker->left_up_origin) {
00464       if (marker->ratio_scale) {
00465         origin = ratioPoint(marker->position.x,
00466                             marker->position.y);
00467       }
00468       else {
00469         origin = cv::Point(marker->position.x,
00470                            marker->position.y);
00471       }
00472     }
00473     else {
00474       if (marker->ratio_scale) {
00475         cv::Point p = ratioPoint(marker->position.x, marker->position.y);
00476         origin = cv::Point(p.x - text_size.width/2,
00477                            p.y + baseline+3);
00478       }
00479       else {
00480         origin = cv::Point(marker->position.x - text_size.width/2,
00481                            marker->position.y + baseline+3);
00482       }
00483     }
00484     
00485     if (marker->filled) {
00486       cv::putText(draw_, marker->text.c_str(), origin, font_, scale, DEFAULT_COLOR, marker->filled);
00487       
00488     }
00489     else {
00490       cv::putText(draw_, marker->text.c_str(), origin, font_, scale, DEFAULT_COLOR);
00491     }
00492   }
00493 
00494   void ImageView2::drawLineStrip3D(const image_view2::ImageMarker2::ConstPtr& marker,
00495                                    std::vector<CvScalar>& colors,
00496                                    std::vector<CvScalar>::iterator& col_it)
00497   {
00498     static std::map<std::string, int> tf_fail;
00499     std::string frame_id = marker->points3D.header.frame_id;
00500     tf::StampedTransform transform;
00501     ros::Time acquisition_time = last_msg_->header.stamp;
00502     //ros::Time acquisition_time = msg->points3D.header.stamp;
00503     ros::Duration timeout(tf_timeout_); // wait 0.5 sec
00504     try {
00505       ros::Time tm;
00506       tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00507       ros::Duration diff = ros::Time::now() - tm;
00508       if ( diff > ros::Duration(1.0) ) { return; }
00509       tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00510                                     acquisition_time, timeout);
00511       tf_listener_.lookupTransform(cam_model_.tfFrame(), frame_id,
00512                                    acquisition_time, transform);
00513       tf_fail[frame_id]=0;
00514     }
00515     catch (tf::TransformException& ex) {
00516       tf_fail[frame_id]++;
00517       if ( tf_fail[frame_id] < 5 ) {
00518         ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00519       } else {
00520         ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00521       }
00522       return;
00523     }
00524     std::vector<geometry_msgs::Point> points2D;
00525     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00526       tf::Point pt = transform.getOrigin();
00527       geometry_msgs::PointStamped pt_cam, pt_;
00528       pt_cam.header.frame_id = cam_model_.tfFrame();
00529       pt_cam.header.stamp = acquisition_time;
00530       pt_cam.point.x = pt.x();
00531       pt_cam.point.y = pt.y();
00532       pt_cam.point.z = pt.z();
00533       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00534 
00535       cv::Point2d uv;
00536       tf::Stamped<tf::Point> pin, pout;
00537       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);
00538       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00539       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00540       geometry_msgs::Point point2D;
00541       point2D.x = uv.x;
00542       point2D.y = uv.y;
00543       points2D.push_back(point2D);
00544     }
00545     cv::Point2d p0, p1;
00546     std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00547     std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00548     p0 = cv::Point2d(it->x, it->y); it++;
00549     for ( ; it!= end; it++ ) {
00550       p1 = cv::Point2d(it->x, it->y);
00551       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00552       p0 = p1;
00553       if(++col_it == colors.end()) col_it = colors.begin();
00554     }
00555   }
00556 
00557   void ImageView2::drawLineList3D(const image_view2::ImageMarker2::ConstPtr& marker,
00558                                   std::vector<CvScalar>& colors,
00559                                   std::vector<CvScalar>::iterator& col_it)
00560   {
00561     static std::map<std::string, int> tf_fail;
00562     std::string frame_id = marker->points3D.header.frame_id;
00563     tf::StampedTransform transform;
00564     ros::Time acquisition_time = last_msg_->header.stamp;
00565     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00566       return;
00567     }
00568     std::vector<geometry_msgs::Point> points2D;
00569     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00570       tf::Point pt = transform.getOrigin();
00571       geometry_msgs::PointStamped pt_cam, pt_;
00572       pt_cam.header.frame_id = cam_model_.tfFrame();
00573       pt_cam.header.stamp = acquisition_time;
00574       pt_cam.point.x = pt.x();
00575       pt_cam.point.y = pt.y();
00576       pt_cam.point.z = pt.z();
00577       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00578 
00579       cv::Point2d uv;
00580       tf::Stamped<tf::Point> pin, pout;
00581       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);
00582       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00583       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00584       geometry_msgs::Point point2D;
00585       point2D.x = uv.x;
00586       point2D.y = uv.y;
00587       points2D.push_back(point2D);
00588     }
00589     cv::Point2d p0, p1;
00590     std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00591     std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00592     for ( ; it!= end; ) {
00593       p0 = cv::Point2d(it->x, it->y); it++;
00594       if ( it != end ) p1 = cv::Point2d(it->x, it->y);
00595       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00596       it++;
00597       if(++col_it == colors.end()) col_it = colors.begin();
00598     }
00599   }
00600   
00601   void ImageView2::drawPolygon3D(const image_view2::ImageMarker2::ConstPtr& marker,
00602                                  std::vector<CvScalar>& colors,
00603                                  std::vector<CvScalar>::iterator& col_it)
00604   {
00605     static std::map<std::string, int> tf_fail;
00606     std::string frame_id = marker->points3D.header.frame_id;
00607     tf::StampedTransform transform;
00608     ros::Time acquisition_time = last_msg_->header.stamp;
00609     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00610       return;
00611     }
00612     std::vector<geometry_msgs::Point> points2D;
00613     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00614       tf::Point pt = transform.getOrigin();
00615       geometry_msgs::PointStamped pt_cam, pt_;
00616       pt_cam.header.frame_id = cam_model_.tfFrame();
00617       pt_cam.header.stamp = acquisition_time;
00618       pt_cam.point.x = pt.x();
00619       pt_cam.point.y = pt.y();
00620       pt_cam.point.z = pt.z();
00621       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00622 
00623       cv::Point2d uv;
00624       tf::Stamped<tf::Point> pin, pout;
00625       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);
00626       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00627       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00628       geometry_msgs::Point point2D;
00629       point2D.x = uv.x;
00630       point2D.y = uv.y;
00631       points2D.push_back(point2D);
00632     }
00633     cv::Point2d p0, p1;
00634     std::vector<geometry_msgs::Point>::const_iterator it = points2D.begin();
00635     std::vector<geometry_msgs::Point>::const_iterator end = points2D.end();
00636     std::vector<cv::Point> points;
00637 
00638     if (marker->filled) {
00639       points.push_back(cv::Point(it->x, it->y));
00640     }
00641     p0 = cv::Point2d(it->x, it->y); it++;
00642     for ( ; it!= end; it++ ) {
00643       p1 = cv::Point2d(it->x, it->y);
00644       if (marker->filled) {
00645         points.push_back(cv::Point(it->x, it->y));
00646       }
00647       cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00648       p0 = p1;
00649       if(++col_it == colors.end()) col_it = colors.begin();
00650     }
00651     it = points2D.begin();
00652     p1 = cv::Point2d(it->x, it->y);
00653     cv::line(draw_, p0, p1, *col_it, (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00654     if (marker->filled) {
00655       cv::fillConvexPoly(draw_, points.data(), points.size(), MsgToRGB(marker->fill_color));
00656     }
00657   }
00658 
00659   void ImageView2::drawPoints3D(const image_view2::ImageMarker2::ConstPtr& marker,
00660                                 std::vector<CvScalar>& colors,
00661                                 std::vector<CvScalar>::iterator& col_it)
00662   {
00663     static std::map<std::string, int> tf_fail;
00664     std::string frame_id = marker->points3D.header.frame_id;
00665     tf::StampedTransform transform;
00666     ros::Time acquisition_time = last_msg_->header.stamp;
00667     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00668       return;
00669     }
00670     BOOST_FOREACH(geometry_msgs::Point p, marker->points3D.points) {
00671       tf::Point pt = transform.getOrigin();
00672       geometry_msgs::PointStamped pt_cam, pt_;
00673       pt_cam.header.frame_id = cam_model_.tfFrame();
00674       pt_cam.header.stamp = acquisition_time;
00675       pt_cam.point.x = pt.x();
00676       pt_cam.point.y = pt.y();
00677       pt_cam.point.z = pt.z();
00678       tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00679 
00680       cv::Point2d uv;
00681       tf::Stamped<tf::Point> pin, pout;
00682       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);
00683       tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00684       uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00685       cv::circle(draw_, uv, (marker->scale == 0 ? 3 : marker->scale) , *col_it, -1);
00686     }
00687   }
00688 
00689   void ImageView2::drawText3D(const image_view2::ImageMarker2::ConstPtr& marker,
00690                               std::vector<CvScalar>& colors,
00691                               std::vector<CvScalar>::iterator& col_it)
00692   {
00693     static std::map<std::string, int> tf_fail;
00694     std::string frame_id = marker->position3D.header.frame_id;
00695     tf::StampedTransform transform;
00696     ros::Time acquisition_time = last_msg_->header.stamp;
00697     if(!lookupTransformation(frame_id, acquisition_time, tf_fail, transform)) {
00698       return;
00699     }
00700     tf::Point pt = transform.getOrigin();
00701     geometry_msgs::PointStamped pt_cam, pt_;
00702     pt_cam.header.frame_id = cam_model_.tfFrame();
00703     pt_cam.header.stamp = acquisition_time;
00704     pt_cam.point.x = pt.x();
00705     pt_cam.point.y = pt.y();
00706     pt_cam.point.z = pt.z();
00707     tf_listener_.transformPoint(frame_id, pt_cam, pt_);
00708 
00709     cv::Point2d uv;
00710     tf::Stamped<tf::Point> pin, pout;
00711     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);
00712     tf_listener_.transformPoint(cam_model_.tfFrame(), pin, pout);
00713     uv = cam_model_.project3dToPixel(cv::Point3d(pout.x(), pout.y(), pout.z()));
00714     cv::Size text_size;
00715     int baseline;
00716     float scale = marker->scale;
00717     if ( scale == 0 ) scale = 1.0;
00718     text_size = cv::getTextSize(marker->text.c_str(), font_,
00719                                 scale, scale, &baseline);
00720     cv::Point origin = cv::Point(uv.x - text_size.width/2,
00721                                  uv.y - baseline-3);
00722     cv::putText(draw_, marker->text.c_str(), origin, font_, scale, CV_RGB(0,255,0),3);
00723   }
00724 
00725   void ImageView2::drawCircle3D(const image_view2::ImageMarker2::ConstPtr& marker,
00726                                 std::vector<CvScalar>& colors,
00727                                 std::vector<CvScalar>::iterator& col_it)
00728   {
00729     static std::map<std::string, int> tf_fail;
00730     std::string frame_id = marker->pose.header.frame_id;
00731     geometry_msgs::PoseStamped pose;
00732     ros::Time acquisition_time = last_msg_->header.stamp;
00733     ros::Duration timeout(tf_timeout_); // wait 0.5 sec
00734     try {
00735       ros::Time tm;
00736       tf_listener_.getLatestCommonTime(cam_model_.tfFrame(), frame_id, tm, NULL);
00737       tf_listener_.waitForTransform(cam_model_.tfFrame(), frame_id,
00738                                     acquisition_time, timeout);
00739       tf_listener_.transformPose(cam_model_.tfFrame(),
00740                                  acquisition_time, marker->pose, frame_id, pose);
00741       tf_fail[frame_id]=0;
00742     }
00743     catch (tf::TransformException& ex) {
00744       tf_fail[frame_id]++;
00745       if ( tf_fail[frame_id] < 5 ) {
00746         ROS_ERROR("[image_view2] TF exception:\n%s", ex.what());
00747       } else {
00748         ROS_DEBUG("[image_view2] TF exception:\n%s", ex.what());
00749       }
00750       return;
00751     }
00752 
00753     tf::Quaternion q;
00754     tf::quaternionMsgToTF(pose.pose.orientation, q);
00755     tf::Matrix3x3 rot = tf::Matrix3x3(q);
00756     double angle = (marker->arc == 0 ? 360.0 :marker->angle);
00757     double scale = (marker->scale == 0 ? DEFAULT_CIRCLE_SCALE : marker->scale);
00758     int N = 100;
00759     std::vector< std::vector<cv::Point2i> > ptss;
00760     std::vector<cv::Point2i> pts;
00761 
00762     for (int i=0; i<N; ++i) {
00763       double th = angle * i / N * TFSIMD_RADS_PER_DEG;
00764       tf::Vector3 v = rot * tf::Vector3(scale * tfCos(th), scale * tfSin(th),0);
00765       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()));
00766       pts.push_back(cv::Point2i((int)pt.x, (int)pt.y));
00767     }
00768     ptss.push_back(pts);
00769 
00770     cv::polylines(draw_, ptss, (marker->arc == 0 ? true : false), MsgToRGB(marker->outline_color), (marker->width == 0 ? DEFAULT_LINE_WIDTH : marker->width));
00771 
00772     if (marker->filled) {
00773       if(marker->arc != 0){
00774         cv::Point2d pt = cam_model_.project3dToPixel(cv::Point3d(pose.pose.position.x, pose.pose.position.y, pose.pose.position.z));
00775         pts.push_back(cv::Point2i((int)pt.x, (int)pt.y));
00776         ptss.clear();
00777         ptss.push_back(pts);
00778       }
00779       cv::fillPoly(draw_, ptss, MsgToRGB(marker->fill_color));
00780     }
00781   }
00782 
00783   void ImageView2::resolveLocalMarkerQueue()
00784   {
00785     {
00786       boost::mutex::scoped_lock lock(queue_mutex_);
00787 
00788       while ( ! marker_queue_.empty() ) {
00789         // remove marker by namespace and id
00790         V_ImageMarkerMessage::iterator new_msg = marker_queue_.begin();
00791         V_ImageMarkerMessage::iterator message_it = local_queue_.begin();
00792         for ( ; message_it < local_queue_.end(); ++message_it ) {
00793           if((*new_msg)->ns == (*message_it)->ns && (*new_msg)->id == (*message_it)->id)
00794             message_it = local_queue_.erase(message_it);
00795         }
00796         local_queue_.push_back(*new_msg);
00797         marker_queue_.erase(new_msg);
00798         // if action == REMOVE and id == -1, clear all marker_queue
00799         if ( (*new_msg)->action == image_view2::ImageMarker2::REMOVE &&
00800              (*new_msg)->id == -1 ) {
00801           local_queue_.clear();
00802         }
00803       }
00804     }
00805 
00806     // check lifetime and remove REMOVE-type marker msg
00807     for(V_ImageMarkerMessage::iterator it = local_queue_.begin(); it < local_queue_.end(); it++) {
00808       if((*it)->action == image_view2::ImageMarker2::REMOVE ||
00809          ((*it)->lifetime.toSec() != 0.0 && (*it)->lifetime.toSec() < ros::Time::now().toSec())) {
00810         it = local_queue_.erase(it);
00811       }
00812     }
00813   }
00814   
00815   void ImageView2::drawMarkers()
00816   {
00817     resolveLocalMarkerQueue();
00818     if ( !local_queue_.empty() )
00819     {
00820       V_ImageMarkerMessage::iterator message_it = local_queue_.begin();
00821       V_ImageMarkerMessage::iterator message_end = local_queue_.end();
00822       ROS_DEBUG("markers = %ld", local_queue_.size());
00823       //processMessage;
00824       for ( ; message_it != message_end; ++message_it )
00825       {
00826         image_view2::ImageMarker2::ConstPtr& marker = *message_it;
00827 
00828         ROS_DEBUG_STREAM("message type = " << marker->type << ", id " << marker->id);
00829 
00830         // outline colors
00831         std::vector<CvScalar> colors;
00832         BOOST_FOREACH(std_msgs::ColorRGBA color, marker->outline_colors) {
00833           colors.push_back(MsgToRGB(color));
00834         }
00835         if(colors.size() == 0) colors.push_back(DEFAULT_COLOR);
00836         std::vector<CvScalar>::iterator col_it = colors.begin();
00837 
00838         // check camera_info
00839         if( marker->type == image_view2::ImageMarker2::FRAMES ||
00840             marker->type == image_view2::ImageMarker2::LINE_STRIP3D ||
00841             marker->type == image_view2::ImageMarker2::LINE_LIST3D ||
00842             marker->type == image_view2::ImageMarker2::POLYGON3D ||
00843             marker->type == image_view2::ImageMarker2::POINTS3D ||
00844             marker->type == image_view2::ImageMarker2::TEXT3D ||
00845             marker->type == image_view2::ImageMarker2::CIRCLE3D) {
00846           {
00847             boost::mutex::scoped_lock lock(info_mutex_);
00848             if (!info_msg_) {
00849               ROS_WARN("[image_view2] camera_info could not found");
00850               continue;
00851             }
00852             cam_model_.fromCameraInfo(info_msg_);
00853           }
00854         }
00855         // CIRCLE, LINE_STRIP, LINE_LIST, POLYGON, POINTS
00856         switch ( marker->type ) {
00857         case image_view2::ImageMarker2::CIRCLE: {
00858           drawCircle(marker);
00859           break;
00860         }
00861         case image_view2::ImageMarker2::LINE_STRIP: {
00862           drawLineStrip(marker, colors, col_it);
00863           break;
00864         }
00865         case image_view2::ImageMarker2::LINE_LIST: {
00866           drawLineList(marker, colors, col_it);
00867           break;
00868         }
00869         case image_view2::ImageMarker2::POLYGON: {
00870           drawPolygon(marker, colors, col_it);
00871           break;
00872         }
00873         case image_view2::ImageMarker2::POINTS: {
00874           drawPoints(marker, colors, col_it);
00875           break;
00876         }
00877         case image_view2::ImageMarker2::FRAMES: {
00878           drawFrames(marker, colors, col_it);
00879           break;
00880         }
00881         case image_view2::ImageMarker2::TEXT: {
00882           drawText(marker, colors, col_it);
00883           break;
00884         }
00885         case image_view2::ImageMarker2::LINE_STRIP3D: {
00886           drawLineStrip3D(marker, colors, col_it);
00887           break;
00888         }
00889         case image_view2::ImageMarker2::LINE_LIST3D: {
00890           drawLineList3D(marker, colors, col_it);
00891           break;
00892         }
00893         case image_view2::ImageMarker2::POLYGON3D: {
00894           drawPolygon3D(marker, colors, col_it);
00895           break;
00896         }
00897         case image_view2::ImageMarker2::POINTS3D: {
00898           drawPoints3D(marker, colors, col_it);
00899           break;
00900         }
00901         case image_view2::ImageMarker2::TEXT3D: {
00902           drawText3D(marker, colors, col_it);
00903           break;
00904         }
00905         case image_view2::ImageMarker2::CIRCLE3D: {
00906           drawCircle3D(marker, colors, col_it);
00907           break;
00908         }
00909         default: {
00910           ROS_WARN("Undefined Marker type(%d)", marker->type);
00911           break;
00912         }
00913         }
00914       }
00915     }    
00916   }
00917 
00918   void ImageView2::drawInteraction()
00919   {
00920     if (mode_ == MODE_RECTANGLE) {
00921       cv::rectangle(draw_, cv::Point(window_selection_.x, window_selection_.y),
00922                     cv::Point(window_selection_.x + window_selection_.width,
00923                               window_selection_.y + window_selection_.height),
00924                     USER_ROI_COLOR, 3, 8, 0);
00925     }
00926     else if (mode_ == MODE_SERIES) {
00927       if (point_array_.size() > 1) {
00928         cv::Point2d from, to;
00929         from = point_array_[0];
00930         for (size_t i = 1; i < point_array_.size(); i++) {
00931           to = point_array_[i];
00932           cv::line(draw_, from, to, USER_ROI_COLOR, 2, 8, 0);
00933           from = to;
00934         }
00935       }
00936     }
00937     else if (mode_ == MODE_SELECT_FORE_AND_BACK) {
00938       boost::mutex::scoped_lock lock(point_array_mutex_);
00939       if (point_fg_array_.size() > 1) {
00940         cv::Point2d from, to;
00941         from = point_fg_array_[0];
00942         for (size_t i = 1; i < point_fg_array_.size(); i++) {
00943           to = point_fg_array_[i];
00944           cv::line(draw_, from, to, CV_RGB(255, 0, 0), 8, 8, 0);
00945           from = to;
00946         }
00947       }
00948       if (point_bg_array_.size() > 1) {
00949         cv::Point2d from, to;
00950         from = point_bg_array_[0];
00951         for (size_t i = 1; i < point_bg_array_.size(); i++) {
00952           to = point_bg_array_[i];
00953           cv::line(draw_, from, to, CV_RGB(0, 255, 0), 8, 8, 0);
00954           from = to;
00955         }
00956       }
00957     }
00958     else if (mode_ == MODE_SELECT_FORE_AND_BACK_RECT) {
00959       boost::mutex::scoped_lock lock(point_array_mutex_);
00960       if (rect_fg_.width != 0 && rect_fg_.height != 0) {
00961         cv::rectangle(draw_,
00962                       cv::Point(rect_fg_.x, rect_fg_.y),
00963                       cv::Point(rect_fg_.x + rect_fg_.width, rect_fg_.y + rect_fg_.height),
00964                       CV_RGB(255, 0, 0), 4);
00965       }
00966       if (rect_bg_.width != 0 && rect_bg_.height != 0) {
00967         cv::rectangle(draw_,
00968                       cv::Point(rect_bg_.x, rect_bg_.y),
00969                       cv::Point(rect_bg_.x + rect_bg_.width, rect_bg_.y + rect_bg_.height),
00970                       CV_RGB(0, 255, 0), 4);
00971       }
00972     }
00973     else if (mode_ == MODE_LINE) {
00974       boost::mutex::scoped_lock lock(line_point_mutex_);
00975       if (line_selected_) {
00976         cv::line(draw_, line_start_point_, line_end_point_, CV_RGB(0, 255, 0), 8, 8, 0);
00977       }
00978     }
00979     else if (mode_ == MODE_POLY) {
00980       boost::mutex::scoped_lock lock(poly_point_mutex_);
00981       if (poly_points_.size() > 0) {
00982         // draw selected points
00983         for (size_t i = 0; i < poly_points_.size() - 1; i++) {
00984           cv::line(draw_, poly_points_[i], poly_points_[i + 1], CV_RGB(255, 0, 0), 8, 8, 0);
00985         }
00986         // draw selecting points
00987         if (poly_selecting_done_) {
00988            cv::line(draw_, poly_points_[poly_points_.size() - 1],
00989                     poly_points_[0],
00990                     CV_RGB(255, 0, 0), 8, 8, 0);
00991         }
00992         else {
00993           cv::line(draw_, poly_points_[poly_points_.size() - 1],
00994                    poly_selecting_point_,
00995                    CV_RGB(0, 255, 0), 8, 8, 0);
00996         }
00997       }
00998     }
00999   }
01000 
01001   void ImageView2::drawInfo(ros::Time& before_rendering)
01002   {
01003     static ros::Time last_time;
01004     static std::string info_str_1, info_str_2;
01005     // update info_str_1, info_str_2 if possible
01006     if ( show_info_ && times_.size() > 0 && ( before_rendering.toSec() - last_time.toSec() > 2 ) ) {
01007       int n = times_.size();
01008       double mean = 0, rate = 1.0, std_dev = 0.0, max_delta, min_delta;
01009 
01010       std::for_each( times_.begin(), times_.end(), (mean += boost::lambda::_1) );
01011       mean /= n;
01012       rate /= mean;
01013 
01014       std::for_each( times_.begin(), times_.end(), (std_dev += (boost::lambda::_1 - mean)*(boost::lambda::_1 - mean) ) );
01015       std_dev = sqrt(std_dev/n);
01016       min_delta = *std::min_element(times_.begin(), times_.end());
01017       max_delta = *std::max_element(times_.begin(), times_.end());
01018 
01019       std::stringstream f1, f2;
01020       f1.precision(3); f1 << std::fixed;
01021       f2.precision(3); f2 << std::fixed;
01022       f1 << "" << image_sub_.getTopic() << " : rate:" << rate;
01023       f2 << "min:" << min_delta << "s max: " << max_delta << "s std_dev: " << std_dev << "s n: " << n;
01024       info_str_1 = f1.str();
01025       info_str_2 = f2.str();
01026       ROS_INFO_STREAM(info_str_1 + " " + info_str_2);
01027       times_.clear();
01028       last_time = before_rendering;
01029     }
01030     if (!info_str_1.empty() && !info_str_2.empty()) {
01031       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);
01032       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);
01033     }
01034   }
01035 
01036   void ImageView2::cropROI()
01037   {
01038     if (mode_ == MODE_RECTANGLE) {
01039       // publish rectangle cropped image
01040       cv::Rect screen_rect(cv::Point(window_selection_.x, window_selection_.y), cv::Point(window_selection_.x + window_selection_.width, window_selection_.y + window_selection_.height));
01041       cv::Mat cropped_img = original_image_(screen_rect);
01042       rectangle_img_pub_.publish(
01043         cv_bridge::CvImage(
01044           last_msg_->header,
01045           last_msg_->encoding,
01046           cropped_img).toImageMsg());
01047     }
01048   }
01049 
01050   void ImageView2::redraw()
01051   {
01052     if (original_image_.empty()) {
01053       ROS_WARN("no image is available yet");
01054       return;
01055     }
01056     ros::Time before_rendering = ros::Time::now();
01057     original_image_.copyTo(image_);
01058     // Draw Section
01059     if ( blurry_mode_ ) {
01060       draw_ = cv::Mat(image_.size(), image_.type(), CV_RGB(0,0,0));
01061     } else {
01062       draw_ = image_;
01063     }
01064     drawMarkers();
01065     drawInteraction();
01066     cropROI();
01067 
01068     if ( draw_grid_ ) drawGrid();
01069     if ( blurry_mode_ ) cv::addWeighted(image_, 0.9, draw_, 1.0, 0.0, image_);
01070     if ( use_window ) {
01071       if (show_info_) {
01072         drawInfo(before_rendering);
01073       }
01074     }
01075     cv_bridge::CvImage out_msg;
01076     out_msg.header   = last_msg_->header;
01077     out_msg.encoding = "bgr8";
01078     out_msg.image    = image_;
01079     image_pub_.publish(out_msg.toImageMsg());
01080     local_image_pub_.publish(out_msg.toImageMsg());
01081   }
01082   
01083   void ImageView2::createDistortGridImage()
01084   {
01085     distort_grid_mask_.setTo(cv::Scalar(0,0,0));
01086     cv::Mat distort_grid_mask(draw_.size(), CV_8UC1);
01087     distort_grid_mask.setTo(cv::Scalar(0));
01088     const float K = 341.0;
01089     float R_divier = (1.0/(draw_.cols/2)), center_x = distort_grid_mask.rows/2, center_y = distort_grid_mask.cols/2;
01090     for(int degree = -80; degree<=80; degree+=space_){
01091       double C = draw_.cols/2.0 * tan(degree * 3.14159265/180);
01092       for(float theta = -1.57; theta <= 1.57; theta+=0.001){
01093         double sin_phi = C * R_divier / tan(theta);
01094         if (sin_phi > 1.0 || sin_phi < -1.0)
01095           continue;
01096         int x1 = K * theta * sqrt(1-sin_phi * sin_phi) + center_x;
01097         int y1 = K * theta * sin_phi + center_y;
01098         int x2 = K * theta * sin_phi + center_x;
01099         int y2 = K * theta * sqrt(1-sin_phi * sin_phi) + center_y;
01100         cv::circle(distort_grid_mask, cvPoint(y1, x1), 2, 1, grid_thickness_);
01101         cv::circle(distort_grid_mask, cvPoint(y2, x2), 2, 1, grid_thickness_);
01102       }
01103     }
01104     cv::Mat red(draw_.size(), draw_.type(), CV_8UC3);
01105     red = cv::Scalar(grid_blue_, grid_green_, grid_red_);
01106     red.copyTo(distort_grid_mask_, distort_grid_mask);
01107   }
01108 
01109   void ImageView2::drawGrid()
01110   {
01111     if(fisheye_mode_){
01112       if(space_ != prev_space_ || prev_red_ != grid_red_
01113          || prev_green_ != grid_green_ || prev_blue_ != grid_blue_
01114          || prev_thickness_ != grid_thickness_){
01115         createDistortGridImage();
01116         prev_space_ = space_;
01117         prev_red_ = grid_red_;
01118         prev_green_ = grid_green_;
01119         prev_blue_ = grid_blue_;
01120         prev_thickness_ = grid_thickness_;
01121       }
01122       cv::add(draw_, distort_grid_mask_, draw_);
01123     }else{
01124       //Main Center Lines
01125       cv::Point2d p0 = cv::Point2d(0, last_msg_->height/2.0);
01126       cv::Point2d p1 = cv::Point2d(last_msg_->width, last_msg_->height/2.0);
01127       cv::line(draw_, p0, p1, CV_RGB(255,0,0), DEFAULT_LINE_WIDTH);
01128 
01129       cv::Point2d p2 = cv::Point2d(last_msg_->width/2.0, 0);
01130       cv::Point2d p3 = cv::Point2d(last_msg_->width/2.0, last_msg_->height);
01131       cv::line(draw_, p2, p3, CV_RGB(255,0,0), DEFAULT_LINE_WIDTH);
01132 
01133       for(int i = 1; i < div_u_ ;i ++){
01134         cv::Point2d u0 = cv::Point2d(0, last_msg_->height * i * 1.0 / div_u_);
01135         cv::Point2d u1 = cv::Point2d(last_msg_->width, last_msg_->height * i * 1.0 / div_u_);
01136         cv::line(draw_, u0, u1, CV_RGB(255,0,0), 1);
01137       }
01138 
01139       for(int i = 1; i < div_v_ ;i ++){
01140         cv::Point2d v0 = cv::Point2d(last_msg_->width * i * 1.0 / div_v_, 0);
01141         cv::Point2d v1 = cv::Point2d(last_msg_->width * i * 1.0 / div_v_, last_msg_->height);
01142         cv::line(draw_, v0, v1, CV_RGB(255,0,0), 1);
01143       }
01144     }
01145   }
01146 
01147   void ImageView2::imageCb(const sensor_msgs::ImageConstPtr& msg)
01148   {
01149     if (msg->width == 0 && msg->height == 0) {
01150       ROS_DEBUG("invalid image");
01151       return;
01152     }
01153     static int count = 0;
01154     if (count < skip_draw_rate_) {
01155       count++;
01156       return;
01157     }
01158     else {
01159       count = 0;
01160     }
01161     static ros::Time old_time;
01162     times_.push_front(ros::Time::now().toSec() - old_time.toSec());
01163     old_time = ros::Time::now();
01164 
01165     if(old_time.toSec() - ros::Time::now().toSec() > 0) {
01166       ROS_WARN("TF Cleared for old time");
01167     }
01168     {
01169       boost::mutex::scoped_lock lock(image_mutex_);
01170       if (msg->encoding.find("bayer") != std::string::npos) {
01171         original_image_ = cv::Mat(msg->height, msg->width, CV_8UC1,
01172                                   const_cast<uint8_t*>(&msg->data[0]), msg->step);
01173       } else if (msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1) {
01174         // standardize pixel values to 0-255 to visualize depth image
01175         cv::Mat input_image = cv_bridge::toCvCopy(msg)->image;
01176         double min, max;
01177         cv::minMaxIdx(input_image, &min, &max);
01178         cv::convertScaleAbs(input_image, original_image_, 255 / max);
01179       } else {
01180         try {
01181           original_image_ = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8)->image;
01182         } catch (cv_bridge::Exception& e) {
01183           ROS_ERROR("Unable to convert %s image to bgr8", msg->encoding.c_str());
01184           return;
01185         }
01186       }
01187       // Hang on to message pointer for sake of mouseCb
01188       last_msg_ = msg;
01189       redraw();
01190     }
01191     if (region_continuous_publish_ &&  continuous_ready_) {
01192       publishMouseInteractionResult();
01193     }
01194   }
01195 
01196   void ImageView2::drawImage() {
01197     if (image_.rows > 0 && image_.cols > 0) {
01198       redraw();
01199     }
01200   }
01201 
01202   void ImageView2::addPoint(int x, int y)
01203   {
01204     cv::Point2d p;
01205     p.x = x;
01206     p.y = y;
01207     {
01208       boost::mutex::scoped_lock lock(point_array_mutex_);
01209       point_array_.push_back(p);
01210     }
01211   }
01212 
01213   void ImageView2::setRegionWindowPoint(int x, int y)
01214   {
01215     boost::mutex::scoped_lock lock(point_array_mutex_);
01216     ROS_DEBUG("setRegionWindowPoint(%d, %d)", x, y);
01217     if (selecting_fg_) {
01218       rect_fg_.x = x;
01219       rect_fg_.y = y;
01220       rect_fg_.width = 0;
01221       rect_fg_.height = 0;
01222     }
01223     else {
01224       rect_bg_.x = x;
01225       rect_bg_.y = y;
01226       rect_bg_.width = 0;
01227       rect_bg_.height = 0;
01228     }
01229   }
01230 
01231   void ImageView2::updateRegionWindowSize(int x, int y)
01232   {
01233     ROS_DEBUG("updateRegionWindowPoint");
01234     boost::mutex::scoped_lock lock(point_array_mutex_);
01235     if (selecting_fg_) {
01236       rect_fg_.width = x - rect_fg_.x;
01237       rect_fg_.height = y - rect_fg_.y;
01238     }
01239     else {
01240       rect_bg_.width = x - rect_bg_.x;
01241       rect_bg_.height = y - rect_bg_.y;
01242     }
01243   }
01244   
01245   void ImageView2::addRegionPoint(int x, int y)
01246   {
01247     cv::Point2d p;
01248     p.x = x;
01249     p.y = y;
01250     {
01251       boost::mutex::scoped_lock lock(point_array_mutex_);
01252       if (selecting_fg_) {
01253         point_fg_array_.push_back(p);
01254       }
01255       else {
01256         point_bg_array_.push_back(p);
01257       }
01258     }
01259   }
01260 
01261   void ImageView2::clearPointArray()
01262   {
01263     boost::mutex::scoped_lock lock(point_array_mutex_);
01264     point_fg_array_.clear();
01265     point_bg_array_.clear();
01266     point_array_.clear();
01267   }
01268 
01269   void ImageView2::publishPointArray()
01270   {
01271     pcl::PointCloud<pcl::PointXY> pcl_cloud;
01272     for (size_t i = 0; i < point_array_.size(); i++) {
01273       pcl::PointXY p;
01274       p.x = point_array_[i].x;
01275       p.y = point_array_[i].y;
01276       pcl_cloud.points.push_back(p);
01277     }
01278     sensor_msgs::PointCloud2::Ptr ros_cloud(new sensor_msgs::PointCloud2);
01279     pcl::toROSMsg(pcl_cloud, *ros_cloud);
01280     ros_cloud->header.stamp = ros::Time::now();
01281     
01282     point_array_pub_.publish(ros_cloud);
01283   }
01284     
01285   
01286   void ImageView2::setMode(KEY_MODE mode)
01287   {
01288     mode_ = mode;
01289   }
01290 
01291   ImageView2::KEY_MODE ImageView2::getMode()
01292   {
01293     return mode_;
01294   }
01295 
01296   bool ImageView2::toggleSelection()
01297   {
01298     boost::mutex::scoped_lock lock(point_array_mutex_);
01299     selecting_fg_ = !selecting_fg_;
01300     return selecting_fg_;
01301   }
01302 
01303   void ImageView2::pointArrayToMask(std::vector<cv::Point2d>& points,
01304                                     cv::Mat& mask)
01305   {
01306     cv::Point2d from, to;
01307     if (points.size() > 1) {
01308       from = points[0];
01309       for (size_t i = 1; i < points.size(); i++) {
01310         to = points[i];
01311         cv::line(mask, from, to, cv::Scalar(255), 8, 8, 0);
01312         from = to;
01313       }
01314     }
01315   }
01316 
01317   void ImageView2::publishMonoImage(ros::Publisher& pub,
01318                                     cv::Mat& image,
01319                                     const std_msgs::Header& header)
01320   {
01321     cv_bridge::CvImage image_bridge(
01322       header, sensor_msgs::image_encodings::MONO8, image);
01323     pub.publish(image_bridge.toImageMsg());
01324   }
01325   
01326   void ImageView2::publishForegroundBackgroundMask()
01327   {
01328     boost::mutex::scoped_lock lock(image_mutex_);
01329     boost::mutex::scoped_lock lock2(point_array_mutex_);
01330     cv::Mat foreground_mask
01331       = cv::Mat::zeros(last_msg_->height, last_msg_->width, CV_8UC1);
01332     cv::Mat background_mask
01333       = cv::Mat::zeros(last_msg_->height, last_msg_->width, CV_8UC1);
01334     if (getMode() == MODE_SELECT_FORE_AND_BACK) {
01335       pointArrayToMask(point_fg_array_, foreground_mask);
01336       pointArrayToMask(point_bg_array_, background_mask);
01337     }
01338     else if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01339       cv::rectangle(foreground_mask, rect_fg_, cv::Scalar(255), CV_FILLED);
01340       cv::rectangle(background_mask, rect_bg_, cv::Scalar(255), CV_FILLED);
01341     }
01342     publishMonoImage(foreground_mask_pub_, foreground_mask, last_msg_->header);
01343     publishMonoImage(background_mask_pub_, background_mask, last_msg_->header);
01344     publishRectFromMaskImage(foreground_rect_pub_, foreground_mask, last_msg_->header);
01345     publishRectFromMaskImage(background_rect_pub_, background_mask, last_msg_->header);
01346   }
01347   
01348   void ImageView2::publishRectFromMaskImage(
01349     ros::Publisher& pub,
01350     cv::Mat& image,
01351     const std_msgs::Header& header)
01352   {
01353     int min_x = image.cols;
01354     int min_y = image.rows;
01355     int max_x = 0;
01356     int max_y = 0;
01357     for (int j = 0; j < image.rows; j++) {
01358       for (int i = 0; i < image.cols; i++) {
01359         if (image.at<uchar>(j, i) != 0) {
01360           min_x = std::min(min_x, i);
01361           min_y = std::min(min_y, j);
01362           max_x = std::max(max_x, i);
01363           max_y = std::max(max_y, j);
01364         }
01365       }
01366     }
01367     geometry_msgs::PolygonStamped poly;
01368     poly.header = header;
01369     geometry_msgs::Point32 min_pt, max_pt;
01370     min_pt.x = min_x; 
01371     min_pt.y = min_y;
01372     max_pt.x = max_x; 
01373     max_pt.y = max_y;
01374     poly.polygon.points.push_back(min_pt);
01375     poly.polygon.points.push_back(max_pt);
01376     pub.publish(poly);
01377   }
01378 
01379   void ImageView2::publishLinePoints()
01380   {
01381     boost::mutex::scoped_lock lock(line_point_mutex_);
01382     geometry_msgs::PolygonStamped ros_line;
01383     ros_line.header = last_msg_->header;
01384     geometry_msgs::Point32 ros_start_point, ros_end_point;
01385     ros_start_point.x = line_start_point_.x;
01386     ros_start_point.y = line_start_point_.y;
01387     ros_end_point.x = line_end_point_.x;
01388     ros_end_point.y = line_end_point_.y;
01389     ros_line.polygon.points.push_back(ros_start_point);
01390     ros_line.polygon.points.push_back(ros_end_point);
01391     line_pub_.publish(ros_line);
01392   }
01393   
01394   void ImageView2::publishMouseInteractionResult()
01395   {
01396     if (getMode() == MODE_SERIES) {
01397       publishPointArray();
01398     }
01399     else if (getMode() == MODE_SELECT_FORE_AND_BACK ||
01400              getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01401       publishForegroundBackgroundMask();
01402     }
01403     else if (getMode() == MODE_LINE) {
01404       publishLinePoints();
01405     }
01406     else {
01407       cv::Point2f Pt_1(window_selection_.x, window_selection_.y);
01408       cv::Point2f Pt(button_up_pos_);
01409       std::cout << "PT_1" << Pt_1 << std::endl;
01410       std::cout << "Pt" << Pt << std::endl;
01411       if (!isValidMovement(Pt_1, Pt)) {
01412         geometry_msgs::PointStamped screen_msg;
01413         screen_msg.point.x = window_selection_.x * resize_x_;
01414         screen_msg.point.y = window_selection_.y * resize_y_;
01415         screen_msg.point.z = 0;
01416         screen_msg.header.stamp = last_msg_->header.stamp;
01417         ROS_INFO("Publish screen point %s (%f %f)", point_pub_.getTopic().c_str(), screen_msg.point.x, screen_msg.point.y);
01418         point_pub_.publish(screen_msg);
01419       } else {
01420         geometry_msgs::PolygonStamped screen_msg;
01421         screen_msg.polygon.points.resize(2);
01422         screen_msg.polygon.points[0].x = window_selection_.x * resize_x_;
01423         screen_msg.polygon.points[0].y = window_selection_.y * resize_y_;
01424         screen_msg.polygon.points[1].x = (window_selection_.x + window_selection_.width) * resize_x_;
01425         screen_msg.polygon.points[1].y = (window_selection_.y + window_selection_.height) * resize_y_;
01426         screen_msg.header = last_msg_->header;
01427         ROS_INFO("Publish rectangle point %s (%f %f %f %f)", rectangle_pub_.getTopic().c_str(),
01428                  screen_msg.polygon.points[0].x, screen_msg.polygon.points[0].y,
01429                  screen_msg.polygon.points[1].x, screen_msg.polygon.points[1].y);
01430         rectangle_pub_.publish(screen_msg);
01431         continuous_ready_ = true;
01432       }
01433     }
01434   }
01435     
01436   
01437   bool ImageView2::isValidMovement(const cv::Point2f& start_point,
01438                                    const cv::Point2f& end_point)
01439   {
01440     double dist_px = cv::norm(cv::Mat(start_point), cv::Mat(end_point));
01441     return dist_px > 3.0;
01442   }
01443 
01444   void ImageView2::updateLineStartPoint(cv::Point p)
01445   {
01446     boost::mutex::scoped_lock lock(line_point_mutex_);
01447     line_start_point_ = p;
01448   }
01449 
01450   void ImageView2::updateLineEndPoint(cv::Point p)
01451   {
01452     boost::mutex::scoped_lock lock(line_point_mutex_);
01453     line_end_point_ = p;
01454   }
01455 
01456   cv::Point ImageView2::getLineStartPoint()
01457   {
01458     boost::mutex::scoped_lock lock(line_point_mutex_);
01459     return cv::Point(line_start_point_);
01460   }
01461   
01462   cv::Point ImageView2::getLineEndPoint()
01463   {
01464     boost::mutex::scoped_lock lock(line_point_mutex_);
01465     return cv::Point(line_end_point_);
01466   }
01467 
01468   void ImageView2::updateLinePoint(cv::Point p)
01469   {
01470     
01471     if (isSelectingLineStartPoint()) {
01472       updateLineStartPoint(p);
01473       updateLineEndPoint(p);
01474     }
01475     else {
01476       updateLineEndPoint(p);
01477     }
01478     {
01479       boost::mutex::scoped_lock lock(line_point_mutex_);
01480       line_select_start_point_ = !line_select_start_point_;
01481       line_selected_ = true;
01482     }
01483   }
01484 
01485   bool ImageView2::isSelectingLineStartPoint()
01486   {
01487     boost::mutex::scoped_lock lock(line_point_mutex_);
01488     return line_select_start_point_;
01489   }
01490   
01491   void ImageView2::processLeftButtonDown(int x, int y)
01492   {
01493     ROS_DEBUG("processLeftButtonDown");
01494     left_button_clicked_ = true;
01495     continuous_ready_ = false;
01496     window_selection_.x = x;
01497     window_selection_.y = y;
01498     window_selection_.width = window_selection_.height = 0;
01499     if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01500       setRegionWindowPoint(x, y);
01501     }
01502     if (getMode() == MODE_LINE) {
01503       continuous_ready_ = false;
01504     }
01505   }
01506 
01507   void ImageView2::processMove(int x, int y)
01508   {
01509     if (left_button_clicked_) {
01510       cv::Point2f Pt_1(window_selection_.x, window_selection_.y);
01511       cv::Point2f Pt(x, y);
01512       if (isValidMovement(Pt_1, Pt)) {
01513         if (getMode() == MODE_RECTANGLE) {
01514           window_selection_.width  = x - window_selection_.x;
01515           window_selection_.height = y - window_selection_.y;
01516         }
01517         else if (getMode() == MODE_SERIES) {
01518           addPoint(x, y);
01519         }
01520         else if (getMode() == MODE_SELECT_FORE_AND_BACK) {
01521           addRegionPoint(x, y);
01522         }
01523         else if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01524           updateRegionWindowSize(x, y);
01525         }
01526       }
01527       // publish the points
01528       geometry_msgs::PointStamped move_point;
01529       move_point.header.stamp = ros::Time::now();
01530       move_point.point.x = x;
01531       move_point.point.y = y;
01532       move_point.point.z = 0;
01533       move_point_pub_.publish(move_point);
01534     }
01535     else {
01536       if (getMode() == MODE_LINE) {
01537         if (!isSelectingLineStartPoint()) {
01538           updateLineEndPoint(cv::Point(x, y));
01539         }
01540       }
01541       else if (getMode() == MODE_POLY) {
01542         updatePolySelectingPoint(cv::Point(x, y));
01543       }
01544     }
01545   }
01546 
01547   void ImageView2::processLeftButtonUp(int x, int y)
01548   {
01549     if (!left_button_clicked_) {
01550       return;
01551     }
01552     if (getMode() == MODE_SERIES) {
01553       publishMouseInteractionResult();
01554       clearPointArray();
01555     }
01556     else if (getMode() == MODE_SELECT_FORE_AND_BACK ||
01557              getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01558       bool fgp = toggleSelection();
01559       if (fgp) {
01560         publishMouseInteractionResult();
01561         continuous_ready_ = true;
01562         //clearPointArray();
01563       }
01564     }
01565     else if (getMode() == MODE_RECTANGLE) {
01566       // store x and y
01567       button_up_pos_ = cv::Point2f(x, y);
01568       publishMouseInteractionResult();
01569     }
01570     else if (getMode() == MODE_LINE) {
01571       updateLinePoint(cv::Point(x, y));
01572       if (isSelectingLineStartPoint()) {
01573         publishMouseInteractionResult();
01574         continuous_ready_ = true;
01575       }
01576     }
01577     else if (getMode() == MODE_POLY) {
01578       if (isPolySelectingFirstTime()) {
01579         continuous_ready_ = false;
01580         clearPolyPoints();
01581       }
01582       updatePolyPoint(cv::Point(x, y));
01583     }
01584     left_button_clicked_ = false;
01585   }
01586   
01587   void ImageView2::updatePolyPoint(cv::Point p)
01588   {
01589     boost::mutex::scoped_lock lock(poly_point_mutex_);
01590     poly_points_.push_back(p);
01591   }
01592 
01593   void ImageView2::publishPolyPoints()
01594   {
01595     boost::mutex::scoped_lock lock(poly_point_mutex_);
01596     geometry_msgs::PolygonStamped poly;
01597     poly.header = last_msg_->header;
01598     for (size_t i = 0; i < poly_points_.size(); i++) {
01599       geometry_msgs::Point32 p;
01600       p.x = poly_points_[i].x;
01601       p.y = poly_points_[i].y;
01602       p.z = 0;
01603       poly.polygon.points.push_back(p);
01604     }
01605     poly_pub_.publish(poly);
01606   }
01607 
01608   void ImageView2::updatePolySelectingPoint(cv::Point p)
01609   {
01610     boost::mutex::scoped_lock lock(poly_point_mutex_);
01611     poly_selecting_point_ = p;
01612   }
01613 
01614   void ImageView2::finishSelectingPoly()
01615   {
01616     boost::mutex::scoped_lock lock(poly_point_mutex_);
01617     poly_selecting_done_ = true;
01618   }
01619 
01620   bool ImageView2::isPolySelectingFirstTime()
01621   {
01622     boost::mutex::scoped_lock lock(poly_point_mutex_);
01623     return poly_selecting_done_;
01624   }
01625 
01626   void ImageView2::clearPolyPoints()
01627   {
01628     boost::mutex::scoped_lock lock(poly_point_mutex_);
01629     poly_selecting_done_ = false;
01630     poly_points_.clear();
01631   }
01632 
01633   void ImageView2::processMouseEvent(int event, int x, int y, int flags, void* param)
01634   {
01635     checkMousePos(x, y);
01636     switch (event){
01637     case CV_EVENT_MOUSEMOVE: {
01638       processMove(x, y);
01639       break;
01640     }
01641     case CV_EVENT_LBUTTONDOWN:  // click
01642       processLeftButtonDown(x, y);
01643       break;
01644     case CV_EVENT_LBUTTONUP:
01645       processLeftButtonUp(x, y);
01646       break;
01647     case CV_EVENT_RBUTTONDOWN:
01648     {
01649       if (getMode() == MODE_POLY) {
01650         // close the polygon
01651         finishSelectingPoly();
01652         publishPolyPoints();
01653         continuous_ready_ = true;
01654       }
01655       else {
01656         boost::mutex::scoped_lock lock(image_mutex_);
01657         if (!image_.empty()) {
01658           std::string filename = (filename_format_ % count_).str();
01659           cv::imwrite(filename.c_str(), image_);
01660           ROS_INFO("Saved image %s", filename.c_str());
01661           count_++;
01662         } else {
01663           ROS_WARN("Couldn't save image, no data!");
01664         }
01665       }
01666       break;
01667     }
01668     }
01669     {
01670       boost::mutex::scoped_lock lock2(image_mutex_);
01671       drawImage();
01672     }
01673     return;
01674   }
01675   
01676   void ImageView2::mouseCb(int event, int x, int y, int flags, void* param)
01677   {
01678     ROS_DEBUG("mouseCB");
01679     ImageView2 *iv = (ImageView2*)param;
01680     iv->processMouseEvent(event, x, y, flags, param);
01681     return;
01682   }
01683 
01684   void ImageView2::pressKey(int key)
01685   {
01686     if (key != -1) {
01687       switch (key) {
01688       case 27: {
01689         resetInteraction();
01690         break;
01691       }
01692       }
01693     }
01694   }
01695 
01696   void ImageView2::showImage()
01697   {
01698     if (use_window) {
01699       if (!window_initialized_) {
01700         cv::namedWindow(window_name_.c_str(), autosize_ ? CV_WINDOW_AUTOSIZE : 0);
01701         cv::setMouseCallback(window_name_.c_str(), &ImageView2::mouseCb, this);
01702         window_initialized_ = false;
01703       }
01704       if(!image_.empty()) {
01705         cv::imshow(window_name_.c_str(), image_);
01706         cv::waitKey(3);
01707       }
01708     }
01709   }
01710 
01711   void ImageView2::checkMousePos(int& x, int& y)
01712   {
01713     if (last_msg_) {
01714       x = std::max(std::min(x, (int)last_msg_->width), 0);
01715       y = std::max(std::min(y, (int)last_msg_->height), 0);
01716     }
01717   }
01718   void ImageView2::resetInteraction()
01719   {
01720     if (getMode() == MODE_SELECT_FORE_AND_BACK) {
01721       boost::mutex::scoped_lock lock(point_array_mutex_);
01722       point_fg_array_.clear();
01723       point_bg_array_.clear();
01724       selecting_fg_ = true;
01725     }
01726     else if (getMode() == MODE_SELECT_FORE_AND_BACK_RECT) {
01727       boost::mutex::scoped_lock lock(point_array_mutex_);
01728       rect_fg_.width = rect_fg_.height = 0;
01729       rect_bg_.width = rect_bg_.height = 0;
01730       selecting_fg_ = true;
01731     }
01732     else if (getMode() == MODE_LINE) {
01733       boost::mutex::scoped_lock lock(line_point_mutex_);
01734       line_select_start_point_ = true;
01735       line_selected_ = false;
01736       continuous_ready_ = false;
01737     }
01738     else if (getMode() == MODE_RECTANGLE) {
01739       button_up_pos_ = cv::Point2f(0, 0);
01740       window_selection_.width = 0;
01741       window_selection_.height = 0;
01742     }
01743     else if (getMode() == MODE_POLY) {
01744       clearPolyPoints();
01745     }
01746   }
01747 
01748   bool ImageView2::rectangleModeServiceCallback(
01749       std_srvs::EmptyRequest& req,
01750       std_srvs::EmptyResponse& res)
01751   {
01752     resetInteraction();
01753     setMode(MODE_RECTANGLE);
01754     resetInteraction();
01755     return true;
01756   }
01757   
01758   bool ImageView2::seriesModeServiceCallback(
01759       std_srvs::EmptyRequest& req,
01760       std_srvs::EmptyResponse& res)
01761   {
01762     resetInteraction();
01763     setMode(MODE_SERIES);
01764     resetInteraction();
01765     return true;
01766   }
01767   
01768   bool ImageView2::grabcutModeServiceCallback(
01769       std_srvs::EmptyRequest& req,
01770       std_srvs::EmptyResponse& res)
01771   {
01772     resetInteraction();
01773     setMode(MODE_SELECT_FORE_AND_BACK);
01774     resetInteraction();
01775     return true;
01776   }
01777   
01778   bool ImageView2::grabcutRectModeServiceCallback(
01779       std_srvs::EmptyRequest& req,
01780       std_srvs::EmptyResponse& res)
01781   {
01782     resetInteraction();
01783     setMode(MODE_SELECT_FORE_AND_BACK_RECT);
01784     resetInteraction();
01785     return true;
01786   }
01787   
01788   bool ImageView2::lineModeServiceCallback(
01789     std_srvs::EmptyRequest& req,
01790     std_srvs::EmptyResponse& res)
01791   {
01792     resetInteraction();
01793     setMode(MODE_LINE);
01794     resetInteraction();
01795     return true;
01796   }
01797 
01798   bool ImageView2::polyModeServiceCallback(
01799     std_srvs::EmptyRequest& req,
01800     std_srvs::EmptyResponse& res)
01801   {
01802     resetInteraction();
01803     setMode(MODE_POLY);
01804     resetInteraction();
01805     return true;
01806   }
01807 
01808   bool ImageView2::noneModeServiceCallback(
01809     std_srvs::EmptyRequest& req,
01810     std_srvs::EmptyResponse& res)
01811   {
01812     resetInteraction();
01813     setMode(MODE_NONE);
01814     resetInteraction();
01815     return true;
01816   }
01817   
01818   bool ImageView2::changeModeServiceCallback(
01819     image_view2::ChangeModeRequest& req,
01820     image_view2::ChangeModeResponse& res)
01821   {
01822     resetInteraction();
01823     KEY_MODE next_mode = stringToMode(req.mode);
01824     setMode(next_mode);
01825     resetInteraction();
01826     return true;
01827   }
01828 
01829   ImageView2::KEY_MODE ImageView2::stringToMode(const std::string& interaction_mode)
01830   {
01831     if (interaction_mode == "rectangle") {
01832       return MODE_RECTANGLE;
01833     }
01834     else if (interaction_mode == "freeform" ||
01835              interaction_mode == "series") {
01836       return MODE_SERIES;
01837     }
01838     else if (interaction_mode == "grabcut") {
01839       return MODE_SELECT_FORE_AND_BACK;
01840     }
01841     else if (interaction_mode == "grabcut_rect") {
01842       return MODE_SELECT_FORE_AND_BACK_RECT;
01843           }
01844     else if (interaction_mode == "line") {
01845       return MODE_LINE;
01846     }
01847     else if (interaction_mode == "poly") {
01848       return MODE_POLY;
01849     }
01850     else if (interaction_mode == "none") {
01851       return MODE_NONE;
01852     }
01853     else {
01854       throw std::string("Unknown mode");
01855     }
01856   }
01857 
01858   void ImageView2::eventCb(
01859     const image_view2::MouseEvent::ConstPtr& event_msg)
01860   {
01861     //ROS_INFO("eventCb");
01862     if (event_msg->type == image_view2::MouseEvent::KEY_PRESSED) {
01863       pressKey(event_msg->key);
01864     }
01865     else {
01866       // scale x, y according to width/height
01867       int x, y;
01868       {
01869         boost::mutex::scoped_lock lock(image_mutex_);
01870         if (!last_msg_) {
01871           ROS_WARN("Image is not yet available");
01872           return;
01873         }
01874         x = ((float)last_msg_->width / event_msg->width) * event_msg->x;
01875         y = ((float)last_msg_->height / event_msg->height) * event_msg->y;
01876       }
01877       // scale
01878       if (event_msg->type == image_view2::MouseEvent::MOUSE_LEFT_UP) {
01879         //ROS_INFO("mouse_left_up");
01880         processMouseEvent(CV_EVENT_LBUTTONUP, x, y, 0, NULL);
01881       }
01882       else if (event_msg->type == image_view2::MouseEvent::MOUSE_LEFT_DOWN) {
01883         //ROS_INFO("mouse_left_down");
01884         processMouseEvent(CV_EVENT_LBUTTONDOWN, x, y, 0, NULL);
01885       }
01886       else if (event_msg->type == image_view2::MouseEvent::MOUSE_MOVE) {
01887         //ROS_INFO("mouse_move");
01888         processMouseEvent(CV_EVENT_MOUSEMOVE, x, y, 0, NULL);
01889       }
01890       else if (event_msg->type == image_view2::MouseEvent::MOUSE_RIGHT_DOWN) {
01891         //ROS_INFO("mouse_right_down");
01892         processMouseEvent(CV_EVENT_RBUTTONDOWN, x, y, 0, NULL);
01893       }
01894     }
01895   }
01896 }
01897 
01898 


image_view2
Author(s): Kei Okada
autogenerated on Fri Sep 8 2017 03:38:44