python - 订阅者无法从发布者读取图像
问题描述
我一直在尝试通过将 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_() 方法执行事件循环,因此它只会在 Qt 执行完毕后才执行完毕,如果将其与 sys.exit 关联,则后续代码将永远不会执行。
另一方面,您不应该使用 while 循环,而只需要使用 eventloop,并使用信号将回调(在辅助线程中执行)中的信息发送到窗口。
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_())
推荐阅读
- flutter - 为什么颤振约束没有通过小部件树向下推?
- php - 即使在检查 API 密钥和注册域后,仍会出现错误“此域未在微型云中注册”
- loops - 使用 NA 的 R 进行循环股票价格回归
- salesforce - SalesForce 对象:Restapi 可见性
- docker - docker错误下使用NodeRed的RPi GPIO控制?
- concurrency - Rust 缓存异步特征
- laravel - 为什么 Laravel-livewire 'wire:model' 不起作用?
- php - php通过两个属性过滤json数组
- python - 使用 Xgboost 进行非线性回归
- python-3.x - 删除场景中选定的 QGraphicsPixmapItem