參考:古月學(xué)院和ROS機(jī)器人開發(fā)實(shí)踐
目標(biāo):實(shí)現(xiàn)ROS系統(tǒng)讀取攝像頭的圖像,ROS讀取的圖像數(shù)據(jù)轉(zhuǎn)化為opencv中的圖像,opencv對(duì)接受的圖像進(jìn)行處理,最后返回給ROS系統(tǒng)可視化輸出。
安裝opencv庫(kù)與相關(guān)的接口包
由于我用的ROS-Melodic版本,其中roscore只能在python2中執(zhí)行,而視覺部分要在python3中執(zhí)行,故將包安裝在兩個(gè)python中。(重要操作,因?yàn)槠渌嘘P(guān)于視覺的庫(kù),比如pytorch,是需要python3的,如果默認(rèn)環(huán)境是python環(huán)境是python2,沒把相應(yīng)的包安裝進(jìn)python3,會(huì)報(bào)缺失依賴的錯(cuò)。)
(1條消息) ROS修改:ubuntu系統(tǒng)更改默認(rèn)python版本(重要操作)_機(jī)械專業(yè)的計(jì)算機(jī)小白的博客-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
下載好相應(yīng)的源碼,放在工作空間的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這個(gè)古月學(xué)院和ROS機(jī)器人開發(fā)實(shí)踐的源碼。
運(yùn)行的代碼
首先是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>
?創(chuàng)建一個(gè)節(jié)點(diǎn),之后作為發(fā)布者,攝像頭的圖像信息,其中參數(shù)必須和攝像頭參數(shù)對(duì)應(yīng),要不會(huì)報(bào)錯(cuò)。
其次是cv_bridge_test.py
?其中要修改python版本聲明,因?yàn)閙olodic版本默認(rèn)python版本是python2,但是現(xiàn)在視覺算法都是用的python3,在python3中才有實(shí)際意義。
修改了聲明:
#!/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):
# 創(chuàng)建cv_bridge,聲明圖像的發(fā)布者和訂閱者
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的圖像數(shù)據(jù)轉(zhuǎn)換成OpenCV的圖像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
# 在opencv的顯示窗口中繪制一個(gè)圓,作為標(biāo)記
(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格式額數(shù)據(jù)轉(zhuǎn)換成ros image格式的數(shù)據(jù)發(fā)布
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(e)
if __name__ == '__main__':
try:
# 初始化ros節(jié)點(diǎn)
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()
根據(jù)最后通過rqt_graph生成的計(jì)算圖來看,/usb_cam為通過launch文件生成的發(fā)布者節(jié)點(diǎn),而/cv_bridge_test為if __name__ == '__main__':下初始化的節(jié)點(diǎn)cv_bridge_test作為訂閱者。
import cv2
from cv_bridge import CvBridge, CvBridgeError
from sensor_msgs.msg import Image
cv2——opencv庫(kù)
cv_bridge——通過調(diào)用此函數(shù)中的api進(jìn)行ROS圖像(imgmsg)與opencv圖像(cv2)的轉(zhuǎn)換。
sensor_msgs.msg——傳感器數(shù)據(jù)類型,其中此處導(dǎo)入的是Image圖像的數(shù)據(jù)類型。
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)
根據(jù)上面的計(jì)算圖:
首先是訂閱者,作用是接收usb_cam發(fā)布的圖像原始信息,話題名/usb_cam/image_raw,話題名這里不能改的,因?yàn)樵谠掝}通信中,發(fā)布者和訂閱者的話題名必須一樣才能進(jìn)行通信。
其次是發(fā)布者,注意這個(gè)發(fā)布者并不是和上面的訂閱者成套,因?yàn)槎咴掝}名不同,意味著二者是無法進(jìn)行話題通信的。其中發(fā)布者發(fā)布的話題cv_bridge_image,數(shù)據(jù)類型為Image,可以通過rqt_image_view命令觀察到。
self.bridge = CvBridge()定義一個(gè)句柄,之后可以靈活調(diào)用相關(guān)轉(zhuǎn)換接口。
def callback(self,data):
# 使用cv_bridge將ROS的圖像數(shù)據(jù)轉(zhuǎn)換成OpenCV的圖像格式
try:
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
except CvBridgeError as e:
print(e)
# 在opencv的顯示窗口中繪制一個(gè)圓,作為標(biāo)記
(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格式額數(shù)據(jù)轉(zhuǎn)換成ros image格式的數(shù)據(jù)發(fā)布
try:
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
except CvBridgeError as e:
print(e)
這是回調(diào)函數(shù),為話題通信訂閱者的參數(shù),其中通過最后一個(gè)參數(shù)調(diào)用了回調(diào)函數(shù)。
self.image_sub = rospy.Subscriber("/usb_cam/image_raw", Image, self.callback)
?同時(shí)在主函數(shù)中,不停的spin回頭,達(dá)到不停的循環(huán)訂閱的目的。
rospy.spin()
在回調(diào)函數(shù)中:
第一步,ROS原始圖像信息轉(zhuǎn)化為opencv中的圖像信息。
cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")
第二步,在opencv中進(jìn)行圖像處理
# 在opencv的顯示窗口中繪制一個(gè)圓,作為標(biāo)記
(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處理過的圖像轉(zhuǎn)化回為ROS圖像信息,同時(shí)發(fā)布出去,發(fā)布后的圖像信息可以通過ROS命令來查看。
self.image_pub.publish(self.bridge.cv2_to_imgmsg(cv_image, "bgr8"))
分析完成,運(yùn)行代碼
roslaunch robot_vision usb_cam.launch
rosrun robot_vision cv_bridge_test.py
rqt_image_view
其中第二部如果是ROS—melodic版本肯定會(huì)報(bào)錯(cuò),當(dāng)然可以通過修改python版本聲明來解決,用python2運(yùn)行,但是現(xiàn)在python2已經(jīng)被淘汰了,即使運(yùn)行成功也毫無意義。
ROS報(bào)錯(cuò):ROS-Melodic中cv_bridge報(bào)錯(cuò)_機(jī)械專業(yè)的計(jì)算機(jī)小白的博客-CSDN博客https://blog.csdn.net/wzfafabga/article/details/127239566?spm=1001.2014.3001.5502如上是解決這個(gè)問題的方法。
運(yùn)行結(jié)果:
這是opencv輸出的圖像。
?這是轉(zhuǎn)化后并發(fā)布出的圖像,其中話題名為cv_bridge_image,這在代碼中有跡可查,而且符合邏輯。
?這是原始圖像,話題名為/usb_cam/image_raw,在代碼中訂閱者接收的圖像數(shù)據(jù)類型消息。(rqt_image_view)
?這是計(jì)算圖(rqt_graph),其中只看見了兩個(gè)節(jié)點(diǎn)文章來源:http://www.zghlxwxcb.cn/news/detail-599364.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-599364.html
到了這里,關(guān)于2.ROS機(jī)器視覺——ROS圖像(imgmsg)與opencv(cv2)對(duì)接的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!