40 #include <opencv2/imgproc/imgproc.hpp>
42 #include <QFileDialog>
43 #include <QMessageBox>
52 , rotate_state_(ROTATE_0)
54 setObjectName(
"ImageView");
69 ui_.color_scheme_combo_box->setCurrentIndex(
ui_.color_scheme_combo_box->findText(
"Gray"));
72 ui_.topics_combo_box->setCurrentIndex(
ui_.topics_combo_box->findText(
""));
73 connect(
ui_.topics_combo_box, SIGNAL(currentIndexChanged(
int)),
this, SLOT(
onTopicChanged(
int)));
75 ui_.refresh_topics_push_button->setIcon(QIcon::fromTheme(
"view-refresh"));
76 connect(
ui_.refresh_topics_push_button, SIGNAL(pressed()),
this, SLOT(
updateTopicList()));
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)));
81 connect(
ui_.dynamic_range_check_box, SIGNAL(toggled(
bool)),
this, SLOT(
onDynamicRange(
bool)));
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()));
89 const QStringList& argv = context.
argv();
96 ui_.image_frame->setOuterLayout(
ui_.image_layout);
98 QRegExp rx(
"([a-zA-Z/][a-zA-Z0-9_/]*)?");
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()));
104 connect(
ui_.smooth_image_check_box, SIGNAL(toggled(
bool)),
ui_.image_frame, SLOT(onSmoothImageChanged(
bool)));
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()));
110 ui_.rotate_label->setMinimumWidth(
111 ui_.rotate_label->fontMetrics().width(
"XXX°")
128 QString topic =
ui_.topics_combo_box->currentText();
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());
137 instance_settings.
setValue(
"num_gridlines",
ui_.num_gridlines_spin_box->value());
138 instance_settings.
setValue(
"smooth_image",
ui_.smooth_image_check_box->isChecked());
140 instance_settings.
setValue(
"color_scheme",
ui_.color_scheme_combo_box->currentIndex());
145 bool zoom1_checked = instance_settings.
value(
"zoom1",
false).toBool();
146 ui_.zoom_1_push_button->setChecked(zoom1_checked);
148 bool dynamic_range_checked = instance_settings.
value(
"dynamic_range",
false).toBool();
149 ui_.dynamic_range_check_box->setChecked(dynamic_range_checked);
151 double max_range = instance_settings.
value(
"max_range",
ui_.max_range_double_spin_box->value()).toDouble();
152 ui_.max_range_double_spin_box->setValue(max_range);
157 QString topic = instance_settings.
value(
"topic",
"").toString();
169 bool publish_click_location = instance_settings.
value(
"publish_click_location",
false).toBool();
170 ui_.publish_click_location_check_box->setChecked(publish_click_location);
172 QString pub_topic = instance_settings.
value(
"mouse_pub_topic",
"").toString();
173 ui_.publish_click_location_topic_line_edit->setText(pub_topic);
175 bool toolbar_hidden = instance_settings.
value(
"toolbar_hidden",
false).toBool();
178 bool smooth_image_checked = instance_settings.
value(
"smooth_image",
false).toBool();
179 ui_.smooth_image_check_box->setChecked(smooth_image_checked);
186 int color_scheme = instance_settings.
value(
"color_scheme",
ui_.color_scheme_combo_box->currentIndex()).toInt();
187 ui_.color_scheme_combo_box->setCurrentIndex(color_scheme);
192 static const std::map<std::string, int> COLOR_SCHEME_MAP
195 {
"Autumn", cv::COLORMAP_AUTUMN },
196 {
"Bone", cv::COLORMAP_BONE },
197 {
"Cool", cv::COLORMAP_COOL },
198 {
"Hot", cv::COLORMAP_HOT },
199 {
"Hsv", cv::COLORMAP_HSV },
200 {
"Jet", cv::COLORMAP_JET },
201 {
"Ocean", cv::COLORMAP_OCEAN },
202 {
"Pink", cv::COLORMAP_PINK },
203 {
"Rainbow", cv::COLORMAP_RAINBOW },
204 {
"Spring", cv::COLORMAP_SPRING },
205 {
"Summer", cv::COLORMAP_SUMMER },
206 {
"Winter", cv::COLORMAP_WINTER }
209 for (
const auto& kv : COLOR_SCHEME_MAP)
211 ui_.color_scheme_combo_box->addItem(QString::fromStdString(kv.first), QVariant(kv.second));
217 QSet<QString> message_types;
218 message_types.insert(
"sensor_msgs/Image");
219 QSet<QString> message_sub_types;
220 message_sub_types.insert(
"sensor_msgs/CompressedImage");
223 QList<QString> transports;
226 for (std::vector<std::string>::const_iterator it = declared.begin(); it != declared.end(); it++)
229 QString transport = it->c_str();
232 QString prefix =
"image_transport/";
233 if (transport.startsWith(prefix))
235 transport = transport.mid(prefix.length());
237 transports.append(transport);
240 QString selected =
ui_.topics_combo_box->currentText();
243 QList<QString> topics =
getTopics(message_types, message_sub_types, transports).values();
246 ui_.topics_combo_box->clear();
247 for (QList<QString>::const_iterator it = topics.begin(); it != topics.end(); it++)
250 label.replace(
" ",
"/");
251 ui_.topics_combo_box->addItem(label, QVariant(*it));
260 QSet<QString> message_sub_types;
261 return getTopics(message_types, message_sub_types, transports).values();
264 QSet<QString>
ImageView::getTopics(
const QSet<QString>& message_types,
const QSet<QString>& message_sub_types,
const QList<QString>& transports)
269 QSet<QString> all_topics;
270 for (ros::master::V_TopicInfo::const_iterator it = topic_info.begin(); it != topic_info.end(); it++)
272 all_topics.insert(it->name.c_str());
275 QSet<QString> topics;
276 for (ros::master::V_TopicInfo::const_iterator it = topic_info.begin(); it != topic_info.end(); it++)
278 if (message_types.contains(it->datatype.c_str()))
280 QString topic = it->name.c_str();
283 topics.insert(topic);
287 for (QList<QString>::const_iterator jt = transports.begin(); jt != transports.end(); jt++)
289 if (all_topics.contains(topic +
"/" + *jt))
291 QString sub = topic +
" " + *jt;
297 if (message_sub_types.contains(it->datatype.c_str()))
299 QString topic = it->name.c_str();
300 int index = topic.lastIndexOf(
"/");
303 topic.replace(index, 1,
" ");
304 topics.insert(topic);
314 int index =
ui_.topics_combo_box->findText(topic);
318 QString label(topic);
319 label.replace(
" ",
"/");
320 ui_.topics_combo_box->addItem(label, QVariant(topic));
321 index =
ui_.topics_combo_box->findText(topic);
323 ui_.topics_combo_box->setCurrentIndex(index);
333 ui_.image_frame->setImage(QImage());
335 QStringList parts =
ui_.topics_combo_box->itemData(index).toString().split(
" ");
336 QString topic = parts.first();
337 QString transport = parts.length() == 2 ? parts.last() :
"raw";
339 if (!topic.isEmpty())
347 QMessageBox::warning(
widget_, tr(
"Loading image transport plugin failed"), e.what());
358 if (
ui_.image_frame->getImage().isNull())
362 ui_.image_frame->setInnerFrameFixedSize(
ui_.image_frame->getImage().size());
364 ui_.image_frame->setInnerFrameMinimumSize(QSize(80, 60));
365 ui_.image_frame->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
366 widget_->setMinimumSize(QSize(80, 60));
367 widget_->setMaximumSize(QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX));
373 ui_.max_range_double_spin_box->setEnabled(!checked);
384 QImage img =
ui_.image_frame->getImageCopy();
386 QString file_name = QFileDialog::getSaveFileName(
widget_, tr(
"Save as image"),
"image.png", tr(
"Image (*.bmp *.jpg *.png *.tiff)"));
387 if (file_name.isEmpty())
397 std::string topicName;
400 topicName =
ui_.publish_click_location_topic_line_edit->text().toStdString();
406 topicName =
"mouse_left";
408 ui_.publish_click_location_topic_line_edit->setText(QString::fromStdString(topicName));
421 if(
ui_.publish_click_location_check_box->isChecked() && !
ui_.image_frame->getImage().isNull())
423 geometry_msgs::Point clickCanvasLocation;
425 clickCanvasLocation.x = round((
double)x/(
double)
ui_.image_frame->width()*(
double)
ui_.image_frame->getImage().width());
426 clickCanvasLocation.y = round((
double)y/(
double)
ui_.image_frame->height()*(
double)
ui_.image_frame->getImage().height());
427 clickCanvasLocation.z = 0;
429 geometry_msgs::Point clickLocation = clickCanvasLocation;
434 clickLocation.x = clickCanvasLocation.y;
435 clickLocation.y =
ui_.image_frame->getImage().width() - clickCanvasLocation.x;
438 clickLocation.x =
ui_.image_frame->getImage().width() - clickCanvasLocation.x;
439 clickLocation.y =
ui_.image_frame->getImage().height() - clickCanvasLocation.y;
442 clickLocation.x =
ui_.image_frame->getImage().height() - clickCanvasLocation.y;
443 clickLocation.y = clickCanvasLocation.x;
461 ui_.toolbar_widget->setVisible(!hide);
485 case ROTATE_0:
ui_.rotate_label->setText(
"0°");
break;
486 case ROTATE_90:
ui_.rotate_label->setText(
"90°");
break;
496 if (pixel[0] + pixel[1] + pixel[2] > 3 * 127)
497 pixel = cv::Vec3b(0,0,0);
499 pixel = cv::Vec3b(255,255,255);
513 indices.append(size / 2);
516 indices.append(size / 2 - 1);
517 index = 1.0f * (size - 1) / 2;
523 indices.append(round(index));
525 indices.append(size - 1 - round(index));
533 indices.append(round(index));
534 indices.append(size - 1 - round(index));
545 for (QList<int>::const_iterator x = columns.begin(); x != columns.end(); ++x)
555 for (QList<int>::const_iterator y = rows.begin(); y != rows.end(); ++y)
581 if (msg->encoding ==
"CV_8UC3")
585 }
else if (msg->encoding ==
"8UC1") {
588 }
else if (msg->encoding ==
"16UC1" || msg->encoding ==
"32FC1") {
591 double max =
ui_.max_range_double_spin_box->value();
592 if (msg->encoding ==
"16UC1") max *= 1000;
593 if (
ui_.dynamic_range_check_box->isChecked())
596 cv::minMaxLoc(cv_ptr->image, &min, &max);
603 cv::Mat img_scaled_8u;
604 cv::Mat(cv_ptr->image-min).convertTo(img_scaled_8u, CV_8UC1, 255. / (max - min));
606 const auto color_scheme_index =
ui_.color_scheme_combo_box->currentIndex();
607 const auto color_scheme =
ui_.color_scheme_combo_box->itemData(color_scheme_index).toInt();
608 if (color_scheme == -1) {
611 cv::Mat img_color_scheme;
612 cv::applyColorMap(img_scaled_8u, img_color_scheme, color_scheme);
616 qWarning(
"ImageView.callback_image() could not convert image from '%s' to 'rgb8' (%s)", msg->encoding.c_str(), e.what());
617 ui_.image_frame->setImage(QImage());
623 qWarning(
"ImageView.callback_image() while trying to convert image from '%s' to 'rgb8' an exception was thrown (%s)", msg->encoding.c_str(), e.what());
624 ui_.image_frame->setImage(QImage());
659 ui_.image_frame->setImage(image);
661 if (!
ui_.zoom_1_push_button->isEnabled())
663 ui_.zoom_1_push_button->setEnabled(
true);