ROS2でのYOLO物体検出入門

このドキュメントでは、ROS2環境でロボットのカメラから取得した画像に対して、YOLO(You Only Look Once)を使用して物体検出を行う方法について説明します。YOLOは、リアルタイムで物体を検出できる高性能なディープラーニングモデルです。

YOLO物体検出の概要

  • ロボットのカメラから取得した画像をリアルタイムで処理
  • ディープラーニングを使用した物体検出の実装
  • 検出結果の可視化とROS2トピックへのパブリッシュ

1. YOLOとは

YOLO(You Only Look Once)は、画像内の物体を検出するためのディープラーニングモデルです。従来の物体検出手法と比較して、以下のような特徴があります:

  • 高速性: リアルタイムでの物体検出が可能
  • 高精度: 最新のYOLOモデルは高い検出精度を実現
  • 使いやすさ: 事前学習済みモデルが提供されており、簡単に利用可能
  • 多様性: 様々な物体クラスを検出可能

YOLOの主な用途

  • 物体検出: 画像内の物体の位置と種類を検出
  • 物体追跡: 動画内の物体を追跡
  • セグメンテーション: 画像内の物体の領域を特定
  • 姿勢推定: 物体の姿勢を推定

2. ROS2でのYOLO物体検出の基本

ROS2でYOLO物体検出を行うためには、以下の手順が必要です:

  1. カメラからの画像をサブスクライブする
  2. ROS2の画像メッセージをOpenCV形式に変換する
  3. YOLOモデルを使用して物体検出を行う
  4. 検出結果を可視化し、必要に応じてパブリッシュする

必要なライブラリ

  • rclpy: ROS2のPythonクライアントライブラリ
  • cv_bridge: ROS2の画像メッセージとOpenCV形式の画像を相互に変換するライブラリ
  • OpenCV: 画像処理のためのライブラリ
  • Ultralytics: YOLOモデルを提供するライブラリ

3. YOLO物体検出の実装

YOLO物体検出を実装するためのROS2ノードを作成します。このノードは、カメラからの画像をサブスクライブし、YOLOモデルを使用して物体検出を行い、検出結果を可視化してパブリッシュします。

実装手順

  1. ROS2ノードを作成する
  2. カメラからの画像をサブスクライブする
  3. YOLOモデルを読み込む
  4. 画像に対して物体検出を行う
  5. 検出結果を可視化し、パブリッシュする

コード例

image_yolo_detection.py

#!/usr/bin/env python3
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from cv_bridge import CvBridge
import cv2
from ultralytics import YOLO
from rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSDurabilityPolicy
from std_msgs.msg import String
import json


class ImageYoloDetection(Node):
    def __init__(self):
        super().__init__('image_yolo_detection')
        
        # Set QoS profile for image data transmission
        qos_profile = QoSProfile(
            depth=5,
            reliability=QoSReliabilityPolicy.BEST_EFFORT,
            durability=QoSDurabilityPolicy.VOLATILE
        )
        
        # Subscribe to camera image topic
        self.subscription = self.create_subscription(
            Image,
            '/kachaka/front_camera/image_raw',
            self.image_callback,
            qos_profile
        )
        
        # Create publisher for detection results
        self.publisher = self.create_publisher(
            Image,
            '/image_yolo_detection/image',
            qos_profile
        )

        # Publish detected object information
        self.object_publisher = self.create_publisher(
            String,
            '/image_yolo_detection/objects',
            qos_profile
        )

        self.bridge = CvBridge()

        # Load YOLOv8 model
        self.model = YOLO('yolov8x.pt')
        
        # Record previously detected objects
        self.last_detected_objects = set()
        
        self.get_logger().info("YOLOv8 node has started.")

    def image_callback(self, msg):
        try:
            # Convert ROS Image message to OpenCV image
            cv_image = self.bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')
        except Exception as e:
            self.get_logger().error("Error converting image: " + str(e))
            return

        # Perform object detection using YOLOv8
        results = self.model(cv_image)

        # Draw detection results on the image
        annotated_image = results[0].plot()

        # Get detected objects
        detected_objects = set()
        for result in results:
            for box in result.boxes:
                class_id = int(box.cls[0])
                class_name = result.names[class_id]
                detected_objects.add(class_name)

        # Publish information if new objects are detected
        new_objects = detected_objects - self.last_detected_objects
        if new_objects:
            # Publish detected object information in JSON format
            object_info = {
                "objects": list(new_objects),
                "timestamp": self.get_clock().now().nanoseconds * 1e-9
            }
            object_msg = String()
            object_msg.data = json.dumps(object_info)
            self.object_publisher.publish(object_msg)
            
            self.get_logger().info(f"Detected objects: {new_objects}")

        # Update detection results
        self.last_detected_objects = detected_objects

        # Convert detection results to ROS Image message and publish
        try:
            annotated_msg = self.bridge.cv2_to_imgmsg(annotated_image, encoding='bgr8')
            self.publisher.publish(annotated_msg)
        except Exception as e:
            self.get_logger().error("Error converting detection results: " + str(e))

        # Display detection results in a window
        cv2.imshow("YOLOv8 Detection", annotated_image)
        cv2.waitKey(1)

def main(args=None):
    rclpy.init(args=args)
    node = ImageYoloDetection()
    try:
        rclpy.spin(node)
    except KeyboardInterrupt:
        node.get_logger().info("Shutting down...")
    finally:
        cv2.destroyAllWindows()
        node.destroy_node()
        rclpy.shutdown()

if __name__ == '__main__':
    main()

コードの説明

  • QoSプロファイル: 画像データの送受信に適したQoSプロファイルを設定
  • サブスクリプション: カメラからの画像をサブスクライブ
  • パブリッシャー: 検出結果をパブリッシュするトピックを作成
  • cv_bridge: ROS2の画像メッセージとOpenCV形式の画像を相互に変換
  • YOLOモデル: Ultralyticsライブラリを使用してYOLOv8モデルを読み込み
  • 物体検出: model(cv_image)を使用して物体検出を実行
  • 結果の可視化: results[0].plot()を使用して検出結果を画像に描画
  • 結果のパブリッシュ: 検出結果をROS Imageメッセージに変換してパブリッシュ
  • 結果の表示: cv2.imshow関数を使用して検出結果を表示

4. YOLOモデルの種類

YOLOには、様々なモデルが提供されています。主なモデルは以下の通りです:

YOLOv8モデル

  • YOLOv8n: 最も軽量なモデル(高速だが精度は低め)
  • YOLOv8s: 小型モデル(バランスの取れた性能)
  • YOLOv8m: 中型モデル(より高い精度)
  • YOLOv8l: 大型モデル(高精度だが低速)
  • YOLOv8x: 最大モデル(最高精度だが最も低速)

モデルの選択

  • 処理速度重視: YOLOv8nやYOLOv8sを選択
  • 精度重視: YOLOv8lやYOLOv8xを選択
  • バランス重視: YOLOv8mを選択

5. パッケージの作成と実行

パッケージの作成

# YOLO物体検出パッケージの作成
ros2 pkg create --build-type ament_python image_yolo_detection --dependencies rclpy sensor_msgs cv_bridge opencv-python ultralytics std_msgs --node-name image_yolo_detection

依存関係のインストール

# Ultralyticsライブラリのインストール
pip install ultralytics

パッケージのビルド

cd ~/ros2_ws
colcon build --packages-select image_yolo_detection

ノードの実行

# YOLO物体検出ノードの実行
ros2 run image_yolo_detection image_yolo_detection

6. YOLO物体検出の応用

実用的な応用例

  • 物体追跡: 検出した物体を追跡する
  • 物体計数: 特定の物体の数をカウントする
  • 異常検知: 通常と異なる物体を検出する
  • ロボットのナビゲーション: 物体を避けながら移動する

研究・開発への応用

  • カスタムデータセットでの学習: 特定の物体に対してYOLOモデルを学習させる
  • マルチモーダル検出: 画像と他のセンサーデータを組み合わせた検出
  • リアルタイム物体追跡: 動画内の物体をリアルタイムで追跡
  • 3D物体検出: 2D画像から3D物体の位置と姿勢を推定

演習

基本的な物体検出

  1. YOLO物体検出ノードを実行して、カメラ画像から物体が検出される様子を観察してみましょう
  2. 異なるYOLOモデル(YOLOv8n、YOLOv8s、YOLOv8m、YOLOv8l、YOLOv8x)を使用して、検出精度と処理速度の違いを観察してみましょう

パラメータの調整

  1. YOLOモデルの信頼度閾値を変更して、検出結果の変化を観察してみましょう
  2. 検出対象のクラスを制限して、特定の物体のみを検出するようにしてみましょう

ノードの拡張

  1. 物体検出ノードに検出確率の情報を追加してみましょう
  2. 検出された物体の数を表示する機能を追加してみましょう
  3. 物体の位置情報(画面のどの部分に検出されたか)を計算して表示してみましょう

内容

ROS2とYOLOを使って、ロボットのカメラ画像からリアルタイムで物体を検出してみよう!