00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
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
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_);
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
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
00352 cv::Point2d uv0, uv1, uv2;
00353 tf::Stamped<tf::Point> pin, pout;
00354
00355
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
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
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
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
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
00427 ros::Duration timeout(tf_timeout_);
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_);
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
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
00723 if ( (*new_msg)->action == image_view2::ImageMarker2::REMOVE &&
00724 (*new_msg)->id == -1 ) {
00725 local_queue_.clear();
00726 }
00727 }
00728 }
00729
00730
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
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
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
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
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
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
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
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
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
01249 }
01250 }
01251 else if (getMode() == MODE_RECTANGLE) {
01252
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:
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
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
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
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 }