订阅者无法从发布者读取图像
Subscriber unable to read image from publisher
我一直在尝试通过将opencv 与pyqt5 集成来让订阅者使用GUI 显示图像,但是单击按钮后图像不显示。在我将 pyqt5 集成到订阅者之前,它能够仅使用 opencv 本身显示图像。
-我正在使用 Ubuntu 18.04.
我的发布者代码:
def main():
image_pub = rospy.Publisher("/image", Image, queue_size=1)
rate = rospy.Rate(50)
bridge = CvBridge()
while not rospy.is_shutdown():
print("------------Mask detection processing one time!------------")
image_path='/home/sk/catkin_ws/src/test/scripts/p_e.png'
cv_image = cv2.imread(image_path)
# read a image using opencv
# change to your real image path
print(cv_image.shape)
#cv2.imshow("Pikachu", cv_image)
msg_image = bridge.cv2_to_imgmsg(cv_image, encoding = "bgr8")
stamp = rospy.Time.now()
msg_image.header.frame_id = "camera_link"
msg_image.header.stamp = stamp
image_pub.publish(msg_image)
rate.sleep()
if __name__ == '__main__':
try:
rospy.init_node('image_pub_node', anonymous=True)
main()
rospy.spin()
except KeyboardInterrupt:
print("Shutting down")
sys.exit(0)
pass
我的订阅者代码:
class ImageWidget(QtWidgets.QWidget):
#def callback(self,data):
def callback(self,rosdata):
global cv_image
#self.bridge = CvBridge()
self.bridge = CvBridge()
#print("in callback")
rate = rospy.Rate(10)
rate.sleep()
try:
cv_image = self.bridge.imgmsg_to_cv2(rosdata, "bgr8")
#cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.button = QtWidgets.QPushButton('Show picture')
self.button.clicked.connect(self.main)
self.image_frame = QtWidgets.QLabel()
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.button)
self.layout.addWidget(self.image_frame)
self.setLayout(self.layout)
def main(self):
rospy.init_node('image_sub_node', anonymous=True)
self.image_sub = rospy.Subscriber("/image", Image, self.callback, queue_size=1, buff_size=52428800)
rate = rospy.Rate(50) #50Hz
bridge = CvBridge()
while not rospy.is_shutdown():
print("------------Mask detection processing one time!------------")
try:
self.cv_image = cv2.imread('Image')
self.cv_image = QtGui.QImage(self.cv_image.data, self.cv_image.shape[1], self.cv_image.shape[0], QtGui.QImage.Format_RGB888).rgbSwapped()
self.image_frame.setPixmap(QtGui.QPixmap.fromImage(self.cv_image))
except Exception:
continue
rate.sleep()
if __name__ == '__main__':
try:
app = QtWidgets.QApplication(sys.argv)
image_widget = ImageWidget()
image_widget.show()
sys.exit(app.exec_())
rospy.init_node('image_sub_node', anonymous=True)
main()
rospy.spin()
except KeyboardInterrupt:
pass
exec_()方法执行的是eventloop所以只有在Qt执行完后才会执行完,如果关联sys.exit则后面的代码永远不会执行
另一方面,您不应该使用 while 循环,而只需要使用事件循环,并使用信号将回调(在辅助线程中执行)中的信息发送到 window。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import rospy
import cv2
class SubscriberManager(QtCore.QObject):
imageChanged = QtCore.pyqtSignal(QtGui.QImage)
def __init__(self, parent=None):
super(SubscriberManager, self).__init__(parent)
self.bridge = CvBridge()
self.subscriber = None
def start(self, name):
self.stop()
self.subscriber = rospy.Subscriber(
name, Image, self._callback, queue_size=1, buff_size=52428800
)
def stop(self):
if self.subscriber is not None:
self.subscriber.unregister()
self.subscriber = None
def _callback(self, rosdata):
try:
cv_image = self.bridge.imgmsg_to_cv2(rosdata, "bgr8")
except CvBridgeError as e:
print(e)
else:
src = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
h, w, ch = src.shape
bytesPerLine = ch * w
qImg = QtGui.QImage(
src.data, w, h, bytesPerLine, QtGui.QImage.Format_RGB888
)
self.imageChanged.emit(qImg)
class ImageWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.button = QtWidgets.QPushButton("Show picture")
self.image_frame = QtWidgets.QLabel()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.button)
lay.addWidget(self.image_frame)
self.subscribe_manager = SubscriberManager()
self.subscribe_manager.imageChanged.connect(self.on_image_changed)
self.button.clicked.connect(self.start)
def start(self):
self.subscribe_manager.start("/image")
@QtCore.pyqtSlot(QtGui.QImage)
def on_image_changed(self, image):
self.image_frame.setPixmap(QtGui.QPixmap.fromImage(image))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
rospy.init_node("image_sub_node", anonymous=True)
image_widget = ImageWidget()
image_widget.show()
sys.exit(app.exec_())
我一直在尝试通过将opencv 与pyqt5 集成来让订阅者使用GUI 显示图像,但是单击按钮后图像不显示。在我将 pyqt5 集成到订阅者之前,它能够仅使用 opencv 本身显示图像。
-我正在使用 Ubuntu 18.04.
我的发布者代码:
def main():
image_pub = rospy.Publisher("/image", Image, queue_size=1)
rate = rospy.Rate(50)
bridge = CvBridge()
while not rospy.is_shutdown():
print("------------Mask detection processing one time!------------")
image_path='/home/sk/catkin_ws/src/test/scripts/p_e.png'
cv_image = cv2.imread(image_path)
# read a image using opencv
# change to your real image path
print(cv_image.shape)
#cv2.imshow("Pikachu", cv_image)
msg_image = bridge.cv2_to_imgmsg(cv_image, encoding = "bgr8")
stamp = rospy.Time.now()
msg_image.header.frame_id = "camera_link"
msg_image.header.stamp = stamp
image_pub.publish(msg_image)
rate.sleep()
if __name__ == '__main__':
try:
rospy.init_node('image_pub_node', anonymous=True)
main()
rospy.spin()
except KeyboardInterrupt:
print("Shutting down")
sys.exit(0)
pass
我的订阅者代码:
class ImageWidget(QtWidgets.QWidget):
#def callback(self,data):
def callback(self,rosdata):
global cv_image
#self.bridge = CvBridge()
self.bridge = CvBridge()
#print("in callback")
rate = rospy.Rate(10)
rate.sleep()
try:
cv_image = self.bridge.imgmsg_to_cv2(rosdata, "bgr8")
#cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.button = QtWidgets.QPushButton('Show picture')
self.button.clicked.connect(self.main)
self.image_frame = QtWidgets.QLabel()
self.layout = QtWidgets.QVBoxLayout()
self.layout.addWidget(self.button)
self.layout.addWidget(self.image_frame)
self.setLayout(self.layout)
def main(self):
rospy.init_node('image_sub_node', anonymous=True)
self.image_sub = rospy.Subscriber("/image", Image, self.callback, queue_size=1, buff_size=52428800)
rate = rospy.Rate(50) #50Hz
bridge = CvBridge()
while not rospy.is_shutdown():
print("------------Mask detection processing one time!------------")
try:
self.cv_image = cv2.imread('Image')
self.cv_image = QtGui.QImage(self.cv_image.data, self.cv_image.shape[1], self.cv_image.shape[0], QtGui.QImage.Format_RGB888).rgbSwapped()
self.image_frame.setPixmap(QtGui.QPixmap.fromImage(self.cv_image))
except Exception:
continue
rate.sleep()
if __name__ == '__main__':
try:
app = QtWidgets.QApplication(sys.argv)
image_widget = ImageWidget()
image_widget.show()
sys.exit(app.exec_())
rospy.init_node('image_sub_node', anonymous=True)
main()
rospy.spin()
except KeyboardInterrupt:
pass
exec_()方法执行的是eventloop所以只有在Qt执行完后才会执行完,如果关联sys.exit则后面的代码永远不会执行
另一方面,您不应该使用 while 循环,而只需要使用事件循环,并使用信号将回调(在辅助线程中执行)中的信息发送到 window。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError
import rospy
import cv2
class SubscriberManager(QtCore.QObject):
imageChanged = QtCore.pyqtSignal(QtGui.QImage)
def __init__(self, parent=None):
super(SubscriberManager, self).__init__(parent)
self.bridge = CvBridge()
self.subscriber = None
def start(self, name):
self.stop()
self.subscriber = rospy.Subscriber(
name, Image, self._callback, queue_size=1, buff_size=52428800
)
def stop(self):
if self.subscriber is not None:
self.subscriber.unregister()
self.subscriber = None
def _callback(self, rosdata):
try:
cv_image = self.bridge.imgmsg_to_cv2(rosdata, "bgr8")
except CvBridgeError as e:
print(e)
else:
src = cv2.cvtColor(cv_image, cv2.COLOR_BGR2RGB)
h, w, ch = src.shape
bytesPerLine = ch * w
qImg = QtGui.QImage(
src.data, w, h, bytesPerLine, QtGui.QImage.Format_RGB888
)
self.imageChanged.emit(qImg)
class ImageWidget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(ImageWidget, self).__init__(parent)
self.button = QtWidgets.QPushButton("Show picture")
self.image_frame = QtWidgets.QLabel()
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.button)
lay.addWidget(self.image_frame)
self.subscribe_manager = SubscriberManager()
self.subscribe_manager.imageChanged.connect(self.on_image_changed)
self.button.clicked.connect(self.start)
def start(self):
self.subscribe_manager.start("/image")
@QtCore.pyqtSlot(QtGui.QImage)
def on_image_changed(self, image):
self.image_frame.setPixmap(QtGui.QPixmap.fromImage(image))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
rospy.init_node("image_sub_node", anonymous=True)
image_widget = ImageWidget()
image_widget.show()
sys.exit(app.exec_())