image_view.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011, Dirk Thomas, TU Darmstadt
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following
13  * disclaimer in the documentation and/or other materials provided
14  * with the distribution.
15  * * Neither the name of the TU Darmstadt nor the names of its
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
25  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
29  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
34 
36 #include <ros/master.h>
38 
39 #include <cv_bridge/cv_bridge.h>
40 #include <opencv2/imgproc/imgproc.hpp>
41 
42 #include <QFileDialog>
43 #include <QMessageBox>
44 #include <QPainter>
45 
46 namespace rqt_image_view {
47 
49  : rqt_gui_cpp::Plugin()
50  , widget_(0)
51  , num_gridlines_(0)
52  , rotate_state_(ROTATE_0)
53 {
54  setObjectName("ImageView");
55 }
56 
58 {
59  widget_ = new QWidget();
60  ui_.setupUi(widget_);
61 
62  if (context.serialNumber() > 1)
63  {
64  widget_->setWindowTitle(widget_->windowTitle() + " (" + QString::number(context.serialNumber()) + ")");
65  }
66  context.addWidget(widget_);
67 
69  ui_.color_scheme_combo_box->setCurrentIndex(ui_.color_scheme_combo_box->findText("Gray"));
70 
72  ui_.topics_combo_box->setCurrentIndex(ui_.topics_combo_box->findText(""));
73  connect(ui_.topics_combo_box, SIGNAL(currentIndexChanged(int)), this, SLOT(onTopicChanged(int)));
74 
75  ui_.refresh_topics_push_button->setIcon(QIcon::fromTheme("view-refresh"));
76  connect(ui_.refresh_topics_push_button, SIGNAL(pressed()), this, SLOT(updateTopicList()));
77 
78  ui_.zoom_1_push_button->setIcon(QIcon::fromTheme("zoom-original"));
79  connect(ui_.zoom_1_push_button, SIGNAL(toggled(bool)), this, SLOT(onZoom1(bool)));
80 
81  connect(ui_.dynamic_range_check_box, SIGNAL(toggled(bool)), this, SLOT(onDynamicRange(bool)));
82 
83  ui_.save_as_image_push_button->setIcon(QIcon::fromTheme("document-save-as"));
84  connect(ui_.save_as_image_push_button, SIGNAL(pressed()), this, SLOT(saveImage()));
85 
86  connect(ui_.num_gridlines_spin_box, SIGNAL(valueChanged(int)), this, SLOT(updateNumGridlines()));
87 
88  // set topic name if passed in as argument
89  const QStringList& argv = context.argv();
90  if (!argv.empty()) {
91  arg_topic_name = argv[0];
93  }
94  pub_topic_custom_ = false;
95 
96  ui_.image_frame->setOuterLayout(ui_.image_layout);
97 
98  QRegExp rx("([a-zA-Z/][a-zA-Z0-9_/]*)?"); //see http://www.ros.org/wiki/ROS/Concepts#Names.Valid_Names (but also accept an empty field)
99  ui_.publish_click_location_topic_line_edit->setValidator(new QRegExpValidator(rx, this));
100  connect(ui_.publish_click_location_check_box, SIGNAL(toggled(bool)), this, SLOT(onMousePublish(bool)));
101  connect(ui_.image_frame, SIGNAL(mouseLeft(int, int)), this, SLOT(onMouseLeft(int, int)));
102  connect(ui_.publish_click_location_topic_line_edit, SIGNAL(editingFinished()), this, SLOT(onPubTopicChanged()));
103 
104  connect(ui_.smooth_image_check_box, SIGNAL(toggled(bool)), ui_.image_frame, SLOT(onSmoothImageChanged(bool)));
105 
106  connect(ui_.rotate_left_push_button, SIGNAL(clicked(bool)), this, SLOT(onRotateLeft()));
107  connect(ui_.rotate_right_push_button, SIGNAL(clicked(bool)), this, SLOT(onRotateRight()));
108 
109  // Make sure we have enough space for "XXX °"
110  ui_.rotate_label->setMinimumWidth(
111  ui_.rotate_label->fontMetrics().width("XXX°")
112  );
113 
114  hide_toolbar_action_ = new QAction(tr("Hide toolbar"), this);
115  hide_toolbar_action_->setCheckable(true);
116  ui_.image_frame->addAction(hide_toolbar_action_);
117  connect(hide_toolbar_action_, SIGNAL(toggled(bool)), this, SLOT(onHideToolbarChanged(bool)));
118 }
119 
121 {
124 }
125 
126 void ImageView::saveSettings(qt_gui_cpp::Settings& plugin_settings, qt_gui_cpp::Settings& instance_settings) const
127 {
128  QString topic = ui_.topics_combo_box->currentText();
129  //qDebug("ImageView::saveSettings() topic '%s'", topic.toStdString().c_str());
130  instance_settings.setValue("topic", topic);
131  instance_settings.setValue("zoom1", ui_.zoom_1_push_button->isChecked());
132  instance_settings.setValue("dynamic_range", ui_.dynamic_range_check_box->isChecked());
133  instance_settings.setValue("max_range", ui_.max_range_double_spin_box->value());
134  instance_settings.setValue("publish_click_location", ui_.publish_click_location_check_box->isChecked());
135  instance_settings.setValue("mouse_pub_topic", ui_.publish_click_location_topic_line_edit->text());
136  instance_settings.setValue("toolbar_hidden", hide_toolbar_action_->isChecked());
137  instance_settings.setValue("num_gridlines", ui_.num_gridlines_spin_box->value());
138  instance_settings.setValue("smooth_image", ui_.smooth_image_check_box->isChecked());
139  instance_settings.setValue("rotate", rotate_state_);
140 }
141 
142 void ImageView::restoreSettings(const qt_gui_cpp::Settings& plugin_settings, const qt_gui_cpp::Settings& instance_settings)
143 {
144  bool zoom1_checked = instance_settings.value("zoom1", false).toBool();
145  ui_.zoom_1_push_button->setChecked(zoom1_checked);
146 
147  bool dynamic_range_checked = instance_settings.value("dynamic_range", false).toBool();
148  ui_.dynamic_range_check_box->setChecked(dynamic_range_checked);
149 
150  double max_range = instance_settings.value("max_range", ui_.max_range_double_spin_box->value()).toDouble();
151  ui_.max_range_double_spin_box->setValue(max_range);
152 
153  num_gridlines_ = instance_settings.value("num_gridlines", ui_.num_gridlines_spin_box->value()).toInt();
154  ui_.num_gridlines_spin_box->setValue(num_gridlines_);
155 
156  QString topic = instance_settings.value("topic", "").toString();
157  // don't overwrite topic name passed as command line argument
158  if (!arg_topic_name.isEmpty())
159  {
160  arg_topic_name = "";
161  }
162  else
163  {
164  //qDebug("ImageView::restoreSettings() topic '%s'", topic.toStdString().c_str());
165  selectTopic(topic);
166  }
167 
168  bool publish_click_location = instance_settings.value("publish_click_location", false).toBool();
169  ui_.publish_click_location_check_box->setChecked(publish_click_location);
170 
171  QString pub_topic = instance_settings.value("mouse_pub_topic", "").toString();
172  ui_.publish_click_location_topic_line_edit->setText(pub_topic);
173 
174  bool toolbar_hidden = instance_settings.value("toolbar_hidden", false).toBool();
175  hide_toolbar_action_->setChecked(toolbar_hidden);
176 
177  bool smooth_image_checked = instance_settings.value("smooth_image", false).toBool();
178  ui_.smooth_image_check_box->setChecked(smooth_image_checked);
179 
180  rotate_state_ = static_cast<RotateState>(instance_settings.value("rotate", 0).toInt());
183  syncRotateLabel();
184 }
185 
187 {
188  static const std::map<std::string, int> COLOR_SCHEME_MAP
189  {
190  { "Gray", -1 }, // Special case: no color map
191  { "Autumn", cv::COLORMAP_AUTUMN },
192  { "Bone", cv::COLORMAP_BONE },
193  { "Cool", cv::COLORMAP_COOL },
194  { "Hot", cv::COLORMAP_HOT },
195  { "Hsv", cv::COLORMAP_HSV },
196  { "Jet", cv::COLORMAP_JET },
197  { "Ocean", cv::COLORMAP_OCEAN },
198  { "Pink", cv::COLORMAP_PINK },
199  { "Rainbow", cv::COLORMAP_RAINBOW },
200  { "Spring", cv::COLORMAP_SPRING },
201  { "Summer", cv::COLORMAP_SUMMER },
202  { "Winter", cv::COLORMAP_WINTER }
203  };
204 
205  for (const auto& kv : COLOR_SCHEME_MAP)
206  {
207  ui_.color_scheme_combo_box->addItem(QString::fromStdString(kv.first), QVariant(kv.second));
208  }
209 }
210 
212 {
213  QSet<QString> message_types;
214  message_types.insert("sensor_msgs/Image");
215  QSet<QString> message_sub_types;
216  message_sub_types.insert("sensor_msgs/CompressedImage");
217 
218  // get declared transports
219  QList<QString> transports;
221  std::vector<std::string> declared = it.getDeclaredTransports();
222  for (std::vector<std::string>::const_iterator it = declared.begin(); it != declared.end(); it++)
223  {
224  //qDebug("ImageView::updateTopicList() declared transport '%s'", it->c_str());
225  QString transport = it->c_str();
226 
227  // strip prefix from transport name
228  QString prefix = "image_transport/";
229  if (transport.startsWith(prefix))
230  {
231  transport = transport.mid(prefix.length());
232  }
233  transports.append(transport);
234  }
235 
236  QString selected = ui_.topics_combo_box->currentText();
237 
238  // fill combo box
239  QList<QString> topics = getTopics(message_types, message_sub_types, transports).values();
240  topics.append("");
241  qSort(topics);
242  ui_.topics_combo_box->clear();
243  for (QList<QString>::const_iterator it = topics.begin(); it != topics.end(); it++)
244  {
245  QString label(*it);
246  label.replace(" ", "/");
247  ui_.topics_combo_box->addItem(label, QVariant(*it));
248  }
249 
250  // restore previous selection
251  selectTopic(selected);
252 }
253 
254 QList<QString> ImageView::getTopicList(const QSet<QString>& message_types, const QList<QString>& transports)
255 {
256  QSet<QString> message_sub_types;
257  return getTopics(message_types, message_sub_types, transports).values();
258 }
259 
260 QSet<QString> ImageView::getTopics(const QSet<QString>& message_types, const QSet<QString>& message_sub_types, const QList<QString>& transports)
261 {
262  ros::master::V_TopicInfo topic_info;
263  ros::master::getTopics(topic_info);
264 
265  QSet<QString> all_topics;
266  for (ros::master::V_TopicInfo::const_iterator it = topic_info.begin(); it != topic_info.end(); it++)
267  {
268  all_topics.insert(it->name.c_str());
269  }
270 
271  QSet<QString> topics;
272  for (ros::master::V_TopicInfo::const_iterator it = topic_info.begin(); it != topic_info.end(); it++)
273  {
274  if (message_types.contains(it->datatype.c_str()))
275  {
276  QString topic = it->name.c_str();
277 
278  // add raw topic
279  topics.insert(topic);
280  //qDebug("ImageView::getTopics() raw topic '%s'", topic.toStdString().c_str());
281 
282  // add transport specific sub-topics
283  for (QList<QString>::const_iterator jt = transports.begin(); jt != transports.end(); jt++)
284  {
285  if (all_topics.contains(topic + "/" + *jt))
286  {
287  QString sub = topic + " " + *jt;
288  topics.insert(sub);
289  //qDebug("ImageView::getTopics() transport specific sub-topic '%s'", sub.toStdString().c_str());
290  }
291  }
292  }
293  if (message_sub_types.contains(it->datatype.c_str()))
294  {
295  QString topic = it->name.c_str();
296  int index = topic.lastIndexOf("/");
297  if (index != -1)
298  {
299  topic.replace(index, 1, " ");
300  topics.insert(topic);
301  //qDebug("ImageView::getTopics() transport specific sub-topic '%s'", topic.toStdString().c_str());
302  }
303  }
304  }
305  return topics;
306 }
307 
308 void ImageView::selectTopic(const QString& topic)
309 {
310  int index = ui_.topics_combo_box->findText(topic);
311  if (index == -1)
312  {
313  // add topic name to list if not yet in
314  QString label(topic);
315  label.replace(" ", "/");
316  ui_.topics_combo_box->addItem(label, QVariant(topic));
317  index = ui_.topics_combo_box->findText(topic);
318  }
319  ui_.topics_combo_box->setCurrentIndex(index);
320 }
321 
323 {
325 
326  // reset image on topic change
327  ui_.image_frame->setImage(QImage());
328 
329  QStringList parts = ui_.topics_combo_box->itemData(index).toString().split(" ");
330  QString topic = parts.first();
331  QString transport = parts.length() == 2 ? parts.last() : "raw";
332 
333  if (!topic.isEmpty())
334  {
336  image_transport::TransportHints hints(transport.toStdString());
337  try {
338  subscriber_ = it.subscribe(topic.toStdString(), 1, &ImageView::callbackImage, this, hints);
339  //qDebug("ImageView::onTopicChanged() to topic '%s' with transport '%s'", topic.toStdString().c_str(), subscriber_.getTransport().c_str());
341  QMessageBox::warning(widget_, tr("Loading image transport plugin failed"), e.what());
342  }
343  }
344 
345  onMousePublish(ui_.publish_click_location_check_box->isChecked());
346 }
347 
348 void ImageView::onZoom1(bool checked)
349 {
350  if (checked)
351  {
352  if (ui_.image_frame->getImage().isNull())
353  {
354  return;
355  }
356  ui_.image_frame->setInnerFrameFixedSize(ui_.image_frame->getImage().size());
357  } else {
358  ui_.image_frame->setInnerFrameMinimumSize(QSize(80, 60));
359  ui_.image_frame->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
360  widget_->setMinimumSize(QSize(80, 60));
361  widget_->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
362  }
363 }
364 
365 void ImageView::onDynamicRange(bool checked)
366 {
367  ui_.max_range_double_spin_box->setEnabled(!checked);
368 }
369 
371 {
372  num_gridlines_ = ui_.num_gridlines_spin_box->value();
373 }
374 
376 {
377  // take a snapshot before asking for the filename
378  QImage img = ui_.image_frame->getImageCopy();
379 
380  QString file_name = QFileDialog::getSaveFileName(widget_, tr("Save as image"), "image.png", tr("Image (*.bmp *.jpg *.png *.tiff)"));
381  if (file_name.isEmpty())
382  {
383  return;
384  }
385 
386  img.save(file_name);
387 }
388 
389 void ImageView::onMousePublish(bool checked)
390 {
391  std::string topicName;
393  {
394  topicName = ui_.publish_click_location_topic_line_edit->text().toStdString();
395  } else {
396  if(!subscriber_.getTopic().empty())
397  {
398  topicName = subscriber_.getTopic()+"_mouse_left";
399  } else {
400  topicName = "mouse_left";
401  }
402  ui_.publish_click_location_topic_line_edit->setText(QString::fromStdString(topicName));
403  }
404 
405  if(checked)
406  {
407  pub_mouse_left_ = getNodeHandle().advertise<geometry_msgs::Point>(topicName, 1000);
408  } else {
410  }
411 }
412 
413 void ImageView::onMouseLeft(int x, int y)
414 {
415  if(ui_.publish_click_location_check_box->isChecked() && !ui_.image_frame->getImage().isNull())
416  {
417  geometry_msgs::Point clickCanvasLocation;
418  // Publish click location in pixel coordinates
419  clickCanvasLocation.x = round((double)x/(double)ui_.image_frame->width()*(double)ui_.image_frame->getImage().width());
420  clickCanvasLocation.y = round((double)y/(double)ui_.image_frame->height()*(double)ui_.image_frame->getImage().height());
421  clickCanvasLocation.z = 0;
422 
423  geometry_msgs::Point clickLocation = clickCanvasLocation;
424 
425  switch(rotate_state_)
426  {
427  case ROTATE_90:
428  clickLocation.x = clickCanvasLocation.y;
429  clickLocation.y = ui_.image_frame->getImage().width() - clickCanvasLocation.x;
430  break;
431  case ROTATE_180:
432  clickLocation.x = ui_.image_frame->getImage().width() - clickCanvasLocation.x;
433  clickLocation.y = ui_.image_frame->getImage().height() - clickCanvasLocation.y;
434  break;
435  case ROTATE_270:
436  clickLocation.x = ui_.image_frame->getImage().height() - clickCanvasLocation.y;
437  clickLocation.y = clickCanvasLocation.x;
438  break;
439  default:
440  break;
441  }
442 
443  pub_mouse_left_.publish(clickLocation);
444  }
445 }
446 
448 {
449  pub_topic_custom_ = !(ui_.publish_click_location_topic_line_edit->text().isEmpty());
450  onMousePublish(ui_.publish_click_location_check_box->isChecked());
451 }
452 
454 {
455  ui_.toolbar_widget->setVisible(!hide);
456 }
457 
459 {
460  int m = rotate_state_ - 1;
461  if(m < 0)
462  m = ROTATE_STATE_COUNT-1;
463 
464  rotate_state_ = static_cast<RotateState>(m);
465  syncRotateLabel();
466 }
467 
469 {
471  syncRotateLabel();
472 }
473 
475 {
476  switch(rotate_state_)
477  {
478  default:
479  case ROTATE_0: ui_.rotate_label->setText("0°"); break;
480  case ROTATE_90: ui_.rotate_label->setText("90°"); break;
481  case ROTATE_180: ui_.rotate_label->setText("180°"); break;
482  case ROTATE_270: ui_.rotate_label->setText("270°"); break;
483  }
484 }
485 
486 void ImageView::invertPixels(int x, int y)
487 {
488  // Could do 255-conversion_mat_.at<cv::Vec3b>(cv::Point(x,y))[i], but that doesn't work well on gray
489  cv::Vec3b & pixel = conversion_mat_.at<cv::Vec3b>(cv::Point(x, y));
490  if (pixel[0] + pixel[1] + pixel[2] > 3 * 127)
491  pixel = cv::Vec3b(0,0,0);
492  else
493  pixel = cv::Vec3b(255,255,255);
494 }
495 
496 QList<int> ImageView::getGridIndices(int size) const
497 {
498  QList<int> indices;
499 
500  // the spacing between adjacent grid lines
501  float grid_width = 1.0f * size / (num_gridlines_ + 1);
502 
503  // select grid line(s) closest to the center
504  float index;
505  if (num_gridlines_ % 2) // odd
506  {
507  indices.append(size / 2);
508  // make the center line 2px wide in case of an even resolution
509  if (size % 2 == 0) // even
510  indices.append(size / 2 - 1);
511  index = 1.0f * (size - 1) / 2;
512  }
513  else // even
514  {
515  index = grid_width * (num_gridlines_ / 2);
516  // one grid line before the center
517  indices.append(round(index));
518  // one grid line after the center
519  indices.append(size - 1 - round(index));
520  }
521 
522  // add additional grid lines from the center to the border of the image
523  int lines = (num_gridlines_ - 1) / 2;
524  while (lines > 0)
525  {
526  index -= grid_width;
527  indices.append(round(index));
528  indices.append(size - 1 - round(index));
529  lines--;
530  }
531 
532  return indices;
533 }
534 
536 {
537  // vertical gridlines
538  QList<int> columns = getGridIndices(conversion_mat_.cols);
539  for (QList<int>::const_iterator x = columns.begin(); x != columns.end(); ++x)
540  {
541  for (int y = 0; y < conversion_mat_.rows; ++y)
542  {
543  invertPixels(*x, y);
544  }
545  }
546 
547  // horizontal gridlines
548  QList<int> rows = getGridIndices(conversion_mat_.rows);
549  for (QList<int>::const_iterator y = rows.begin(); y != rows.end(); ++y)
550  {
551  for (int x = 0; x < conversion_mat_.cols; ++x)
552  {
553  invertPixels(x, *y);
554  }
555  }
556 }
557 
558 void ImageView::callbackImage(const sensor_msgs::Image::ConstPtr& msg)
559 {
560  try
561  {
562  // First let cv_bridge do its magic
564  conversion_mat_ = cv_ptr->image;
565 
566  if (num_gridlines_ > 0)
567  overlayGrid();
568  }
569  catch (cv_bridge::Exception& e)
570  {
571  try
572  {
573  // If we're here, there is no conversion that makes sense, but let's try to imagine a few first
575  if (msg->encoding == "CV_8UC3")
576  {
577  // assuming it is rgb
578  conversion_mat_ = cv_ptr->image;
579  } else if (msg->encoding == "8UC1") {
580  // convert gray to rgb
581  cv::cvtColor(cv_ptr->image, conversion_mat_, CV_GRAY2RGB);
582  } else if (msg->encoding == "16UC1" || msg->encoding == "32FC1") {
583  // scale / quantify
584  double min = 0;
585  double max = ui_.max_range_double_spin_box->value();
586  if (msg->encoding == "16UC1") max *= 1000;
587  if (ui_.dynamic_range_check_box->isChecked())
588  {
589  // dynamically adjust range based on min/max in image
590  cv::minMaxLoc(cv_ptr->image, &min, &max);
591  if (min == max) {
592  // completely homogeneous images are displayed in gray
593  min = 0;
594  max = 2;
595  }
596  }
597  cv::Mat img_scaled_8u;
598  cv::Mat(cv_ptr->image-min).convertTo(img_scaled_8u, CV_8UC1, 255. / (max - min));
599 
600  const auto color_scheme_index = ui_.color_scheme_combo_box->currentIndex();
601  const auto color_scheme = ui_.color_scheme_combo_box->itemData(color_scheme_index).toInt();
602  if (color_scheme == -1) {
603  cv::cvtColor(img_scaled_8u, conversion_mat_, CV_GRAY2RGB);
604  } else {
605  cv::Mat img_color_scheme;
606  cv::applyColorMap(img_scaled_8u, img_color_scheme, color_scheme);
607  cv::cvtColor(img_color_scheme, conversion_mat_, CV_BGR2RGB);
608  }
609  } else {
610  qWarning("ImageView.callback_image() could not convert image from '%s' to 'rgb8' (%s)", msg->encoding.c_str(), e.what());
611  ui_.image_frame->setImage(QImage());
612  return;
613  }
614  }
615  catch (cv_bridge::Exception& e)
616  {
617  qWarning("ImageView.callback_image() while trying to convert image from '%s' to 'rgb8' an exception was thrown (%s)", msg->encoding.c_str(), e.what());
618  ui_.image_frame->setImage(QImage());
619  return;
620  }
621  }
622 
623  // Handle rotation
624  switch(rotate_state_)
625  {
626  case ROTATE_90:
627  {
628  cv::Mat tmp;
629  cv::transpose(conversion_mat_, tmp);
630  cv::flip(tmp, conversion_mat_, 1);
631  break;
632  }
633  case ROTATE_180:
634  {
635  cv::Mat tmp;
636  cv::flip(conversion_mat_, tmp, -1);
637  conversion_mat_ = tmp;
638  break;
639  }
640  case ROTATE_270:
641  {
642  cv::Mat tmp;
643  cv::transpose(conversion_mat_, tmp);
644  cv::flip(tmp, conversion_mat_, 0);
645  break;
646  }
647  default:
648  break;
649  }
650 
651  // image must be copied since it uses the conversion_mat_ for storage which is asynchronously overwritten in the next callback invocation
652  QImage image(conversion_mat_.data, conversion_mat_.cols, conversion_mat_.rows, conversion_mat_.step[0], QImage::Format_RGB888);
653  ui_.image_frame->setImage(image);
654 
655  if (!ui_.zoom_1_push_button->isEnabled())
656  {
657  ui_.zoom_1_push_button->setEnabled(true);
658  }
659  // Need to update the zoom 1 every new image in case the image aspect ratio changed,
660  // though could check and see if the aspect ratio changed or not.
661  onZoom1(ui_.zoom_1_push_button->isChecked());
662 }
663 }
664 
virtual void onMouseLeft(int x, int y)
Definition: image_view.cpp:413
CvImageConstPtr toCvShare(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
virtual void onPubTopicChanged()
Definition: image_view.cpp:447
virtual void initPlugin(qt_gui_cpp::PluginContext &context)
Definition: image_view.cpp:57
Subscriber subscribe(const std::string &base_topic, uint32_t queue_size, const boost::function< void(const sensor_msgs::ImageConstPtr &)> &callback, const ros::VoidPtr &tracked_object=ros::VoidPtr(), const TransportHints &transport_hints=TransportHints())
QAction * hide_toolbar_action_
Definition: image_view.h:151
virtual QSet< QString > getTopics(const QSet< QString > &message_types, const QSet< QString > &message_sub_types, const QList< QString > &transports)
Definition: image_view.cpp:260
virtual void callbackImage(const sensor_msgs::Image::ConstPtr &msg)
Definition: image_view.cpp:558
ros::Publisher pub_mouse_left_
Definition: image_view.h:147
void publish(const boost::shared_ptr< M > &message) const
virtual ROS_DEPRECATED QList< QString > getTopicList(const QSet< QString > &message_types, const QList< QString > &transports)
Definition: image_view.cpp:254
image_transport::Subscriber subscriber_
Definition: image_view.h:129
virtual void onMousePublish(bool checked)
Definition: image_view.cpp:389
Ui::ImageViewWidget ui_
Definition: image_view.h:125
virtual void onDynamicRange(bool checked)
Definition: image_view.cpp:365
ROSCPP_DECL bool getTopics(V_TopicInfo &topics)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
void addWidget(QWidget *widget)
std::vector< TopicInfo > V_TopicInfo
virtual void onZoom1(bool checked)
Definition: image_view.cpp:348
virtual void saveImage()
Definition: image_view.cpp:375
const QStringList & argv() const
virtual void onRotateLeft()
Definition: image_view.cpp:458
virtual void onTopicChanged(int index)
Definition: image_view.cpp:322
virtual void shutdownPlugin()
Definition: image_view.cpp:120
std::string getTopic() const
std::vector< std::string > getDeclaredTransports() const
virtual void onRotateRight()
Definition: image_view.cpp:468
void setValue(const QString &key, const QVariant &value)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
ros::NodeHandle & getNodeHandle() const
virtual void updateTopicList()
Definition: image_view.cpp:211
virtual void saveSettings(qt_gui_cpp::Settings &plugin_settings, qt_gui_cpp::Settings &instance_settings) const
Definition: image_view.cpp:126
virtual void selectTopic(const QString &topic)
Definition: image_view.cpp:308
virtual void overlayGrid()
Definition: image_view.cpp:535
virtual void restoreSettings(const qt_gui_cpp::Settings &plugin_settings, const qt_gui_cpp::Settings &instance_settings)
Definition: image_view.cpp:142
virtual void onHideToolbarChanged(bool hide)
Definition: image_view.cpp:453
QList< int > getGridIndices(int size) const
Definition: image_view.cpp:496
virtual void invertPixels(int x, int y)
Definition: image_view.cpp:486
#define PLUGINLIB_EXPORT_CLASS(class_type, base_class_type)
virtual void updateNumGridlines()
Definition: image_view.cpp:370
virtual void setColorSchemeList()
Definition: image_view.cpp:186


rqt_image_view
Author(s): Dirk Thomas
autogenerated on Mon Mar 18 2019 02:53:45