ROS2での画像処理入門
RGB画像
このドキュメントでは、ROS2環境でロボットのカメラから取得した画像を処理する方法について説明します。具体的には、グレースケール変換とエッジ検出という2つの基本的な画像処理手法を実装する方法を学びます。
画像処理の概要
- ロボットのカメラから取得した画像をリアルタイムで処理
- OpenCVライブラリを使用した基本的な画像処理手法の実装
- ROS2のトピック通信を利用した画像データの送受信
1. 画像処理とは
画像処理とは、デジタル画像に対して何らかの操作を加えることで、画像の品質を向上させたり、画像から情報を抽出したりする技術です。ロボット工学では、画像処理は以下のような目的で使用されます:
- 環境認識: 周囲の環境を理解する
- 物体検出: 特定の物体を識別する
- 位置推定: ロボットの位置や姿勢を推定する
- 障害物回避: 障害物を検出して回避する
基本的な画像処理手法
- グレースケール変換: カラー画像を白黒画像に変換
- エッジ検出: 画像内の物体の輪郭を検出
- ノイズ除去: 画像内のノイズを除去
- 二値化: 画像を白と黒の2色に変換
2. ROS2での画像処理の基本
ROS2では、画像データはsensor_msgs/Image
型のメッセージとして扱われます。画像処理を行うためには、以下の手順が必要です:
- カメラからの画像をサブスクライブする
- ROS2の画像メッセージをOpenCV形式に変換する
- OpenCVを使用して画像処理を行う
- 必要に応じて処理結果を表示またはパブリッシュする
必要なライブラリ
- rclpy: ROS2のPythonクライアントライブラリ
- cv_bridge: ROS2の画像メッセージとOpenCV形式の画像を相互に変換するライブラリ
- OpenCV: 画像処理のためのライブラリ
3. グレースケール変換の実装
グレー画像
グレースケール変換は、カラー画像を白黒画像に変換する処理です。各ピクセルの色情報(RGB)を、明るさを表す単一の値に変換します。
実装手順
- ROS2ノードを作成する
- カメラからの画像をサブスクライブする
- 画像をグレースケールに変換する
- 変換結果を表示する
コード例
#!/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 rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSDurabilityPolicy
class ImageGrayProcessor(Node):
def __init__(self):
super().__init__('image_gray_processor')
# Set QoS profile
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
)
self.bridge = CvBridge()
self.get_logger().info("ImageGrayProcessor 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')
# Convert to grayscale
gray_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
# Display grayscale image
cv2.imshow("Grayscale Image", gray_image)
cv2.waitKey(1)
except Exception as e:
self.get_logger().error(f"Error processing image: {str(e)}")
def main(args=None):
rclpy.init(args=args)
node = ImageGrayProcessor()
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形式の画像を相互に変換
- グレースケール変換:
cv2.cvtColor
関数を使用してBGR形式からグレースケールに変換 - 画像表示:
cv2.imshow
関数を使用して処理結果を表示
4. エッジ検出の実装
Edge画像
エッジ検出は、画像内の物体の輪郭を検出する処理です。OpenCVでは、Cannyエッジ検出アルゴリズムが一般的に使用されます。実装手順
- ROS2ノードを作成する
- カメラからの画像をサブスクライブする
- 画像をグレースケールに変換する
- Cannyエッジ検出を適用する
- 処理結果を表示する
コード例
#!/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 rclpy.qos import QoSProfile, QoSReliabilityPolicy, QoSDurabilityPolicy
class ImageEdgeDetectionNode(Node):
def __init__(self):
super().__init__('image_edge_detection_node')
# Set QoS profile
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
)
self.bridge = CvBridge()
self.get_logger().info("Edge Detection 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')
# Convert to grayscale
gray_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
# Apply Canny edge detection
edges = cv2.Canny(gray_image, 50, 150)
# Display original image, grayscale image, and edge detection result
cv2.imshow("Original Image", cv_image)
cv2.imshow("Grayscale Image", gray_image)
cv2.imshow("Edge Detection", edges)
cv2.waitKey(1)
except Exception as e:
self.get_logger().error(f"Error processing image: {str(e)}")
def main(args=None):
rclpy.init(args=args)
node = ImageEdgeDetectionNode()
try:
rclpy.spin(node)
except KeyboardInterrupt:
node.get_logger().info("Shutting down...")
finally:
cv2.destroyAllWindows()
node.destroy_node()
rclpy.shutdown()
if __name__ == '__main__':
main()
コードの説明
- グレースケール変換: エッジ検出の前に画像をグレースケールに変換
- Cannyエッジ検出:
cv2.Canny
関数を使用してエッジを検出- 第2引数(50): 低い閾値
- 第3引数(150): 高い閾値
- 複数画像の表示: 元画像、グレースケール画像、エッジ検出結果を同時に表示
5. パッケージの作成と実行
パッケージの作成
# グレースケール変換パッケージの作成
ros2 pkg create --build-type ament_python image_gray_processor --dependencies rclpy sensor_msgs cv_bridge opencv-python --node-name image_gray_processor
# エッジ検出パッケージの作成
ros2 pkg create --build-type ament_python image_edge_detection --dependencies rclpy sensor_msgs cv_bridge opencv-python --node-name image_edge_detection
パッケージのビルド
cd ~/ros2_ws
colcon build --packages-select image_gray_processor image_edge_detection
ノードの実行
# グレースケール変換ノードの実行
ros2 run image_gray_processor image_gray_processor
# エッジ検出ノードの実行
ros2 run image_edge_detection image_edge_detection
6. 画像処理の応用
実用的な応用例
- 物体追跡: 特定の物体を追跡する
- 顔認識: 人の顔を検出・認識する
- 文字認識(OCR): 画像内の文字を認識する
- 障害物検出: ロボットの前方にある障害物を検出する
研究・開発への応用
- SLAM(Simultaneous Localization and Mapping): 環境のマップを作成しながら位置を推定する
- 物体認識: 様々な物体を識別する
- ジェスチャー認識: 人のジェスチャーを認識する
演習
基本的な画像処理
- グレースケール変換ノードを実行して、カメラ画像が白黒に変換される様子を観察してみましょう
- エッジ検出ノードを実行して、物体の輪郭が検出される様子を観察してみましょう
パラメータの調整
- Cannyエッジ検出の閾値を変更して、エッジ検出結果の変化を観察してみましょう