Meet YOLO26: next-gen vision AI.

Link to this sectionدليل البدء السريع لـ ROS (نظام تشغيل الروبوت)#

يوضح هذا الدليل كيفية دمج Ultralytics YOLO مع روبوت يعمل بنظام ROS Noetic لتشغيل object detection وsegmentation في الوقت الفعلي على صور RGB وصور العمق والسحب النقطية.

انتقل إلى إعداد YOLO مع ROS، ثم اعمل باستخدام صور RGB أو صور العمق أو السحب النقطية.

ROS Introduction (captioned) from Open Robotics on Vimeo.

Link to this sectionما هو ROS؟#

يُعد Robot Operating System (ROS) إطار عمل مفتوح المصدر يُستخدم على نطاق واسع في أبحاث الروبوتات والصناعة. يوفر ROS مجموعة من المكتبات والأدوات لمساعدة المطورين في إنشاء تطبيقات الروبوتات. تم تصميم ROS للعمل مع مختلف المنصات الروبوتية، مما يجعله أداة مرنة وقوية لخبراء الروبوتات.

Link to this sectionالميزات الرئيسية لـ ROS#

  1. البنية النمطية (Modular Architecture): يتميز ROS ببنية نمطية، مما يسمح للمطورين ببناء أنظمة معقدة من خلال دمج مكونات أصغر قابلة لإعادة الاستخدام تُسمى nodes. يقوم كل عقدة (node) عادةً بوظيفة محددة، وتتواصل العقد مع بعضها البعض باستخدام رسائل عبر topics أو services.

  2. برمجيات التواصل الوسيطة (Communication Middleware): يوفر ROS بنية تحتية قوية للاتصالات تدعم التواصل بين العمليات والحوسبة الموزعة. يتم تحقيق ذلك من خلال نموذج النشر والاشتراك لتدفقات البيانات (topics) ونموذج الطلب والرد لاستدعاءات الخدمات (services).

  3. تجريد الأجهزة (Hardware Abstraction): يوفر ROS طبقة تجريد فوق الأجهزة، مما يتيح للمطورين كتابة كود مستقل عن نوع الجهاز. يسمح هذا باستخدام نفس الكود مع إعدادات أجهزة مختلفة، مما يسهل عملية التكامل والتجربة.

  4. الأدوات والمرافق: يأتي ROS مع مجموعة غنية من الأدوات والمرافق للتصور والتصحيح والمحاكاة. على سبيل المثال، يُستخدم RViz لتصور بيانات المستشعرات ومعلومات حالة الروبوت، بينما يوفر Gazebo بيئة محاكاة قوية لاختبار الخوارزميات وتصميمات الروبوتات.

  5. النظام البيئي الموسع: نظام ROS البيئي واسع وينمو باستمرار، مع توفر العديد من الحزم لتطبيقات روبوتية مختلفة، بما في ذلك الملاحة، والتحكم، والإدراك، والمزيد. يساهم المجتمع بفعالية في تطوير وصيانة هذه الحزم.

تطور إصدارات ROS

منذ تطويره في عام 2007، تطور ROS عبر إصدارات متعددة، حيث قدم كل منها ميزات وتحسينات جديدة لتلبية الاحتياجات المتزايدة لمجتمع الروبوتات. يمكن تصنيف تطوير ROS إلى سلسلتين رئيسيتين: ROS 1 و ROS 2. يركز هذا الدليل على إصدار الدعم طويل المدى (LTS) من ROS 1، المعروف باسم ROS Noetic Ninjemys، ويجب أن يعمل الكود أيضاً مع الإصدارات السابقة.

Link to this sectionROS 1 مقابل ROS 2#

بينما قدم ROS 1 أساساً متيناً لتطوير الروبوتات، يعالج ROS 2 أوجه قصوره من خلال توفير:

  • الأداء في الوقت الفعلي (Real-time Performance): دعم محسن للأنظمة في الوقت الفعلي والسلوك الحتمي.
  • الأمان: ميزات أمان معززة للتشغيل الآمن والموثوق في بيئات مختلفة.
  • القابلية للتوسع: دعم أفضل لأنظمة الروبوتات المتعددة والنشر على نطاق واسع.
  • دعم عبر المنصات: توافق موسع مع أنظمة تشغيل مختلفة بخلاف Linux، بما في ذلك Windows و macOS.
  • اتصالات مرنة: استخدام DDS لاتصالات أكثر مرونة وكفاءة بين العمليات.

Link to this sectionرسائل ومواضيع ROS#

في ROS، يتم تسهيل التواصل بين العقد من خلال messages و topics. الرسالة هي هيكل بيانات يحدد المعلومات المتبادلة بين العقد، بينما الموضوع (topic) هو قناة مسمات يتم من خلالها إرسال واستقبال الرسائل. يمكن للعقد نشر الرسائل إلى موضوع أو الاشتراك في رسائل من موضوع، مما يمكنها من التواصل مع بعضها البعض. يسمح نموذج النشر والاشتراك هذا باتصال غير متزامن وفك الارتباط بين العقد. عادةً ما يقوم كل مستشعر أو مشغل في نظام روبوتي بنشر البيانات إلى موضوع، والذي يمكن بعد ذلك استهلاكه من قبل عقد أخرى للمعالجة أو التحكم. لأغراض هذا الدليل، سنركز على رسائل Image و Depth و PointCloud ومواضيع الكاميرا.

Link to this sectionإعداد Ultralytics YOLO مع ROS#

تم اختبار هذا الدليل باستخدام بيئة ROS هذه، وهي نسخة مشتقة من مستودع ROSbot ROS. تتضمن هذه البيئة حزمة Ultralytics YOLO، وحاوية Docker للإعداد السهل، وحزم ROS شاملة، وعوالم Gazebo للاختبار السريع. وهي مصممة للعمل مع Husarion ROSbot 2 PRO. ستعمل أمثلة الكود المقدمة في أي بيئة ROS Noetic/Melodic، بما في ذلك المحاكاة والواقع الفعلي.

Husarion ROSbot 2 PRO autonomous robot platform

Link to this sectionتثبيت التبعيات#

بصرف النظر عن بيئة ROS، ستحتاج إلى تثبيت التبعيات التالية:

  • حزمة ROS NumPy: مطلوبة للتحويل السريع بين رسائل ROS Image ومصفوفات NumPy.

    pip install ros_numpy
  • حزمة Ultralytics:

    pip install ultralytics

Link to this sectionاستخدم Ultralytics مع sensor_msgs/Image في ROS#

The sensor_msgs/Image message type is commonly used in ROS for representing image data. It contains fields for encoding, height, width, and pixel data, making it suitable for transmitting images captured by cameras or other sensors. Image messages are widely used in robotic applications for tasks such as visual perception, object detection, and navigation.

Detection and Segmentation in ROS Gazebo

Link to this sectionالاستخدام خطوة بخطوة للصور#

يوضح مقتطف الكود التالي كيفية استخدام حزمة Ultralytics YOLO مع ROS. في هذا المثال، نشترك في موضوع كاميرا، ونعالج الصورة الواردة باستخدام YOLO، وننشر الكائنات المكتشفة إلى مواضيع جديدة لمهام detection و segmentation.

أولاً، قم باستيراد المكتبات الضرورية وقم بإنشاء نموذجين: واحد لـ segmentation وآخر لـ detection. قم بتهيئة عقدة ROS (بالاسم ultralytics) لتمكين التواصل مع ROS master. لضمان اتصال مستقر، نقوم بتضمين توقف مؤقت، مما يمنح العقدة وقتاً كافياً لإنشاء الاتصال قبل المتابعة.

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)

قم بتهيئة موضوعين في ROS: واحد لـ detection وآخر لـ segmentation. سيتم استخدام هذه المواضيع لنشر الصور المشروحة، مما يجعلها متاحة لمزيد من المعالجة. يتم تسهيل التواصل بين العقد باستخدام رسائل sensor_msgs/Image.

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)

أخيراً، قم بإنشاء مشترك يستمع إلى الرسائل على موضوع /camera/color/image_raw ويستدعي وظيفة رد نداء (callback function) لكل رسالة جديدة. تتلقى وظيفة رد النداء هذه رسائل من نوع sensor_msgs/Image، وتحولها إلى مصفوفة NumPy باستخدام ros_numpy، وتعالج الصور باستخدام نماذج YOLO التي تم إنشاؤها مسبقاً، وتشرح الصور، ثم تنشرها مرة أخرى إلى المواضيع المعنية: /ultralytics/detection/image للاكتشاف و /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()
الكود الكامل
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()
تصحيح الأخطاء (Debugging)

قد يكون تصحيح أخطاء عقد ROS (نظام تشغيل الروبوت) أمراً صعباً نظراً للطبيعة الموزعة للنظام. يمكن للعديد من الأدوات المساعدة في هذه العملية:

  1. rostopic echo <TOPIC-NAME> : يتيح لك هذا الأمر عرض الرسائل المنشورة على موضوع معين، مما يساعدك على فحص تدفق البيانات.
  2. rostopic list: استخدم هذا الأمر لسرد جميع المواضيع المتاحة في نظام ROS، مما يمنحك نظرة عامة على تدفقات البيانات النشطة.
  3. rqt_graph: تعرض أداة التصور هذه رسم الاتصالات بين العقد، مما يوفر رؤى حول كيفية ترابط العقد وكيفية تفاعلها.
  4. للتصورات الأكثر تعقيداً، مثل التنسيقات ثلاثية الأبعاد، يمكنك استخدام RViz. RViz (ROS Visualization) هي أداة تصور قوية ثلاثية الأبعاد لـ ROS. تسمح لك بتصور حالة الروبوت الخاص بك وبيئته في الوقت الفعلي. باستخدام RViz، يمكنك عرض بيانات المستشعرات (مثل sensor_msgs/Image)، وحالات نموذج الروبوت، وأنواع أخرى مختلفة من المعلومات، مما يجعل تصحيح الأخطاء وفهم سلوك نظامك الروبوتي أسهل.

Link to this sectionنشر الفئات المكتشفة باستخدام std_msgs/String#

Standard ROS messages also include std_msgs/String messages. In many applications, it is not necessary to republish the entire annotated image; instead, only the classes present in the robot's view are needed. The following example demonstrates how to use std_msgs/String messages to republish the detected classes on the /ultralytics/detection/classes topic. These messages are more lightweight and provide essential information, making them valuable for various applications.

Link to this sectionمثال على حالة الاستخدام#

تخيل روبوت مستودع مجهز بكاميرا ونموذج detection للأشياء. بدلاً من إرسال صور مشروحة كبيرة عبر الشبكة، يمكن للروبوت نشر قائمة بالفئات المكتشفة كرسائل std_msgs/String. على سبيل المثال، عندما يكتشف الروبوت كائنات مثل "box" و "pallet" و "forklift"، فإنه ينشر هذه الفئات إلى موضوع /ultralytics/detection/classes. يمكن بعد ذلك استخدام هذه المعلومات من قبل نظام مراقبة مركزي لتتبع المخزون في الوقت الفعلي، أو تحسين تخطيط مسار الروبوت لتجنب العوائق، أو تشغيل إجراءات محددة مثل التقاط صندوق تم اكتشافه. يقلل هذا النهج من النطاق الترددي المطلوب للاتصال ويركز على نقل البيانات المهمة.

Link to this sectionالاستخدام خطوة بخطوة للسلاسل النصية#

يوضح هذا المثال كيفية استخدام حزمة Ultralytics YOLO مع ROS. في هذا المثال، نشترك في موضوع كاميرا، ونعالج الصورة الواردة باستخدام YOLO، وننشر الكائنات المكتشفة إلى موضوع جديد /ultralytics/detection/classes باستخدام رسائل std_msgs/String. تُستخدم حزمة ros_numpy لتحويل رسالة ROS Image إلى مصفوفة NumPy للمعالجة باستخدام YOLO.

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()

Link to this sectionاستخدم Ultralytics مع صور العمق في ROS#

بالإضافة إلى صور RGB، يدعم ROS صور العمق، التي توفر معلومات حول مسافة الكائنات من الكاميرا. تعد صور العمق حاسمة لتطبيقات الروبوتات مثل تجنب العوائق، ورسم الخرائط ثلاثية الأبعاد، وتحديد الموقع.

صورة العمق هي صورة يمثل فيها كل بكسل المسافة من الكاميرا إلى كائن ما. على عكس صور RGB التي تلتقط اللون، تلتقط صور العمق معلومات مكانية، مما يمكن الروبوتات من إدراك البنية ثلاثية الأبعاد لبيئتها.

الحصول على صور العمق

يمكن الحصول على صور العمق باستخدام مستشعرات مختلفة:

  1. كاميرات ستيريو: تستخدم كاميرتين لحساب العمق بناءً على تباين الصور.
  2. كاميرات زمن الرحلة (ToF): تقيس الوقت الذي يستغرقه الضوء للعودة من كائن ما.
  3. مستشعرات الضوء المهيكل: تُسقط نمطاً وتقيس تشوهه على الأسطح.

Link to this sectionاستخدام YOLO مع صور العمق#

في ROS، يتم تمثيل صور العمق بواسطة نوع الرسالة sensor_msgs/Image، الذي يتضمن حقولاً للترميز، والارتفاع، والعرض، وبيانات البكسل. غالباً ما يستخدم حقل الترميز لصور العمق تنسيقاً مثل "16UC1"، مما يشير إلى عدد صحيح غير موقّع بـ 16 بت لكل بكسل، حيث تمثل كل قيمة المسافة إلى الكائن. تُستخدم صور العمق عادةً بالتزامن مع صور RGB لتوفير رؤية أكثر شمولاً للبيئة.

باستخدام YOLO، من الممكن استخراج المعلومات ودمجها من كل من صور RGB وصور العمق. على سبيل المثال، يمكن لـ YOLO اكتشاف الكائنات داخل صورة RGB، ويمكن استخدام هذا الاكتشاف لتحديد المناطق المقابلة في صورة العمق. يسمح هذا باستخراج معلومات عمق دقيقة للكائنات المكتشفة، مما يعزز قدرة الروبوت على فهم بيئته بأبعاد ثلاثية.

كاميرات RGB-D

عند العمل مع صور العمق، من الضروري التأكد من محاذاة صور RGB والعمق بشكل صحيح. توفر كاميرات RGB-D، مثل سلسلة Intel RealSense، صور RGB وصور عمق متزامنة، مما يسهل دمج المعلومات من كلا المصدرين. إذا كنت تستخدم كاميرات RGB وعمق منفصلة، فمن الضروري معايرتها لضمان محاذاة دقيقة.

Link to this sectionالاستخدام خطوة بخطوة للعمق#

في هذا المثال، نستخدم YOLO لتجزئة صورة وتطبيق القناع المستخرج لتجزئة الكائن في صورة العمق. يسمح لنا هذا بتحديد مسافة كل بكسل من الكائن المهتم من المركز البؤري للكاميرا. من خلال الحصول على معلومات المسافة هذه، يمكننا حساب المسافة بين الكاميرا والكائن المحدد في المشهد. ابدأ باستيراد المكتبات الضرورية، وإنشاء عقدة ROS، وتثبيت نموذج تجزئة وموضوع ROS.

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)

بعد ذلك، حدد وظيفة رد نداء تعالج رسالة صورة العمق الواردة. تنتظر الوظيفة رسائل صورة العمق وصورة RGB، وتحولها إلى مصفوفات NumPy، وتطبق نموذج التجزئة على صورة RGB. ثم تستخرج قناع التجزئة لكل كائن مكتشف وتحسب متوسط مسافة الكائن عن الكاميرا باستخدام صورة العمق. تحتوي معظم المستشعرات على مسافة قصوى، تُعرف بمسافة القص (clip distance)، والتي يتم تمثيل القيم التي تتجاوزها كـ inf (np.inf). قبل المعالجة، من المهم تصفية هذه القيم الفارغة وتعيين قيمة 0 لها. أخيراً، تنشر الكائنات المكتشفة مع متوسط مسافاتها إلى موضوع /ultralytics/detection/distance.

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()
الكود الكامل
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()

Link to this sectionاستخدم Ultralytics مع sensor_msgs/PointCloud2 في ROS#

Detection and Segmentation in ROS Gazebo

The sensor_msgs/PointCloud2 message type is a data structure used in ROS to represent 3D point cloud data. This message type is integral to robotic applications, enabling tasks such as 3D mapping, object recognition, and localization.

سحابة النقاط هي مجموعة من نقاط البيانات المحددة ضمن نظام إحداثيات ثلاثي الأبعاد. تمثل نقاط البيانات هذه السطح الخارجي لكائن أو مشهد، تم التقاطها عبر تقنيات المسح ثلاثي الأبعاد. تحتوي كل نقطة في السحابة على إحداثيات X و Y و Z، والتي تتوافق مع موقعها في الفضاء، وقد تتضمن أيضاً معلومات إضافية مثل اللون والشدة.

إطار مرجعي

عند العمل مع sensor_msgs/PointCloud2، من الضروري مراعاة الإطار المرجعي للمستشعر الذي تم الحصول منه على بيانات سحابة النقاط. يتم التقاط سحابة النقاط في البداية في الإطار المرجعي للمستشعر. يمكنك تحديد هذا الإطار المرجعي من خلال الاستماع إلى موضوع /tf_static. ومع ذلك، اعتماداً على متطلبات تطبيقك المحددة، قد تحتاج إلى تحويل سحابة النقاط إلى إطار مرجعي آخر. يمكن تحقيق هذا التحويل باستخدام حزمة tf2_ros، التي توفر أدوات لإدارة إطارات الإحداثيات وتحويل البيانات بينها.

الحصول على سحب النقاط

يمكن الحصول على سحب النقاط باستخدام مستشعرات مختلفة:

  1. LIDAR (كشف المدى بالضوء والقياس): يستخدم نبضات الليزر لقياس المسافات إلى الكائنات وإنشاء خرائط ثلاثية الأبعاد عالية precision.
  2. كاميرات العمق: تلتقط معلومات العمق لكل بكسل، مما يسمح بإعادة بناء المشهد ثلاثي الأبعاد.
  3. كاميرات ستيريو: تستخدم كاميرتين أو أكثر للحصول على معلومات العمق من خلال التثليث.
  4. ماسحات الضوء المهيكل: تُسقط نمطاً معروفاً على سطح ما وتقيس التشويه لحساب العمق.

Link to this sectionاستخدام YOLO مع سحب النقاط#

لدمج YOLO مع رسائل من نوع sensor_msgs/PointCloud2، يمكننا استخدام طريقة مشابهة لتلك المستخدمة لخرائط العمق. من خلال الاستفادة من معلومات اللون المضمنة في سحابة النقاط، يمكننا استخراج صورة ثنائية الأبعاد، وإجراء تجزئة على هذه الصورة باستخدام YOLO، ثم تطبيق القناع الناتج على النقاط ثلاثية الأبعاد لعزل الكائن ثلاثي الأبعاد محل الاهتمام.

للتعامل مع سحب النقاط، نوصي باستخدام Open3D (pip install open3d)، وهي مكتبة Python سهلة الاستخدام. توفر Open3D أدوات قوية لإدارة هياكل بيانات سحابة النقاط، وتصورها، وتنفيذ عمليات معقدة بسلاسة. يمكن لهذه المكتبة تبسيط العملية بشكل كبير وتعزيز قدرتنا على معالجة وتحليل سحب النقاط بالتزامن مع التجزئة القائمة على YOLO.

Link to this sectionالاستخدام خطوة بخطوة لسحب النقاط#

قم باستيراد المكتبات الضرورية وقم بإنشاء نموذج YOLO للتجزئة.

import time

import rospy

from ultralytics import YOLO

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

قم بإنشاء وظيفة pointcloud2_to_array، والتي تحول رسالة sensor_msgs/PointCloud2 إلى مصفوفتي NumPy. تحتوي رسائل sensor_msgs/PointCloud2 على n من النقاط بناءً على width و height الصورة التي تم الحصول عليها. على سبيل المثال، ستتكون الصورة 480 x 640 من 307,200 نقطة. تتضمن كل نقطة ثلاث إحداثيات مكانية (xyz) واللون المقابل بتنسيق RGB. يمكن اعتبار هذه كقناتين منفصلتين من المعلومات.

تعيد الوظيفة إحداثيات xyz وقيم RGB بتنسيق دقة الكاميرا الأصلية (width x height). تحتوي معظم المستشعرات على مسافة قصوى، تُعرف بمسافة القص، والتي يتم تمثيل القيم التي تتجاوزها كـ inf (np.inf). قبل المعالجة، من المهم تصفية هذه القيم الفارغة وتعيين قيمة 0 لها.

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

بعد ذلك، اشترك في موضوع /camera/depth/points لاستلام رسالة سحابة النقاط وتحويل رسالة sensor_msgs/PointCloud2 إلى مصفوفات NumPy تحتوي على إحداثيات XYZ وقيم RGB (باستخدام وظيفة pointcloud2_to_array). عالج صورة RGB باستخدام نموذج YOLO لاستخراج الكائنات المجزأة. لكل كائن مكتشف، استخرج قناع التجزئة وقم بتطبيقه على كل من صورة RGB وإحداثيات XYZ لعزل الكائن في الفضاء ثلاثي الأبعاد.

معالجة القناع مباشرة لأنها تتكون من قيم ثنائية، حيث يشير 1 إلى وجود الكائن و 0 إلى غيابه. لتطبيق القناع، ما عليك سوى ضرب القنوات الأصلية بالقناع. تعزل هذه العملية بشكل فعال الكائن محل الاهتمام داخل الصورة. أخيراً، قم بإنشاء كائن سحابة نقاط Open3D وقم بتصور الكائن المجزأ في الفضاء ثلاثي الأبعاد مع الألوان المرتبطة به.

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])
الكود الكامل
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

Link to this sectionالخلاصة#

مع دمج Ultralytics YOLO في ROS، يمكن لروبوتك تشغيل object detection وsegmentation عبر صور RGB وصور العمق والسحب النقطية، مما يحول تدفقات المستشعرات الخام إلى إدراك قابل للتنفيذ. من هنا، استكشف Predict mode لمزيد من خيارات الاستدلال، أو اتبع خطوات مشروع رؤية الكمبيوتر لنقل تطبيق الروبوتات الخاص بك من النموذج الأولي إلى الإنتاج.

Link to this sectionالأسئلة الشائعة#

Link to this sectionما هو نظام تشغيل الروبوت (ROS)؟#

يُعد Robot Operating System (ROS) إطار عمل مفتوح المصدر يُستخدم عادةً في الروبوتات لمساعدة المطورين في إنشاء تطبيقات روبوتات قوية. يوفر مجموعة من المكتبات والأدوات لبناء الأنظمة الروبوتية والتفاعل معها، مما يتيح تطوير التطبيقات المعقدة بشكل أسهل. يدعم ROS التواصل بين العقد باستخدام الرسائل عبر topics أو services.

Link to this sectionكيف يمكنني دمج Ultralytics YOLO مع ROS لاكتشاف الكائنات في الوقت الفعلي؟#

يتضمن دمج Ultralytics YOLO مع ROS إعداد بيئة ROS واستخدام YOLO لمعالجة بيانات المستشعرات. ابدأ بتثبيت التبعيات المطلوبة مثل ros_numpy و Ultralytics YOLO:

pip install ros_numpy ultralytics

بعد ذلك، قم بإنشاء عقدة ROS واشترك في موضوع صورة لمعالجة البيانات الواردة من أجل object detection. إليك مثال مبسط:

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()

Link to this sectionما هي مواضيع ROS وكيف تُستخدم في Ultralytics YOLO؟#

تسهل موضوعات ROS التواصل بين العقد في شبكة ROS باستخدام نموذج النشر والاشتراك. الموضوع عبارة عن قناة مسماة تستخدمها العقد لإرسال واستقبال الرسائل بشكل غير متزامن. في سياق Ultralytics YOLO، يمكنك جعل عقدة تشترك في موضوع صورة، ومعالجة الصور باستخدام YOLO لمهام مثل detection أو segmentation، ونشر النتائج في موضوعات جديدة.

على سبيل المثال، اشترك في موضوع كاميرا وعالج الصورة الواردة للاكتشاف:

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

Link to this sectionلماذا نستخدم صور العمق مع Ultralytics YOLO في ROS؟#

توفر صور العمق في ROS، التي يمثلها sensor_msgs/Image، مسافة الكائنات من الكاميرا، وهي ضرورية لمهام مثل تجنب العوائق، ورسم الخرائط ثلاثية الأبعاد، وتحديد الموقع. من خلال استخدام معلومات العمق جنباً إلى جنب مع صور RGB، يمكن للروبوتات فهم بيئتها ثلاثية الأبعاد بشكل أفضل.

باستخدام YOLO، يمكنك استخراج أقنعة التجزئة من صور RGB وتطبيق هذه الأقنعة على صور العمق للحصول على معلومات دقيقة عن الكائنات ثلاثية الأبعاد، مما يحسن قدرة الروبوت على التنقل والتفاعل مع محيطه.

Link to this sectionكيف يمكنني تصور سحب النقاط ثلاثية الأبعاد مع YOLO في ROS؟#

لتصور سحب النقاط ثلاثية الأبعاد في ROS مع YOLO:

  1. قم بتحويل رسائل sensor_msgs/PointCloud2 إلى مصفوفات NumPy.
  2. استخدم YOLO لتجزئة صور RGB.
  3. طبق قناع التجزئة على سحابة النقاط.

إليك مثال باستخدام Open3D للتصور:

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])

يوفر هذا النهج تصوراً ثلاثي الأبعاد للكائنات المجزأة، وهو مفيد لمهام مثل الملاحة والتعامل في تطبيقات الروبوتات.

التعليقات