参考:古月学院和ROS机器人开发实践
目标:实现ROS系统读取摄像头的图像,ROS读取的图像数据转化为opencv中的图像,opencv对接受的图像进行处理,最后返回给ROS系统可视化输出。
安装opencv库与相关的接口包
由于我用的ROS-Melodic版本,其中roscore只能在python2中执行,而视觉部分要在python3中执行,故将包安装在两个python中。(重要操作,因为其他有关于视觉的库,比如pytorch,是需要python3的,如果默认环境是python环境是python2,没把相应的包安装进python3,会报缺失依赖的错。)
(1条消息) ROS修改:ubuntu系统更改默认python版本(重要操作)_机械专业的计算机小白的博客-CSDN博客https://blog.csdn.net/wzfafabga/article/details/127191057?spm=1001.2014.3001.5501具体切换python版本方法在如上文章中。
sudo apt-get install ros-melodic-vision-opencv libopencv-dev ros-melodic-vision-opencv python-opencv
下载好相应的源码,放在工作空间的src中
guyueclass/planning&perception/robot_vision_beginner/robot_vision at main · guyuehome/guyueclass (github.com)https://github.com/guyuehome/guyueclass/tree/main/planning%26perception/robot_vision_beginner/robot_vision这个古月学院和ROS机器人开发实践的源码。
运行的代码
首先是usb_cam.launch
<launch>
<node name="usb_cam" pkg="usb_cam" type="usb_cam_node" output="screen" >
<param name="video_device" value="/dev/video0" />
<param name="image_width" value="640" />
<param name="image_height" value="480" />
<param name="pixel_format" value="yuyv" />
<param name="camera_frame_id" value="usb_cam" />
<param name="io_method" value="mmap"/>
</node>
</launch>
创建一个节点,之后作为发布者,摄像头的图像信息,其中参数必须和摄像头参数对应,要不会报错。
其次是cv_bridge_test.py
其中要修改python版本声明,因为molodic版本默认python版本是python2,但是现在视觉算法都是用的python3,在python3中才有实际意义。
修改了声明:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import rospy
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
class image_converter:
def __init__(self):
# 创建cv_bridge,声明图像的发布者和订阅者
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
def callback(self,data):
# 使用cv_bridge将ROS的图像数据转换成OpenCV的图像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
# 在opencv的显示窗口中绘制一个圆,作为标记
(rows,cols,channels) = cv_image.shape
if cols > 60 and rows > 60 :
cv2.circle(cv_image, (60, 60), 30, (0,0,255), -1)
# 显示Opencv格式的图像
cv2.imshow("Image window", cv_image)
cv2.waitKey(3)
# 再将opencv格式额数据转换成ros image格式的数据发布
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(e)
if __name__ == '__main__':
try:
# 初始化ros节点
rospy.init_node("cv_bridge_test")
rospy.loginfo("Starting cv_bridge_test node")
image_converter()
rospy.spin()
except KeyboardInterrupt:
print("Shutting down cv_bridge_test node.")
cv2.destroyAllWindows()
根据最后通过rqt_graph生成的计算图来看,/usb_cam为通过launch文件生成的发布者节点,而/cv_bridge_test为if __name__ == '__main__':下初始化的节点cv_bridge_test作为订阅者。
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
cv2——opencv库
cv_bridge——通过调用此函数中的api进行ROS图像(imgmsg)与opencv图像(cv2)的转换。
sensor_msgs.msg——传感器数据类型,其中此处导入的是Image图像的数据类型。
self.image_pub = rospy.Publisher("cv_bridge_image", Image, queue_size=1)
self.bridge = CvBridge()
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
根据上面的计算图:
首先是订阅者,作用是接收usb_cam发布的图像原始信息,话题名/usb_cam/image_raw,话题名这里不能改的,因为在话题通信中,发布者和订阅者的话题名必须一样才能进行通信。
其次是发布者,注意这个发布者并不是和上面的订阅者成套,因为二者话题名不同,意味着二者是无法进行话题通信的。其中发布者发布的话题cv_bridge_image,数据类型为Image,可以通过rqt_image_view命令观察到。
self.bridge = CvBridge()定义一个句柄,之后可以灵活调用相关转换接口。
def callback(self,data):
# 使用cv_bridge将ROS的图像数据转换成OpenCV的图像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
# 在opencv的显示窗口中绘制一个圆,作为标记
(rows,cols,channels) = cv_image.shape
if cols > 60 and rows > 60 :
cv2.circle(cv_image, (60, 60), 30, (0,0,255), -1)
# 显示Opencv格式的图像
cv2.imshow("Image window", cv_image)
cv2.waitKey(3)
# 再将opencv格式额数据转换成ros image格式的数据发布
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(e)
这是回调函数,为话题通信订阅者的参数,其中通过最后一个参数调用了回调函数。
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
同时在主函数中,不停的spin回头,达到不停的循环订阅的目的。
rospy.spin()
在回调函数中:
第一步,ROS原始图像信息转化为opencv中的图像信息。
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
第二步,在opencv中进行图像处理
# 在opencv的显示窗口中绘制一个圆,作为标记
(rows,cols,channels) = cv_image.shape
if cols > 60 and rows > 60 :
cv2.circle(cv_image, (60, 60), 30, (0,0,255), -1)
# 显示Opencv格式的图像
cv2.imshow("Image window", cv_image)
cv2.waitKey(3)
第三步,opencv处理过的图像转化回为ROS图像信息,同时发布出去,发布后的图像信息可以通过ROS命令来查看。
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
分析完成,运行代码
roslaunch robot_vision usb_cam.launch
rosrun robot_vision cv_bridge_test.py
rqt_image_view
其中第二部如果是ROS—melodic版本肯定会报错,当然可以通过修改python版本声明来解决,用python2运行,但是现在python2已经被淘汰了,即使运行成功也毫无意义。
ROS报错:ROS-Melodic中cv_bridge报错_机械专业的计算机小白的博客-CSDN博客https://blog.csdn.net/wzfafabga/article/details/127239566?spm=1001.2014.3001.5502如上是解决这个问题的方法。
运行结果:
这是opencv输出的图像。
这是转化后并发布出的图像,其中话题名为cv_bridge_image,这在代码中有迹可查,而且符合逻辑。
这是原始图像,话题名为/usb_cam/image_raw,在代码中订阅者接收的图像数据类型消息。(rqt_image_view)
这是计算图(rqt_graph),其中只看见了两个节点文章来源:https://www.toymoban.com/news/detail-599364.html
文章来源地址https://www.toymoban.com/news/detail-599364.html
到了这里,关于2.ROS机器视觉——ROS图像(imgmsg)与opencv(cv2)对接的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!