Ultralytics YOLO27:

ROS (Robot İşletim Sistemi) hızlı başlangıç kılavuzu#

Bu kılavuz, gerçek zamanlı nesne algılama ve segmentasyon işlemlerini RGB görüntüler, derinlik görüntüleri ve nokta bulutları üzerinde çalıştırmak için Ultralytics YOLO'yu ROS1 (rospy) veya ROS2 (rclpy) ile nasıl entegre edeceğini gösterir.

Önce YOLO'yu ROS ile kurma bölümüne, ardından RGB görüntüleri, derinlik görüntüleri veya nokta bulutları bölümüne geç.

ROS nedir?#

Robot İşletim Sistemi (ROS), robotik araştırmalarında ve endüstride yaygın olarak kullanılan açık kaynaklı bir çatıdır. ROS, geliştiricilerin robot uygulamaları oluşturmasına yardımcı olan bir kütüphane ve araç koleksiyonu sağlar. ROS, çeşitli robotik platformlarla çalışacak şekilde tasarlanmıştır; bu da onu robotik uzmanları için esnek ve güçlü bir araç hâline getirir. Kısa bir tanıtım için Open Robotics'in üç dakikalık ROS Tanıtımı videosunu izle.

ROS'un Temel Özellikleri#

  1. Modüler Mimari: ROS, geliştiricilerin düğümler adı verilen daha küçük, yeniden kullanılabilir bileşenleri birleştirerek karmaşık sistemler oluşturmasına olanak tanıyan modüler bir mimariye sahiptir. Her düğüm genellikle belirli bir işlevi yerine getirir ve düğümler, konular veya hizmetler üzerinden mesajlar kullanarak birbirleriyle iletişim kurar.

  2. İletişim Ara Katmanı: ROS, süreçler arası iletişimi ve dağıtık bilişimi destekleyen sağlam bir iletişim altyapısı sunar. Bu, veri akışları (konular) için yayınla-abone ol modelinin ve hizmet çağrıları için istek-yanıt modelinin kullanılmasıyla sağlanır.

  3. Donanım Soyutlama: ROS, donanım üzerinde bir soyutlama katmanı sağlayarak geliştiricilerin cihazdan bağımsız kod yazmasına olanak tanır. Böylece aynı kod farklı donanım kurulumlarıyla kullanılabilir ve entegrasyon ile denemeler kolaylaşır.

  4. Araçlar ve Yardımcı Programlar: ROS; görselleştirme, hata ayıklama ve simülasyon için zengin bir araç ve yardımcı program koleksiyonuyla birlikte gelir. Örneğin RViz, sensör verilerini ve robot durumu bilgilerini görselleştirmek için kullanılırken Gazebo, algoritmaları ve robot tasarımlarını test etmek için güçlü bir simülasyon ortamı sağlar.

  5. Geniş Ekosistem: ROS ekosistemi geniş ve sürekli büyümektedir; navigasyon, manipülasyon, algılama ve daha fazlası gibi farklı robotik uygulamalar için çok sayıda paket mevcuttur. Topluluk, bu paketlerin geliştirilmesine ve bakımına aktif olarak katkıda bulunur.

ROS Sürümlerinin Gelişimi

ROS, 2007'deki geliştirilmesinden bu yana birden çok sürümden geçerek ROS 1 ve ROS 2 olarak ikiye ayrılmıştır. Aşağıdaki mevcut örneklerde ROS1 Noetic kullanılır; ROS2'yi Kullanma bölümündeki kompakt bağdaştırıcılar, güncel ROS2 sürümleri için karşılık gelen rclpy arayüzlerini gösterir.

ROS 1 ve ROS 2#

ROS 1 robotik geliştirme için sağlam bir temel sunarken ROS 2, aşağıdakileri sağlayarak eksikliklerini giderir:

  • Gerçek Zamanlı Performans: Gerçek zamanlı sistemler ve belirlen deterministik davranış için geliştirilmiş destek.
  • Güvenlik: Çeşitli ortamlarda güvenli ve güvenilir çalışma için geliştirilmiş güvenlik özellikleri.
  • Ölçeklenebilirlik: Çok robotlu sistemler ve büyük ölçekli dağıtımlar için daha iyi destek.
  • Platformlar Arası Destek: Windows ve macOS dâhil olmak üzere Linux dışındaki çeşitli işletim sistemleriyle genişletilmiş uyumluluk.
  • Esnek İletişim: Daha esnek ve verimli süreçler arası iletişim için DDS kullanımı.

ROS Mesajları ve Konuları#

ROS'ta düğümler arasındaki iletişim mesajlar ve konular aracılığıyla sağlanır. Mesaj, düğümler arasında değiş tokuş edilen bilgileri tanımlayan bir veri yapısıdır; konu ise mesajların gönderilip alındığı adlandırılmış bir kanaldır. Düğümler bir konuya mesaj yayınlayabilir veya bir konunun mesajlarına abone olabilir; bu da birbirleriyle iletişim kurmalarını sağlar. Bu yayınla-abone ol modeli, düğümler arasında eşzamansız iletişime ve gevşek bağlılığa olanak tanır. Bir robotik sistemdeki her sensör veya aktüatör genellikle verileri bir konuya yayınlar; diğer düğümler de bu verileri işleme veya kontrol amacıyla kullanabilir. Bu kılavuz kapsamında Image, Depth ve PointCloud mesajlarına ve kamera konularına odaklanacağız.

Ultralytics YOLO'yu ROS ile Kurma#

ROS1 örnekleri, ROSbot ROS deposunun bir çatalı olan bu ROS ortamı kullanılarak test edilmiştir. Aynı YOLO ve NumPy işleme adımları ROS2'de de geçerlidir; yalnızca düğüm yaşam döngüsü ve mesaj dönüştürme farklıdır.

Husarion ROSbot 2 PRO autonomous robot platform

Bağımlılıkların Kurulumu#

ROS ortamının yanı sıra aşağıdaki bağımlılıkları da yüklemen gerekir:

  • ROS NumPy paketi: ROS Image mesajları ile NumPy dizileri arasında hızlı dönüşüm için gereklidir.

    pip install ros_numpy
  • Ultralytics paketi:

    pip install ultralytics

ROS2'yi Kullanma#

ROS2, rospy yerine rclpy kullanır ve görüntü dönüşümünde ros_numpy yerine cv_bridge kullanır. Aşağıdaki düğüm, aşağıda gösterilen RGB algılama akışının eksiksiz ROS2 karşılığıdır; modelleri bir kez örneklendir ve geri çağırmalar arasında yeniden kullan.

import cv_bridge
import rclpy
from rclpy.node import Node
from rclpy.qos import qos_profile_sensor_data
from sensor_msgs.msg import Image

from ultralytics import YOLO

class UltralyticsNode(Node):
    """Run YOLO detection on ROS2 image messages."""

    def __init__(self):
        """Initialize the ROS2 node, model, and image interfaces."""
        super().__init__("ultralytics")
        self.bridge = cv_bridge.CvBridge()
        self.model = YOLO("yolo26m.pt")
        self.publisher = self.create_publisher(Image, "/ultralytics/detection/image", 5)
        self.create_subscription(Image, "/camera/color/image_raw", self.callback, qos_profile_sensor_data)

    def callback(self, message):
        """Publish the annotated camera frame."""
        image = self.bridge.imgmsg_to_cv2(message, desired_encoding="bgr8")
        annotated = self.model(image)[0].plot(show=False)
        self.publisher.publish(self.bridge.cv2_to_imgmsg(annotated, encoding="bgr8"))

def main(args=None):
    """Start the ROS2 node."""
    rclpy.init(args=args)
    node = UltralyticsNode()
    rclpy.spin(node)
    node.destroy_node()
    rclpy.shutdown()

if __name__ == "__main__":
    main()

Derinlik görüntüleri için aşağıdaki derinlik işleme kodunu yeniden kullan ve yalnızca mesaj edinme ile dönüştürme kısımlarını değiştir:

self.create_subscription(Image, "/camera/color/image_raw", self.rgb_callback, qos_profile_sensor_data)
self.create_subscription(Image, "/camera/depth/image_raw", self.depth_callback, qos_profile_sensor_data)

def rgb_callback(self, message):
    self.rgb_image = self.bridge.imgmsg_to_cv2(message, desired_encoding="bgr8")

def depth_callback(self, message):
    depth_image = self.bridge.imgmsg_to_cv2(message, desired_encoding="passthrough")
    # Apply the NumPy mask and distance calculation from the depth example below.

Nokta bulutları için ROS2, sensor_msgs_py.point_cloud2 sağlar; düzenli bulutu bir kez dönüştür, ardından aşağıdaki NumPy segmentasyonunu ve 3B eşlemesini yeniden kullan:

from sensor_msgs_py import point_cloud2

points = point_cloud2.read_points_numpy(message, field_names=("x", "y", "z", "rgb"))
points = points.reshape(message.height, message.width, 4)

Ultralytics'i ROS sensor_msgs/Image ile Kullanma#

sensor_msgs/Image mesaj türü, ROS'ta görüntü verilerini temsil etmek için yaygın olarak kullanılır. Kodlama, yükseklik, genişlik ve piksel verileri için alanlar içerdiğinden kameralar veya diğer sensörler tarafından yakalanan görüntülerin iletilmesi için uygundur. Image mesajları; görsel algılama, nesne algılama ve navigasyon gibi görevlerde robotik uygulamalarda yaygın olarak kullanılır.

Detection and Segmentation in ROS Gazebo

Görüntülerin Adım Adım Kullanımı#

Aşağıdaki kod parçacığı, Ultralytics YOLO paketinin ROS ile nasıl kullanılacağını gösterir. Bu örnekte bir kamera konusuna abone oluyor, gelen görüntüyü YOLO kullanarak işliyor ve algılanan nesneleri algılama ile segmentasyon için yeni konulara yayınlıyoruz.

Önce gerekli kütüphaneleri içe aktar ve iki modeli örneklendir: biri segmentasyon, diğeri algılama için. ROS ana yöneticisiyle iletişimi etkinleştirmek üzere ultralytics adıyla bir ROS düğümü başlat. Kararlı bir bağlantı sağlamak için kısa bir bekleme ekliyoruz; böylece düğüm devam etmeden önce bağlantıyı kurmak için yeterli zamana sahip oluyor.

import time

import rospy

from ultralytics import YOLO

detection_model = YOLO("yolo26m.pt")
segmentation_model = YOLO("yolo26m-seg.pt")
rospy.init_node("ultralytics")
time.sleep(1)

İki ROS konusu başlat: biri algılama, diğeri segmentasyon için. Bu konular, açıklamalı görüntüleri yayınlamak ve daha sonraki işlemler için erişilebilir hâle getirmek amacıyla kullanılacaktır. Düğümler arasındaki iletişim sensor_msgs/Image mesajları kullanılarak sağlanır.

from sensor_msgs.msg import Image

det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
seg_image_pub = rospy.Publisher("/ultralytics/segmentation/image", Image, queue_size=5)

Son olarak /camera/color/image_raw konusundaki mesajları dinleyen ve her yeni mesaj için bir geri çağırma işlevi çağıran bir abone oluştur. Bu geri çağırma işlevi sensor_msgs/Image türündeki mesajları alır, bunları ros_numpy kullanarak NumPy dizisine dönüştürür, önceden örneklendirilen YOLO modelleriyle görüntüleri işler, görüntülere açıklama ekler ve ardından bunları ilgili konulara geri yayınlar: algılama için /ultralytics/detection/image, segmentasyon için /ultralytics/segmentation/image.

import ros_numpy

def callback(data):
    """Callback function to process image and publish annotated images."""
    array = ros_numpy.numpify(data)
    if det_image_pub.get_num_connections():
        det_result = detection_model(array)
        det_annotated = det_result[0].plot(show=False)
        det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))

    if seg_image_pub.get_num_connections():
        seg_result = segmentation_model(array)
        seg_annotated = seg_result[0].plot(show=False)
        seg_image_pub.publish(ros_numpy.msgify(Image, seg_annotated, encoding="rgb8"))

rospy.Subscriber("/camera/color/image_raw", Image, callback)

while True:
    rospy.spin()
Eksiksiz kod
import time

import ros_numpy
import rospy
from sensor_msgs.msg import Image

from ultralytics import YOLO

detection_model = YOLO("yolo26m.pt")
segmentation_model = YOLO("yolo26m-seg.pt")
rospy.init_node("ultralytics")
time.sleep(1)

det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
seg_image_pub = rospy.Publisher("/ultralytics/segmentation/image", Image, queue_size=5)

def callback(data):
    """Callback function to process image and publish annotated images."""
    array = ros_numpy.numpify(data)
    if det_image_pub.get_num_connections():
        det_result = detection_model(array)
        det_annotated = det_result[0].plot(show=False)
        det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))

    if seg_image_pub.get_num_connections():
        seg_result = segmentation_model(array)
        seg_annotated = seg_result[0].plot(show=False)
        seg_image_pub.publish(ros_numpy.msgify(Image, seg_annotated, encoding="rgb8"))

rospy.Subscriber("/camera/color/image_raw", Image, callback)

while True:
    rospy.spin()
Hata Ayıklama

ROS (Robot İşletim Sistemi) düğümlerinde hata ayıklamak, sistemin dağıtık yapısı nedeniyle zor olabilir. Bu süreçte çeşitli araçlar yardımcı olabilir:

  1. rostopic echo <TOPIC-NAME> : Bu komut, belirli bir konuda yayınlanan mesajları görüntülemeni ve veri akışını incelemeni sağlar.
  2. rostopic list: ROS sistemindeki tüm kullanılabilir konuları listelemek ve etkin veri akışlarına genel bakış elde etmek için bu komutu kullan.
  3. rqt_graph: Bu görselleştirme aracı, düğümler arasındaki iletişim grafiğini görüntüleyerek düğümlerin nasıl birbirine bağlandığı ve nasıl etkileşim kurduğu hakkında bilgi sağlar.
  4. 3B gösterimler gibi daha karmaşık görselleştirmeler için RViz kullanabilirsin. RViz (ROS Görselleştirme), ROS için güçlü bir 3B görselleştirme aracıdır. Robotunun ve çevresinin durumunu gerçek zamanlı olarak görselleştirmeni sağlar. RViz ile sensör verilerini (ör. sensor_msgs/Image), robot modeli durumlarını ve çeşitli diğer bilgi türlerini görüntüleyebilir; böylece robotik sisteminin davranışında hata ayıklamak ve bunu anlamak kolaylaşır.

Algılanan Sınıfları std_msgs/String ile Yayınlama#

Standart ROS mesajları std_msgs/String mesajlarını da içerir. Birçok uygulamada açıklamalı görüntünün tamamını yeniden yayınlamak gerekli değildir; bunun yerine yalnızca robotun görüş alanındaki sınıflar yeterlidir. Aşağıdaki örnek, algılanan sınıfları /ultralytics/detection/classes konusunda yeniden yayınlamak için std_msgs/String mesajlarının nasıl kullanılacağını gösterir. Bu mesajlar daha hafiftir ve temel bilgileri sağlar; bu nedenle çeşitli uygulamalar için değerlidir.

Örnek Kullanım Durumu#

Kameraya ve nesne algılama modeline sahip bir depo robotunu düşün. Robot, ağ üzerinden büyük açıklamalı görüntüler göndermek yerine algılanan sınıfların listesini std_msgs/String mesajları olarak yayınlayabilir. Örneğin robot "box", "pallet" ve "forklift" gibi nesneler algıladığında bu sınıfları /ultralytics/detection/classes konusuna yayınlar. Bu bilgiler, merkezi bir izleme sistemi tarafından envanteri gerçek zamanlı olarak takip etmek, engellerden kaçınmak üzere robotun yol planlamasını optimize etmek veya algılanan bir kutuyu alma gibi belirli eylemleri tetiklemek için kullanılabilir. Bu yaklaşım, iletişim için gereken bant genişliğini azaltır ve kritik verilerin iletilmesine odaklanır.

Dizelerin Adım Adım Kullanımı#

Bu örnek, Ultralytics YOLO paketinin ROS ile nasıl kullanılacağını gösterir. Bu örnekte bir kamera konusuna abone oluyor, gelen görüntüyü YOLO kullanarak işliyor ve algılanan nesneleri std_msgs/String mesajlarını kullanarak /ultralytics/detection/classes adlı yeni konuya yayınlıyoruz. ros_numpy paketi, ROS Image mesajını YOLO ile işlenmek üzere NumPy dizisine dönüştürmek için kullanılır.

import time

import ros_numpy
import rospy
from sensor_msgs.msg import Image
from std_msgs.msg import String

from ultralytics import YOLO

detection_model = YOLO("yolo26m.pt")
rospy.init_node("ultralytics")
time.sleep(1)
classes_pub = rospy.Publisher("/ultralytics/detection/classes", String, queue_size=5)

def callback(data):
    """Callback function to process image and publish detected classes."""
    array = ros_numpy.numpify(data)
    if classes_pub.get_num_connections():
        det_result = detection_model(array)
        classes = det_result[0].boxes.cls.cpu().numpy().astype(int)
        names = [det_result[0].names[i] for i in classes]
        classes_pub.publish(String(data=str(names)))

rospy.Subscriber("/camera/color/image_raw", Image, callback)
while True:
    rospy.spin()

Ultralytics'i ROS Derinlik Görüntüleriyle Kullanma#

ROS, RGB görüntülerinin yanı sıra nesnelerin kameraya olan uzaklığı hakkında bilgi sağlayan derinlik görüntülerini de destekler. Derinlik görüntüleri; engellerden kaçınma, 3B haritalama ve konum belirleme gibi robotik uygulamalar için kritik öneme sahiptir.

Derinlik görüntüsü, her pikselin kameradan bir nesneye olan uzaklığı temsil ettiği bir görüntüdür. Renkleri yakalayan RGB görüntülerinin aksine derinlik görüntüleri uzamsal bilgileri yakalar ve robotların çevrelerinin 3B yapısını algılamasını sağlar.

Derinlik Görüntülerini Edinme

Derinlik görüntüleri çeşitli sensörler kullanılarak elde edilebilir:

  1. Stereo Kameralar: Görüntü farklılığına göre derinliği hesaplamak için iki kamera kullanır.
  2. Uçuş Süresi (ToF) Kameraları: Işığın bir nesneden geri dönmesinin ne kadar sürdüğünü ölçer.
  3. Yapılandırılmış Işık Sensörleri: Bir desen yansıtır ve yüzeylerdeki deformasyonunu ölçer.

YOLO'yu Derinlik Görüntüleriyle Kullanma#

ROS'ta derinlik görüntüleri; kodlama, yükseklik, genişlik ve piksel verileri için alanlar içeren sensor_msgs/Image mesaj türüyle temsil edilir. Derinlik görüntülerinin kodlama alanında genellikle piksel başına 16 bitlik işaretsiz tamsayıyı belirten "16UC1" gibi bir biçim kullanılır; her değer nesneye olan uzaklığı temsil eder. Derinlik görüntüleri, çevrenin daha kapsamlı bir görünümünü sağlamak için genellikle RGB görüntüleriyle birlikte kullanılır.

YOLO kullanarak hem RGB hem de derinlik görüntülerindeki bilgileri çıkarmak ve birleştirmek mümkündür. Örneğin YOLO, bir RGB görüntüsündeki nesneleri algılayabilir ve bu algılama, derinlik görüntüsündeki karşılık gelen bölgeleri belirlemek için kullanılabilir. Böylece algılanan nesneler için hassas derinlik bilgileri çıkarılabilir ve robotun çevresini üç boyutlu olarak anlama yeteneği geliştirilebilir.

RGB-D Kameralar

Derinlik görüntüleriyle çalışırken RGB ve derinlik görüntülerinin doğru şekilde hizalandığından emin olmak çok önemlidir. Intel RealSense serisi gibi RGB-D kameralar, senkronize RGB ve derinlik görüntüleri sağlayarak her iki kaynaktaki bilgilerin birleştirilmesini kolaylaştırır. Ayrı RGB ve derinlik kameraları kullanıyorsan doğru hizalamayı sağlamak için bunları kalibre etmen kritik önem taşır.

Derinliğin Adım Adım Kullanımı#

Bu örnekte YOLO'yu bir görüntüyü segmentlere ayırmak ve çıkarılan maskeyi derinlik görüntüsündeki nesneyi segmentlere ayırmak için kullanıyoruz. Böylece ilgilenilen nesnenin her pikselinin kameranın odak merkezine olan uzaklığını belirleyebiliyoruz. Bu uzaklık bilgisiyle kamera ile sahnedeki belirli nesne arasındaki mesafeyi hesaplayabiliriz. Gerekli kütüphaneleri içe aktararak, bir ROS düğümü oluşturarak ve bir segmentasyon modeli ile ROS konusu örneklendirerek başla.

import time

import rospy
from std_msgs.msg import String

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)

segmentation_model = YOLO("yolo26m-seg.pt")

classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)

Ardından gelen derinlik görüntüsü mesajını işleyen bir geri çağırma işlevi tanımla. İşlev, derinlik görüntüsü ve RGB görüntüsü mesajlarını bekler, bunları NumPy dizilerine dönüştürür ve segmentasyon modelini RGB görüntüsüne uygular. Daha sonra algılanan her nesne için segmentasyon maskesini çıkarır ve derinlik görüntüsünü kullanarak nesnenin kameraya olan ortalama uzaklığını hesaplar. Çoğu sensörün, klip mesafesi olarak bilinen ve ötesinde değerlerin inf (np.inf) olarak gösterildiği bir maksimum mesafesi vardır. İşlemeden önce bu boş değerleri filtrelemek ve bunlara 0 değerini atamak önemlidir. Son olarak algılanan nesneleri ortalama uzaklıklarıyla birlikte /ultralytics/detection/distance konusuna yayınlar.

import numpy as np
import ros_numpy
from sensor_msgs.msg import Image

def callback(data):
    """Callback function to process depth image and RGB image."""
    image = rospy.wait_for_message("/camera/color/image_raw", Image)
    image = ros_numpy.numpify(image)
    depth = ros_numpy.numpify(data)
    result = segmentation_model(image)

    all_objects = []
    for index, cls in enumerate(result[0].boxes.cls):
        class_index = int(cls.cpu().numpy())
        name = result[0].names[class_index]
        mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
        obj = depth[mask == 1]
        obj = obj[~np.isnan(obj)]
        avg_distance = np.mean(obj) if len(obj) else np.inf
        all_objects.append(f"{name}: {avg_distance:.2f}m")

    classes_pub.publish(String(data=str(all_objects)))

rospy.Subscriber("/camera/depth/image_raw", Image, callback)

while True:
    rospy.spin()
Eksiksiz kod
import time

import numpy as np
import ros_numpy
import rospy
from sensor_msgs.msg import Image
from std_msgs.msg import String

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)

segmentation_model = YOLO("yolo26m-seg.pt")

classes_pub = rospy.Publisher("/ultralytics/detection/distance", String, queue_size=5)

def callback(data):
    """Callback function to process depth image and RGB image."""
    image = rospy.wait_for_message("/camera/color/image_raw", Image)
    image = ros_numpy.numpify(image)
    depth = ros_numpy.numpify(data)
    result = segmentation_model(image)

    all_objects = []
    for index, cls in enumerate(result[0].boxes.cls):
        class_index = int(cls.cpu().numpy())
        name = result[0].names[class_index]
        mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
        obj = depth[mask == 1]
        obj = obj[~np.isnan(obj)]
        avg_distance = np.mean(obj) if len(obj) else np.inf
        all_objects.append(f"{name}: {avg_distance:.2f}m")

    classes_pub.publish(String(data=str(all_objects)))

rospy.Subscriber("/camera/depth/image_raw", Image, callback)

while True:
    rospy.spin()

Ultralytics'i ROS sensor_msgs/PointCloud2 ile Kullanma#

Detection and Segmentation in ROS Gazebo

sensor_msgs/PointCloud2 mesaj türü, ROS'ta 3B nokta bulutu verilerini temsil etmek için kullanılan bir veri yapısıdır. Bu mesaj türü, 3B haritalama, nesne tanıma ve konum belirleme gibi görevleri mümkün kılarak robotik uygulamalarında önemli bir rol oynar.

Nokta bulutu, üç boyutlu bir koordinat sistemi içinde tanımlanan veri noktaları koleksiyonudur. Bu veri noktaları, 3B tarama teknolojileriyle yakalanan bir nesnenin veya sahnenin dış yüzeyini temsil eder. Buluttaki her nokta, uzaydaki konumuna karşılık gelen X, Y ve Z koordinatlarına ve renk ile yoğunluk gibi ek bilgilere sahip olabilir.

Referans çerçevesi

sensor_msgs/PointCloud2 ile çalışırken nokta bulutu verilerinin alındığı sensörün referans çerçevesini dikkate almak çok önemlidir. Nokta bulutu başlangıçta sensörün referans çerçevesinde yakalanır. Bu referans çerçevesini /tf_static konusunu dinleyerek belirleyebilirsin. Ancak belirli uygulama gereksinimlerine bağlı olarak nokta bulutunu başka bir referans çerçevesine dönüştürmen gerekebilir. Bu dönüşüm, koordinat çerçevelerini yönetmek ve verileri bunlar arasında dönüştürmek için araçlar sağlayan tf2_ros paketiyle gerçekleştirilebilir.

Nokta Bulutlarını Edinme

Nokta bulutları çeşitli sensörler kullanılarak elde edilebilir:

  1. LIDAR (Işık Algılama ve Menzil Ölçme): Nesnelere olan uzaklıkları ölçmek ve yüksek-hassasiyetli 3B haritalar oluşturmak için lazer darbeleri kullanır.
  2. Derinlik Kameraları: Her piksel için derinlik bilgisi yakalayarak sahnenin 3B olarak yeniden oluşturulmasını sağlar.
  3. Stereo Kameralar: Nirengi yoluyla derinlik bilgisi elde etmek için iki veya daha fazla kamera kullanır.
  4. Yapılandırılmış Işık Tarayıcıları: Bilinen bir deseni yüzeye yansıtır ve derinliği hesaplamak için deformasyonu ölçer.

YOLO'yu Nokta Bulutlarıyla Kullanma#

YOLO'yu sensor_msgs/PointCloud2 türündeki mesajlarla entegre etmek için derinlik haritalarında kullanılana benzer bir yöntem uygulayabiliriz. Nokta bulutunda gömülü renk bilgisinden yararlanarak bir 2B görüntü çıkarabilir, bu görüntü üzerinde YOLO ile segmentasyon gerçekleştirebilir ve ardından elde edilen maskeyi üç boyutlu noktalara uygulayarak ilgilenilen 3B nesneyi ayırabiliriz.

Nokta bulutlarını işlemek için kullanıcı dostu bir Python kütüphanesi olan Open3D'yi (pip install open3d) kullanmanı öneririz. Open3D, nokta bulutu veri yapılarını yönetmek, bunları görselleştirmek ve karmaşık işlemleri sorunsuz şekilde gerçekleştirmek için güçlü araçlar sunar. Bu kütüphane, süreci büyük ölçüde basitleştirebilir ve YOLO tabanlı segmentasyonla birlikte nokta bulutlarını işleme ve analiz etme yeteneğimizi geliştirebilir.

Nokta Bulutlarının Adım Adım Kullanımı#

Gerekli kütüphaneleri içe aktar ve segmentasyon için YOLO modelini örneklendir.

import time

import rospy

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo26m-seg.pt")

sensor_msgs/PointCloud2 mesajını iki NumPy dizisine dönüştüren pointcloud2_to_array işlevini oluştur. sensor_msgs/PointCloud2 mesajları, alınan görüntünün width ve height değerlerine dayalı n noktaları içerir. Örneğin 480 x 640 görüntüsünde 307,200 nokta bulunur. Her nokta üç uzamsal koordinat (xyz) ve RGB biçiminde karşılık gelen rengi içerir. Bunlar iki ayrı bilgi kanalı olarak değerlendirilebilir.

İşlev, xyz koordinatlarını ve RGB değerlerini özgün kamera çözünürlüğü (width x height) biçiminde döndürür. Çoğu sensörün, klip mesafesi olarak bilinen ve ötesinde değerlerin inf (np.inf) olarak gösterildiği bir maksimum mesafesi vardır. İşlemeden önce bu boş değerleri filtrelemek ve bunlara 0 değerini atamak önemlidir.

import numpy as np
import ros_numpy

def pointcloud2_to_array(pointcloud2: PointCloud2) -> tuple:
    """Convert a ROS PointCloud2 message to a numpy array.

    Args:
        pointcloud2 (PointCloud2): the PointCloud2 message

    Returns:
        (tuple): tuple containing (xyz, rgb)
    """
    pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
    split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
    rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
    xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
    xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
    nan_rows = np.isnan(xyz).all(axis=2)
    xyz[nan_rows] = [0, 0, 0]
    rgb[nan_rows] = [0, 0, 0]
    return xyz, rgb

Nokta bulutu mesajını almak için /camera/depth/points konusuna abone ol ve sensor_msgs/PointCloud2 mesajını (pointcloud2_to_array işlevini kullanarak) XYZ koordinatlarını ve RGB değerlerini içeren NumPy dizilerine dönüştür. Segmentlere ayrılmış nesneleri çıkarmak için RGB görüntüsünü YOLO modeliyle işle. Algılanan her nesne için segmentasyon maskesini çıkar ve nesneyi 3B uzayda ayırmak üzere hem RGB görüntüsüne hem de XYZ koordinatlarına uygula.

Maske ikili değerlerden oluştuğu için işlenmesi basittir; 1 nesnenin varlığını, 0 ise yokluğunu belirtir. Maskeyi uygulamak için özgün kanalları maskeyle çarpman yeterlidir. Bu işlem, ilgilenilen nesneyi görüntü içinde etkili bir şekilde ayırır. Son olarak bir Open3D nokta bulutu nesnesi oluştur ve segmentlere ayrılan nesneyi ilişkili renkleriyle 3B uzayda görselleştir.

import sys

import open3d as o3d

ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)

if not len(result[0].boxes.cls):
    print("No objects detected")
    sys.exit()

classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
    mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
    mask_expanded = np.stack([mask, mask, mask], axis=2)

    obj_rgb = rgb * mask_expanded
    obj_xyz = xyz * mask_expanded

    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((ros_cloud.height * ros_cloud.width, 3)))
    pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((ros_cloud.height * ros_cloud.width, 3)) / 255)
    o3d.visualization.draw_geometries([pcd])
Eksiksiz kod
import sys
import time

import numpy as np
import open3d as o3d
import ros_numpy
import rospy
from sensor_msgs.msg import PointCloud2

from ultralytics import YOLO

rospy.init_node("ultralytics")
time.sleep(1)
segmentation_model = YOLO("yolo26m-seg.pt")

def pointcloud2_to_array(pointcloud2: PointCloud2) -> tuple:
    """Convert a ROS PointCloud2 message to a numpy array.

    Args:
        pointcloud2 (PointCloud2): the PointCloud2 message

    Returns:
        (tuple): tuple containing (xyz, rgb)
    """
    pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
    split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
    rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
    xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
    xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
    nan_rows = np.isnan(xyz).all(axis=2)
    xyz[nan_rows] = [0, 0, 0]
    rgb[nan_rows] = [0, 0, 0]
    return xyz, rgb

ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
xyz, rgb = pointcloud2_to_array(ros_cloud)
result = segmentation_model(rgb)

if not len(result[0].boxes.cls):
    print("No objects detected")
    sys.exit()

classes = result[0].boxes.cls.cpu().numpy().astype(int)
for index, class_id in enumerate(classes):
    mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
    mask_expanded = np.stack([mask, mask, mask], axis=2)

    obj_rgb = rgb * mask_expanded
    obj_xyz = xyz * mask_expanded

    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((ros_cloud.height * ros_cloud.width, 3)))
    pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((ros_cloud.height * ros_cloud.width, 3)) / 255)
    o3d.visualization.draw_geometries([pcd])

Point Cloud Segmentation with Ultralytics

Sonuç#

Ultralytics YOLO ROS ile entegre edildiğinde robotun RGB görüntüleri, derinlik görüntüleri ve nokta bulutları üzerinde nesne algılama ve segmentasyon gerçekleştirebilir; böylece ham sensör akışlarını eyleme dönüştürülebilir algılama verilerine çevirir. Buradan daha fazla çıkarım seçeneği için Tahmin modu bölümünü inceleyebilir veya robotik uygulamanı prototipten üretime taşımak için bir bilgisayarlı görü projesinin adımlarını izleyebilirsin.

SSS#

  • Robot İşletim Sistemi (ROS), geliştiricilerin sağlam robot uygulamaları oluşturmasına yardımcı olmak için robotikte yaygın olarak kullanılan açık kaynaklı bir çatıdır. Robotik sistemler oluşturmak ve bunlarla arayüz oluşturmak için bir kütüphane ve araç koleksiyonu sağlar ve karmaşık uygulamaların daha kolay geliştirilmesini mümkün kılar. ROS, konular veya hizmetler üzerinden mesajlarla düğümler arasındaki iletişimi destekler.

  • Ultralytics YOLO'yu ROS ile entegre etmek, bir ROS ortamı kurmayı ve sensör verilerini işlemek için YOLO'yu kullanmayı içerir. ros_numpy ve Ultralytics YOLO gibi gerekli bağımlılıkları yükleyerek başla:

    pip install ros_numpy ultralytics

    Ardından bir ROS düğümü oluştur ve gelen verileri nesne algılama için işlemek üzere bir görüntü konusuna abone ol. İşte minimal bir örnek:

    import ros_numpy
    import rospy
    from sensor_msgs.msg import Image
    
    from ultralytics import YOLO
    
    detection_model = YOLO("yolo26m.pt")
    rospy.init_node("ultralytics")
    det_image_pub = rospy.Publisher("/ultralytics/detection/image", Image, queue_size=5)
    
    def callback(data):
        array = ros_numpy.numpify(data)
        det_result = detection_model(array)
        det_annotated = det_result[0].plot(show=False)
        det_image_pub.publish(ros_numpy.msgify(Image, det_annotated, encoding="rgb8"))
    
    rospy.Subscriber("/camera/color/image_raw", Image, callback)
    rospy.spin()
  • ROS konuları, yayınla-abone ol modelini kullanarak bir ROS ağındaki düğümler arasındaki iletişimi sağlar. Konu, düğümlerin mesajları eşzamansız olarak gönderip almak için kullandığı adlandırılmış bir kanaldır. Ultralytics YOLO bağlamında bir düğümü görüntü konusuna abone olacak şekilde ayarlayabilir, görüntüleri algılama veya segmentasyon gibi görevler için YOLO kullanarak işleyebilir ve sonuçları yeni konulara yayınlayabilirsin.

    Örneğin bir kamera konusuna abone ol ve gelen görüntüyü algılama için işle:

    rospy.Subscriber("/camera/color/image_raw", Image, callback)
  • ROS'ta sensor_msgs/Image ile temsil edilen derinlik görüntüleri, nesnelerin kameraya olan uzaklığını sağlar; bu bilgi engellerden kaçınma, 3B haritalama ve konum belirleme gibi görevler için kritik öneme sahiptir. RGB görüntüleriyle birlikte derinlik bilgisini kullanarak robotlar 3B çevrelerini daha iyi anlayabilir.

    YOLO ile RGB görüntülerinden segmentasyon maskeleri çıkarabilir ve hassas 3B nesne bilgileri elde etmek için bu maskeleri derinlik görüntülerine uygulayabilirsin; böylece robotun çevresinde gezinme ve çevresiyle etkileşim kurma yeteneği gelişir.

  • YOLO ile ROS'ta 3B nokta bulutlarını görselleştirmek için:

    1. sensor_msgs/PointCloud2 mesajlarını NumPy dizilerine dönüştür.
    2. RGB görüntülerini bölütlemek için YOLO'yu kullan.
    3. Bölütleme maskesini nokta bulutuna uygula.

    Görselleştirme için Open3D kullanan bir örnek:

    import sys
    
    import numpy as np
    import open3d as o3d
    import ros_numpy
    import rospy
    from sensor_msgs.msg import PointCloud2
    
    from ultralytics import YOLO
    
    rospy.init_node("ultralytics")
    segmentation_model = YOLO("yolo26m-seg.pt")
    
    def pointcloud2_to_array(pointcloud2):
        pc_array = ros_numpy.point_cloud2.pointcloud2_to_array(pointcloud2)
        split = ros_numpy.point_cloud2.split_rgb_field(pc_array)
        rgb = np.stack([split["b"], split["g"], split["r"]], axis=2)
        xyz = ros_numpy.point_cloud2.get_xyz_points(pc_array, remove_nans=False)
        xyz = np.array(xyz).reshape((pointcloud2.height, pointcloud2.width, 3))
        return xyz, rgb
    
    ros_cloud = rospy.wait_for_message("/camera/depth/points", PointCloud2)
    xyz, rgb = pointcloud2_to_array(ros_cloud)
    result = segmentation_model(rgb)
    
    if not len(result[0].boxes.cls):
        print("No objects detected")
        sys.exit()
    
    classes = result[0].boxes.cls.cpu().numpy().astype(int)
    for index, class_id in enumerate(classes):
        mask = result[0].masks.data.cpu().numpy()[index, :, :].astype(int)
        mask_expanded = np.stack([mask, mask, mask], axis=2)
    
        obj_rgb = rgb * mask_expanded
        obj_xyz = xyz * mask_expanded
    
        pcd = o3d.geometry.PointCloud()
        pcd.points = o3d.utility.Vector3dVector(obj_xyz.reshape((-1, 3)))
        pcd.colors = o3d.utility.Vector3dVector(obj_rgb.reshape((-1, 3)) / 255)
        o3d.visualization.draw_geometries([pcd])

    Bu yaklaşım, bölütlenmiş nesnelerin 3B görselleştirmesini sunar ve robotik uygulamalarda navigasyon ve manipülasyon gibi görevler için kullanışlıdır.

Yorumlar