YOLO Vision 2026:

ROS (Robot Operating System) başlangıç rehberi#

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

YOLO'yu ROS ile kurma konusuna atla, ardından RGB görüntüler, derinlik görüntüler veya nokta bulutları ile çalış.

ROS Introduction (captioned) from Open Robotics on Vimeo.

ROS nedir?#

Robot İşletim Sistemi (ROS), robotik araştırmalarında ve endüstrisinde yaygın olarak kullanılan açık kaynaklı bir altyapıdır. ROS, geliştiricilerin robot uygulamaları oluşturmasına yardımcı olmak için bir kütüphane ve araç koleksiyonu sağlar. Çeşitli robotik platformlarla çalışacak şekilde tasarlanan ROS, robotik uzmanları için esnek ve güçlü bir araçtır.

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 kurmasını sağlayan modüler bir mimariye sahiptir. Her düğüm tipik olarak belirli bir işlevi yerine getirir ve düğümler konular veya servisler üzerinden mesajlaşarak birbirleriyle iletişim kurar.

  2. İletişim Ara Katmanı (Middleware): ROS, işlemler 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 bir yayınla-abone ol (publish-subscribe) modeli ve hizmet çağrıları için bir istek-yanıt modeli aracılığıyla elde edilir.

  3. Donanım Soyutlama: ROS, donanım üzerinde bir soyutlama katmanı sağlayarak geliştiricilerin cihazdan bağımsız kod yazmalarını mümkün kılar. Bu, aynı kodun farklı donanım kurulumlarıyla kullanılmasına olanak tanıyarak entegrasyonu ve denemeleri kolaylaştırı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 seti ile 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. Kapsamlı Ekosistem: ROS ekosistemi geniştir ve sürekli büyümektedir; navigasyon, manipülasyon, algılama ve daha fazlası dahil olmak üzere 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 Evrimi

2007'deki gelişiminden bu yana ROS, ROS 1 ve ROS 2 olarak bölünerek birden fazla sürüm aracılığıyla evrim geçirmiştir. Aşağıdaki mevcut örnekler ROS1 Noetic kullanmaktadır; ROS2 Kullanımı bölümündeki kompakt adaptörler ise güncel ROS2 sürümleri için karşılık gelen rclpy arayüzlerini gösterir.

ROS 1 ve ROS 2 Karşılaştırması#

ROS 1 robotik geliştirme için sağlam bir temel sağlasa da, ROS 2 şunları sunarak eksikliklerini gidermektedir:

  • Gerçek Zamanlı Performans: Gerçek zamanlı sistemler ve deterministik davranış için iyileştirilmiş destek.
  • Güvenlik: Çeşitli ortamlarda güvenli ve güvenilir çalışma için geliştirilmiş güvenlik özellikleri.
  • Ölçeklenebilirlik: Çoklu robot sistemleri ve büyük ölçekli dağıtımlar için daha iyi destek.
  • Platformlar Arası Destek: Windows ve macOS dahil olmak üzere Linux dışındaki çeşitli işletim sistemleriyle genişletilmiş uyumluluk.
  • Esnek İletişim: İşlemler arası daha esnek ve verimli 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 kolaylaştırılı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 (publish) veya bir konudan gelen mesajlara abone olabilir (subscribe); bu da birbirleriyle iletişim kurmalarını sağlar. Bu yayınla-abone ol (publish-subscribe) modeli, eşzamansız (asynchronous) iletişime ve düğümler arasında bağımsızlığın azaltılmasına (decoupling) olanak tanır. Robotik bir sistemdeki her sensör veya aktüatör tipik olarak bir konuya veri yayınlar ve bu veri daha sonra işleme veya kontrol için diğer düğümler tarafından tüketilebilir. Bu kılavuzun amaçları doğrultusunda 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şlemleri ROS2'de de geçerlidir; yalnızca düğüm yaşam döngüsü ve mesaj dönüşümü farklılık gösterir.

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 kurman gerekecektir:

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

    pip install ros_numpy
  • Ultralytics paketi:

    pip install ultralytics

ROS2 Kullanımı#

ROS2, rospy yerine rclpy kullanır ve ros_numpy görüntü dönüşümünü cv_bridge ile değiştirir. Aşağıdaki düğüm, aşağıdaki RGB tespit akışının eksiksiz ROS2 karşılığıdır; modelleri bir kez örnekle ve geri çağrılar (callbacks) 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 edinimi ve 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; organize bulutu bir kez dönüştür, ardından aşağıdaki NumPy bölütleme ve 3D haritalama işlemlerini 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 kullan#

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çerir; bu da onu kameralar veya diğer sensörler tarafından yakalanan görüntüleri iletmek için uygun hale getirir. Görüntü mesajları robotik uygulamalarda görsel algı, nesne tespiti ve navigasyon gibi görevler için yaygın olarak kullanılır.

Detection and Segmentation in ROS Gazebo

Görüntü 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 tespit edilen nesneleri tespit ve bölütleme için yeni konulara yayınlıyoruz.

İlk olarak, gerekli kütüphaneleri içe aktar ve iki model örnekle: biri bölütleme için, diğeri tespit için. ROS ana düğümü (ROS master) ile iletişimi etkinleştirmek için bir ROS düğümü başlat (ultralytics adıyla). Kararlı bir bağlantı sağlamak için kısa bir duraklama ekliyoruz, böylece düğüme devam etmeden önce bağlantıyı kurması için yeterli zaman tanımış oluyoruz.

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 tespit için, diğeri bölütleme için. Bu konular, açıklama eklenmiş (annotated) görüntüleri yayınlamak için kullanılacak ve bunların daha fazla işleme için erişilebilir olmasını sağlayacaktır. Düğümler arasındaki iletişim sensor_msgs/Image mesajları kullanılarak kolaylaştırılı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ğrı (callback) fonksiyonu çağıran bir abone (subscriber) oluştur. Bu geri çağrı fonksiyonu sensor_msgs/Image türündeki mesajları alır, bunları ros_numpy kullanarak bir NumPy dizisine dönüştürür, görüntüleri daha önce örneklenmiş YOLO modelleriyle işler, görüntülere açıklama ekler ve ardından bunları ilgili konulara geri yayınlar: tespit için /ultralytics/detection/image ve bölütleme 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()
Kodun tamamı
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

Sistemin dağıtık yapısı nedeniyle ROS (Robot Operating System) düğümlerinde hata ayıklamak zor olabilir. Bu süreçte yardımcı olabilecek birkaç araç şunlardır:

  1. rostopic echo <TOPIC-NAME> : Bu komut, belirli bir konuda yayınlanan mesajları görüntülemeni sağlayarak veri akışını denetmene yardımcı olur.
  2. rostopic list: ROS sistemindeki tüm mevcut konuları listelemek için bu komutu kullan; bu sayede aktif veri akışlarına genel bir bakış elde edersin.
  3. rqt_graph: Bu görselleştirme aracı, düğümler arasındaki iletişim grafiğini göstererek düğümlerin birbirine nasıl bağlandığı ve nasıl etkileşime girdiğine dair içgörüler sağlar.
  4. 3D gösterimler gibi daha karmaşık görselleştirmeler için RViz kullanabilirsin. RViz (ROS Visualization), ROS için güçlü bir 3D görselleştirme aracıdır. Robotunun ve çevresinin durumunu gerçek zamanlı olarak görselleştirmeni sağlar. RViz ile sensör verilerini (örn. sensor_msgs/Image), robot modeli durumlarını ve diğer çeşitli bilgi türlerini görüntüleyebilir, böylece robotik sisteminin davranışını hata ayıklamayı ve anlamayı daha kolay hale getirebilirsin.

Tespit Edilen Sınıfları std_msgs/String ile Yayınla#

Standart ROS mesajları ayrıca std_msgs/String mesajlarını içerir. Birçok uygulamada, tüm açıklama eklenmiş görüntüyü yeniden yayınlamak gerekli değildir; bunun yerine, yalnızca robotun görüş alanında bulunan sınıflar gereklidir. Aşağıdaki örnek, algılanan sınıfları /ultralytics/detection/classes kanalında yeniden yayınlamak için std_msgs/String mesajlarının nasıl kullanılacağını göstermektedir. Bu mesajlar daha hafiftir ve temel bilgiler sağlar, bu da onları çeşitli uygulamalar için değerli kılar.

Örnek Kullanım Senaryosu#

Kamerayla ve nesne tespit modeliyle donatılmış bir depo robotunu düşün. Ağ üzerinden büyük açıklama eklenmiş görüntüler göndermek yerine robot, tespit edilen sınıfların bir listesini std_msgs/String mesajları olarak yayınlayabilir. Örneğin, robot "kutu" (box), "palet" (pallet) ve "forklift" gibi nesneleri tespit ettiğinde, bu sınıfları /ultralytics/detection/classes konusuna yayınlar. Bu bilgiler daha sonra merkezi bir izleme sistemi tarafından envanteri gerçek zamanlı olarak takip etmek, engellerden kaçınmak için robotun rota planlamasını optimize etmek veya tespit edilen bir kutuyu almak gibi belirli eylemleri tetiklemek için kullanılabilir. Bu yaklaşım, iletişim için gereken bant genişliğini azaltır ve kritik verileri iletmeye odaklanır.

String Adım Adım Kullanımı#

Bu örnek, Ultralytics YOLO paketinin ROS ile nasıl kullanılacağını göstermektedir. Bu örnekte, bir kamera kanalına abone oluyor, YOLO kullanarak gelen görüntüyü işliyor ve algılanan nesneleri std_msgs/String mesajlarını kullanarak yeni /ultralytics/detection/classes kanalında yayınlıyoruz. ros_numpy paketi, ROS Image mesajını YOLO ile işlemek üzere bir 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üleri ile Kullanma#

RGB görüntülere ek olarak ROS, nesnelerin kameraya olan mesafesi hakkında bilgi sağlayan derinlik görüntülerini de destekler. Derinlik görüntüleri; engellerden kaçınma, 3D haritalama ve konum belirleme (localization) gibi robotik uygulamalar için çok önemlidir.

Derinlik görüntüsü, her pikselin kameradan bir nesneye olan mesafeyi temsil ettiği bir görüntüdür. Renk yakalayan RGB görüntülerin aksine, derinlik görüntüleri uzamsal bilgiyi yakalar ve robotların çevrelerinin 3D yapısını algılamasını sağlar.

Derinlik Görüntülerini Elde Etme

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

  1. Stereo Kameralar: Görüntü farkına (disparity) dayanarak derinliği hesaplamak için iki kamera kullanır.
  2. Uçuş Süresi (ToF) Kameraları: Işığın bir nesneden dönmesinin aldığı süreyi ölçer.
  3. Yapılandırılmış Işık Sensörleri: Bir desen yansıtır ve yüzeyler üzerindeki deformasyonunu ölçer.

YOLO'yu Derinlik Görüntüleri ile 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üleri için kodlama alanı genellikle piksel başına 16 bitlik işaretsiz bir tamsayıyı belirten "16UC1" gibi bir format kullanır; burada her değer nesneye olan mesafeyi temsil eder. Derinlik görüntüleri, ortama daha kapsamlı bir bakış sağlamak için genellikle RGB görüntülerle birlikte kullanılır.

YOLO kullanarak, hem RGB hem de derinlik görüntülerinden bilgi çıkarmak ve birleştirmek mümkündür. Örneğin, YOLO bir RGB görüntüsü içindeki nesneleri tespit edebilir ve bu tespit, derinlik görüntüsündeki karşılık gelen bölgeleri belirlemek için kullanılabilir. Bu, tespit edilen nesneler için hassas derinlik bilgilerinin çıkarılmasına olanak tanıyarak robotun çevresini üç boyutlu olarak anlama yeteneğini geliştirir.

RGB-D Kameralar

Derinlik görüntüleriyle çalışırken, RGB ve derinlik görüntülerinin doğru bir şekilde hizalandığından emin olmak esastır. Intel RealSense serisi gibi RGB-D kameralar, senkronize RGB ve derinlik görüntüleri sağlayarak her iki kaynaktan gelen bilgileri birleştirmeyi kolaylaştırır. Ayrı RGB ve derinlik kameraları kullanıyorsan, doğru hizalamayı garanti etmek için bunları kalibre etmen çok önemlidir.

Derinlik Adım Adım Kullanımı#

Bu örnekte, bir görüntüyü segmentlere ayırmak için YOLO kullanıyor ve derinlik görüntüsündeki nesneyi segmentlere ayırmak için çıkarılan maskeyi uyguluyoruz. Bu, ilgi duyulan nesnenin her bir pikselinin kameranın odak merkezinden olan mesafesini belirlememizi sağlar. Bu mesafe bilgilerini elde ederek, 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 ve bir ROS konusu başlatarak 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ğrı (callback) fonksiyonu tanımla. Bu fonksiyon, derinlik görüntüsü ve RGB görüntüsü mesajlarını bekler, bunları NumPy dizilerine dönüştürür ve bölütleme modelini RGB görüntüye uygular. Ardından tespit edilen her nesne için bölütleme maskesini çıkarır ve derinlik görüntüsünü kullanarak nesnenin kameradan olan ortalama mesafesini hesaplar. Çoğu sensörün, değerlerin inf (np.inf) olarak temsil edildiği klip mesafesi (clip distance) adı verilen maksimum bir mesafesi vardır. İşlemden önce, bu boş (null) değerleri filtrelemek ve bunlara 0 değeri atamak önemlidir. Son olarak, tespit edilen nesneleri ortalama mesafeleriyle 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()
Kodun tamamı
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 kullan#

Detection and Segmentation in ROS Gazebo

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

Nokta bulutu, üç boyutlu bir koordinat sistemi içinde tanımlanan veri noktalarından oluşan bir koleksiyondur. Bu veri noktaları, 3D tarama teknolojileri aracılığıyla yakalanan bir nesnenin veya sahnenin dış yüzeyini temsil eder. Buluttaki her noktanın uzaydaki konumuna karşılık gelen X, Y ve Z koordinatları vardır ve ayrıca renk ve yoğunluk gibi ek bilgiler de içerebilir.

Referans çerçevesi

sensor_msgs/PointCloud2 ile çalışırken, nokta bulutu verilerinin elde edildiği sensörün referans çerçevesini dikkate almak esastır. Nokta bulutu başlangıçta sensörün referans çerçevesinde yakalanır. /tf_static konusunu dinleyerek bu referans çerçevesini belirleyebilirsin. Bununla birlikte, özel 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 veriler arasında dönüşüm yapmak için araçlar sağlayan tf2_ros paketi kullanılarak gerçekleştirilebilir.

Nokta Bulutlarını Elde Etme

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

  1. LIDAR (Light Detection and Ranging - Işık Tespiti ve Uzaklık Ölçümü): Nesnelere olan mesafeleri ölçmek ve yüksek hassasiyetli 3D haritalar oluşturmak için lazer darbeleri kullanır.
  2. Derinlik Kameraları: Sahnenin 3D rekonstrüksiyonuna olanak tanıyan her piksel için derinlik bilgisini yakalar.
  3. Stereo Kameralar: Üçgenleme yoluyla derinlik bilgisi elde etmek için iki veya daha fazla kamera kullanır.
  4. Yapılandırılmış Işık Tarayıcıları: Bir yüzey üzerine bilinen bir desen yansıtır ve derinliği hesaplamak için deformasyonu ölçer.

YOLO'yu Nokta Bulutları ile Kullanma#

YOLO'yu sensor_msgs/PointCloud2 türündeki mesajlarla entegre etmek için, derinlik haritaları için kullanılan yönteme benzer bir yöntem izleyebiliriz. Nokta bulutuna gömülü renk bilgilerinden yararlanarak bir 2D görüntü çıkarabilir, YOLO kullanarak bu görüntü üzerinde bölütleme gerçekleştirebilir ve ardından ilgilenilen 3D nesneyi izole etmek için ortaya çıkan maskeyi üç boyutlu noktalara uygulayabiliriz.

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

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

Gerekli kütüphaneleri içe aktar ve segmentasyon için YOLO modelini oluştur.

import time

import rospy

from ultralytics import YOLO

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

Bir sensor_msgs/PointCloud2 mesajını iki NumPy dizisine dönüştüren bir pointcloud2_to_array fonksiyonu oluşturun. sensor_msgs/PointCloud2 mesajları, edinilen görüntünün width ve height değerlerine dayanarak n noktalarını içerir. Örneğin, bir 480 x 640 görüntüsü 307,200 noktalarına sahip olacaktır. Her nokta üç uzamsal koordinat (xyz) ve RGB formatındaki ilgili rengi içerir. Bunlar iki ayrı bilgi kanalı olarak değerlendirilebilir.

Fonksiyon, xyz koordinatlarını ve RGB değerlerini orijinal kamera çözünürlüğü (width x height) formatında döndürür. Çoğu sensörün, değerlerin inf (np.inf) olarak temsil edildiği klip mesafesi (clip distance) adı verilen maksimum bir mesafesi vardır. İşlemden önce, bu boş değerleri filtrelemek ve bunlara 0 değeri 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

Ardından, nokta bulutu mesajını almak için /camera/depth/points konusuna abone ol ve sensor_msgs/PointCloud2 mesajını XYZ koordinatlarını ve RGB değerlerini içeren NumPy dizilerine dönüştür (pointcloud2_to_array fonksiyonunu kullanarak). Bölütlenmiş nesneleri çıkarmak için YOLO modelini kullanarak RGB görüntüyü işle. Tespit edilen her nesne için bölütleme maskesini çıkar ve nesneyi 3D uzayda izole etmek için bu maskeyi hem RGB görüntüye hem de XYZ koordinatlarına uygula.

Maskeyi işlemek oldukça basittir; çünkü maske, nesnenin varlığını belirten 1 ve yokluğunu belirten 0 değerlerinden oluşan ikili (binary) değerlerden oluşur. Maskeyi uygulamak için orijinal kanalları maskeyle çarpman yeterlidir. Bu işlem, görüntü içindeki ilgilenilen nesneyi etkili bir şekilde izole eder. Son olarak, bir Open3D nokta bulutu nesnesi oluştur ve bölütlenmiş nesneyi ilgili renklerle birlikte 3D 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])
Kodun tamamı
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'nun ROS ile entegre edilmesiyle robotun; ham sensör akışlarını eyleme dönüştürülebilir bir algıya dönüştürerek RGB görüntüler, derinlik görüntüler ve nokta bulutları üzerinde nesne tespiti ve bölütleme çalıştırabilir. Buradan, daha fazla çıkarım seçeneği için Tahmin modunu (Predict mode) keşfet veya robotik uygulamanı prototipten üretime taşımak için bir bilgisayarlı görü projesinin adımlarını takip et.

SSS#

Robot İşletim Sistemi (ROS) nedir?#

Robot İşletim Sistemi (ROS), geliştiricilerin güçlü robot uygulamaları oluşturmasına yardımcı olmak için robotikte yaygın olarak kullanılan açık kaynaklı bir altyapıdır. Karmaşık uygulamaların geliştirilmesini kolaylaştırarak, robotik sistemler kurmak ve bunlarla arabirim oluşturmak için bir kütüphane ve araç koleksiyonu sağlar. ROS, konular veya servisler üzerinden mesajlar kullanarak düğümler arası iletişimi destekler.

Ultralytics YOLO'yu gerçek zamanlı nesne tespiti için ROS ile nasıl entegre ederim?#

Ultralytics YOLO'yu ROS ile entegre etmek, bir ROS ortamı kurmayı ve sensör verilerini işlemek için YOLO 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 nesne tespiti için gelen verileri işlemek üzere bir görüntü konusuna abone ol. İşte minimum 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ı nelerdir ve Ultralytics YOLO'da nasıl kullanılırlar?#

ROS konuları, bir yayınla-abone ol (publish-subscribe) modeli kullanarak bir ROS ağındaki düğümler arasındaki iletişimi kolaylaştırır. Konu, düğümlerin eşzamansız olarak mesaj göndermek ve almak için kullandığı adlandırılmış bir kanaldır. Ultralytics YOLO bağlamında, bir düğümün bir görüntü konusuna abone olmasını sağlayabilir, tespit veya bölütleme gibi görevler için YOLO kullanarak görüntüleri işleyebilir ve sonuçları yeni konulara yayınlayabilirsin.

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

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

Neden ROS'ta Ultralytics YOLO ile derinlik görüntüleri kullanmalıyım?#

sensor_msgs/Image ile temsil edilen ROS'taki derinlik görüntüleri; engellerden kaçınma, 3D haritalama ve konum belirleme gibi görevler için çok önemli olan, nesnelerin kameraya olan mesafesini sağlar. Robotlar, RGB görüntülerin yanı sıra derinlik bilgilerini kullanarak 3D çevrelerini daha iyi anlayabilir.

YOLO ile RGB görüntülerden bölütleme maskeleri çıkarabilir ve robotun çevresiyle gezinme ve etkileşim kurma yeteneğini geliştirerek hassas 3D nesne bilgileri elde etmek için bu maskeleri derinlik görüntülerine uygulayabilirsin.

ROS'ta YOLO ile 3D nokta bulutlarını nasıl görselleştirebilirim?#

ROS'ta YOLO ile 3D 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üleri segmentlere ayırmak için YOLO kullan.
  3. Segmentasyon maskesini nokta bulutuna uygula.

İşte 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, robotik uygulamalarında navigasyon ve manipülasyon gibi görevler için yararlı olan, bölütlenmiş nesnelerin bir 3D görselleştirmesini sağlar.

Yorumlar