2. ROS マシン ビジョン - ROS イメージ (imgmsg) と opencv (cv2) のドッキング

参考: Gu Yue CollegeとROSロボット開発実習

目標: カメラの画像を読み取る ROS システムを実現するには、ROS によって読み取られた画像データが opencv で画像に変換され、opencv は受け取った画像を処理し、最後にそれを ROS システムに返して視覚的に出力します。

opencv ライブラリと関連インターフェイス パッケージをインストールする

私はROS-Melodic版を使用しているため、roscoreはpython2でしか実行できず、ビジョン部分はpython3で実行する必要があるため、パッケージは2つのpythonにインストールされます。(pytorch などの他のビジョン関連ライブラリには python3 が必要なため、重要な操作です。デフォルト環境が python2 で、対応するパッケージが python3 にインストールされていない場合は、依存関係の欠落エラーが報告されます。)

(1 メッセージ) ROS 変更: ubuntu システムがデフォルトの Python バージョンを変更します (重要な操作) 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 メインの guyuehome/guyueclass (github.com) https://github.com/guyuehome/guyueclass/tree/main/planning%26perception/robot_vision_beginner/robot_visionこの Guyue Academy および ROS ロボット開発実践ソース コード。

実行中のコード

1 つ目は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 のバージョン宣言は変更する必要があります。これは、モロディック バージョンのデフォルトの 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 は起動ファイルによって生成されたパブリッシャ ノードであり、/cv_bridge_test は __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 — センサー データ タイプ。画像イメージのデータ タイプがここにインポートされます。

        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)

上記の計算グラフによると、次のようになります。

1 つ目はサブスクライバーで、その役割はusb_camによってパブリッシュされた元のイメージ情報、トピック名/usb_cam/image_rawを受信することです。トピック通信ではパブリッシャーとサブスクライバーのトピック名が使用されるため、ここでトピック名を変更することはできません。通信するには同じでなければなりません。

2 番目はパブリッシャーです。このパブリッシャーは上記のサブスクライバーと同じではないことに注意してください。これは、両者のトピック名が異なるためであり、このトピックに関して両者は通信できないことを意味します。このうち、発行者によって発行されたトピック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)

 同時に、メイン関数では、スピンはノンストップで戻り、ノンストップの循環サブスクリプションの目的を達成します。

rospy.spin()

コールバック関数内:

最初のステップでは、ROS の元の画像情報が opencv の画像情報に変換されます。

cv_image = self.bridge.imgmsg_to_cv2(data, "bgr8")

2 番目のステップ、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)

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が廃止されてしまったのでやっても意味がありません正常に実行されます。

icon-default.png?t=M85BROSエラー: ROS-Melodic メソッドの cv_bridge エラー

操作結果:

これはopencvによって出力された画像です。

 これは変換されリリースされたイメージで、トピック名はcv_bridge_imageで、コード内で追跡可能で論理的です。

 これは生の画像であり、トピック名は/usb_cam/image_rawであり、サブスクライバがコードで受信する画像データ型メッセージです。(rqt_image_view)

 これは計算グラフ (rqt_graph) であり、ノードが 2 つだけ表示されています。

おすすめ

転載: blog.csdn.net/wzfafabga/article/details/127237869