image_view2_wrapper.py
Go to the documentation of this file.
00001 from distutils.version import LooseVersion
00002 import math
00003 import os
00004 import sys
00005 from threading import Lock, Thread
00006 import time
00007 
00008 import cv2
00009 import numpy as np
00010 import python_qt_binding
00011 from python_qt_binding.QtCore import pyqtSignal
00012 from python_qt_binding.QtCore import pyqtSlot
00013 from python_qt_binding.QtCore import QEvent
00014 from python_qt_binding.QtCore import QSize
00015 from python_qt_binding.QtCore import Qt
00016 import python_qt_binding.QtCore as QtCore
00017 from python_qt_binding.QtCore import QTimer
00018 from python_qt_binding.QtCore import qWarning
00019 from python_qt_binding.QtCore import Slot
00020 from python_qt_binding.QtGui import QBrush
00021 from python_qt_binding.QtGui import QColor
00022 from python_qt_binding.QtGui import QFont
00023 from python_qt_binding.QtGui import QIcon
00024 from python_qt_binding.QtGui import QImage
00025 from python_qt_binding.QtGui import QPainter
00026 from python_qt_binding.QtGui import QPen
00027 from python_qt_binding.QtGui import QPixmap
00028 from python_qt_binding.QtGui import qRgb
00029 import python_qt_binding.QtGui as QtGui
00030 import yaml
00031 
00032 from cv_bridge import CvBridge
00033 from cv_bridge import CvBridgeError
00034 from image_view2.msg import MouseEvent
00035 from resource_retriever import get_filename
00036 import rospy
00037 from rqt_gui_py.plugin import Plugin
00038 from sensor_msgs.msg import Image
00039 from std_msgs.msg import Bool
00040 from std_msgs.msg import Time
00041 
00042 if LooseVersion(python_qt_binding.QT_BINDING_VERSION).version[0] >= 5:
00043     from python_qt_binding.QtWidgets import QAction
00044     from python_qt_binding.QtWidgets import QComboBox
00045     from python_qt_binding.QtWidgets import QDialog
00046     from python_qt_binding.QtWidgets import QMenu
00047     from python_qt_binding.QtWidgets import QMessageBox
00048     from python_qt_binding.QtWidgets import QLabel
00049     from python_qt_binding.QtWidgets import QPushButton
00050     from python_qt_binding.QtWidgets import QSizePolicy
00051     from python_qt_binding.QtWidgets import QVBoxLayout
00052     from python_qt_binding.QtWidgets import QWidget
00053 
00054 else:
00055     from python_qt_binding.QtGui import QAction
00056     from python_qt_binding.QtGui import QComboBox
00057     from python_qt_binding.QtGui import QDialog
00058     from python_qt_binding.QtGui import QMenu
00059     from python_qt_binding.QtGui import QMessageBox
00060     from python_qt_binding.QtGui import QLabel
00061     from python_qt_binding.QtGui import QPushButton
00062     from python_qt_binding.QtGui import QSizePolicy
00063     from python_qt_binding.QtGui import QVBoxLayout
00064     from python_qt_binding.QtGui import QWidget
00065 
00066 
00067 class ComboBoxDialog(QDialog):
00068     def __init__(self, parent=None):
00069         super(ComboBoxDialog, self).__init__()
00070         self.number = 0
00071         vbox = QVBoxLayout(self)
00072         self.combo_box = QComboBox(self)
00073         self.combo_box.activated.connect(self.onActivated)
00074         vbox.addWidget(self.combo_box)
00075         button = QPushButton()
00076         button.setText("Done")
00077         button.clicked.connect(self.buttonCallback)
00078         vbox.addWidget(button)
00079         self.setLayout(vbox)
00080 
00081     def buttonCallback(self, event):
00082         self.close()
00083 
00084     def onActivated(self, number):
00085         self.number = number
00086 
00087 
00088 class ImageView2Plugin(Plugin):
00089     """
00090     rqt wrapper for image_view2
00091     """
00092     def __init__(self, context):
00093         super(ImageView2Plugin, self).__init__(context)
00094         self.setObjectName("ImageView2Plugin")
00095         self._widget = ImageView2Widget()
00096         context.add_widget(self._widget)
00097 
00098     def save_settings(self, plugin_settings, instance_settings):
00099         self._widget.save_settings(plugin_settings, instance_settings)
00100 
00101     def restore_settings(self, plugin_settings, instance_settings):
00102         self._widget.restore_settings(plugin_settings, instance_settings)
00103 
00104     def trigger_configuration(self):
00105         self._widget.trigger_configuration()
00106 
00107 
00108 class ScaledLabel(QLabel):
00109     def __init__(self, *args, **kwargs):
00110         QLabel.__init__(self)
00111         self._pixmap = QPixmap(self.pixmap())
00112 
00113     def resizeEvent(self, event):
00114         self.setPixmap(self._pixmap.scaled(
00115             self.width(), self.height(),
00116             QtCore.Qt.KeepAspectRatio))
00117 
00118 
00119 class ImageView2Widget(QWidget):
00120     """
00121     Qt widget to communicate with image_view2
00122     """
00123     cv_image = None
00124     pixmap = None
00125     repaint_trigger = pyqtSignal()
00126 
00127     def __init__(self):
00128         super(ImageView2Widget, self).__init__()
00129         self.left_button_clicked = False
00130 
00131         self.repaint_trigger.connect(self.redraw)
00132         self.lock = Lock()
00133         self.need_to_rewrite = False
00134         self.bridge = CvBridge()
00135         self.image_sub = None
00136         self.event_pub = None
00137         self.label = ScaledLabel()
00138         self.label.setAlignment(Qt.AlignCenter)
00139         self.label.setSizePolicy(
00140             QSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored))
00141         # self.label.installEventFilter(self)
00142         vbox = QVBoxLayout(self)
00143         vbox.addWidget(self.label)
00144         self.setLayout(vbox)
00145 
00146         self._image_topics = []
00147         self._update_topic_thread = Thread(target=self.updateTopics)
00148         self._update_topic_thread.start()
00149 
00150         self._active_topic = None
00151         self.setMouseTracking(True)
00152         self.label.setMouseTracking(True)
00153         self._dialog = ComboBoxDialog()
00154         self.show()
00155 
00156     def trigger_configuration(self):
00157         self._dialog.exec_()
00158         self.setupSubscriber(self._image_topics[self._dialog.number])
00159 
00160     def setupSubscriber(self, topic):
00161         if self.image_sub:
00162             self.image_sub.unregister()
00163         rospy.loginfo("Subscribing %s" % (topic + "/marked"))
00164         self.image_sub = rospy.Subscriber(topic + "/marked",
00165                                           Image, 
00166                                           self.imageCallback)
00167         self.event_pub = rospy.Publisher(
00168             topic + "/event", MouseEvent, queue_size=1)
00169         self._active_topic = topic
00170 
00171     def onActivated(self, number):
00172         self.setupSubscriber(self._image_topics[number])
00173 
00174     def imageCallback(self, msg):
00175         with self.lock:
00176             if msg.width == 0 or msg.height == 0:
00177                 rospy.logdebug("Looks input images is invalid")
00178                 return
00179             cv_image = self.bridge.imgmsg_to_cv2(msg, msg.encoding)
00180             if msg.encoding == "bgr8":
00181                 self.cv_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
00182             elif msg.encoding == "rgb8":
00183                 self.cv_image = cv_image
00184             self.numpy_image = np.asarray(self.cv_image)
00185             self.need_to_rewrite = True
00186             self.repaint_trigger.emit()
00187 
00188     def updateTopics(self):
00189         need_to_update = False
00190         for (topic, topic_type) in rospy.get_published_topics():
00191             if topic_type == "sensor_msgs/Image":
00192                 with self.lock:
00193                     if not topic in self._image_topics:
00194                         self._image_topics.append(topic)
00195                         need_to_update = True
00196         if need_to_update:
00197             with self.lock:
00198                 self._image_topics = sorted(self._image_topics)
00199                 self._dialog.combo_box.clear()
00200                 for topic in self._image_topics:
00201                     self._dialog.combo_box.addItem(topic)
00202                 if self._active_topic:
00203                     self._dialog.combo_box.setCurrentIndex(
00204                         self._image_topics.index(self._active_topic))
00205         time.sleep(1)
00206 
00207     @pyqtSlot()
00208     def redraw(self):
00209         with self.lock:
00210             if not self.need_to_rewrite:
00211                 return
00212             if np.all(self.cv_image) is not None:
00213                 size = self.cv_image.shape
00214                 img = QImage(self.cv_image.data,
00215                              size[1], size[0], size[2] * size[1],
00216                              QImage.Format_RGB888)
00217                 # convert to QPixmap
00218                 self.pixmap = QPixmap(size[1], size[0])
00219                 self.pixmap.convertFromImage(img)
00220                 self.label.setPixmap(self.pixmap.scaled(
00221                     self.label.width(), self.label.height(),
00222                     QtCore.Qt.KeepAspectRatio))
00223                 # self.label.setPixmap(self.pixmap)
00224 
00225     def mousePosition(self, e):
00226         label_x = self.label.x()
00227         label_y = self.label.y()
00228         label_width = self.label.width()
00229         label_height = self.label.height()
00230         pixmap_width = self.label.pixmap().width()
00231         pixmap_height = self.label.pixmap().height()
00232         x_offset = (label_width - pixmap_width) / 2.0 + label_x
00233         y_offset = (label_height - pixmap_height) / 2.0 + label_y
00234         return (e.x() - x_offset, e.y() - y_offset)
00235 
00236     def mouseMoveEvent(self, e):
00237         msg = MouseEvent()
00238         msg.header.stamp = rospy.Time.now()
00239         msg.type = MouseEvent.MOUSE_MOVE
00240         msg.x, msg.y = self.mousePosition(e)
00241         msg.width = self.label.pixmap().width()
00242         msg.height = self.label.pixmap().height()
00243         if self.event_pub:
00244             self.event_pub.publish(msg)
00245 
00246     def mousePressEvent(self, e):
00247         msg = MouseEvent()
00248         msg.header.stamp = rospy.Time.now()
00249         if e.button() == Qt.LeftButton:
00250             msg.type = MouseEvent.MOUSE_LEFT_DOWN
00251             self.left_button_clicked = True
00252         elif e.button() == Qt.RightButton:
00253             msg.type = MouseEvent.MOUSE_RIGHT_DOWN
00254         msg.width = self.label.pixmap().width()
00255         msg.height = self.label.pixmap().height()
00256         msg.x, msg.y = self.mousePosition(e)
00257         if self.event_pub:
00258             self.event_pub.publish(msg)
00259 
00260     def mouseReleaseEvent(self, e):
00261         if e.button() == Qt.LeftButton:
00262             self.left_button_clicked = False
00263             msg = MouseEvent()
00264             msg.header.stamp = rospy.Time.now()
00265             msg.width = self.label.pixmap().width()
00266             msg.height = self.label.pixmap().height()
00267             msg.type = MouseEvent.MOUSE_LEFT_UP
00268             msg.x, msg.y = self.mousePosition(e)
00269             if self.event_pub:
00270                 self.event_pub.publish(msg)
00271 
00272     def save_settings(self, plugin_settings, instance_settings):
00273         if self._active_topic:
00274             instance_settings.set_value("active_topic", self._active_topic)
00275 
00276     def restore_settings(self, plugin_settings, instance_settings):
00277         if instance_settings.value("active_topic"):
00278             topic = instance_settings.value("active_topic")
00279             self._dialog.combo_box.addItem(topic)
00280             self.setupSubscriber(topic)


jsk_rqt_plugins
Author(s):
autogenerated on Wed May 1 2019 02:40:16