как использовать OpenCV-Python в ROS

использование yolo с opencv-python в среде ROS Я хочу использовать yolo с Opencv-python в ROS для управления камерой и обнаружения объектов. Теперь я уже знаю, как запустить yolo в Windows, но я не знаю, как запустить его в ROS. как я могу перенести свой код в ROS?


person CAW    schedule 28.10.2019    source источник


Ответы (1)


ROS — это платформа для простого объединения различных библиотек, которые предоставляют интерфейсы, определенные не как файлы заголовков, а как «узлы», вызываемые «файлами запуска» (скриптами xml). Это означает, что вы хотите запускать Yolo на канале видео/камеры, но хотите, чтобы он взаимодействовал с другими библиотеками или кодом. Если нет, то ROS не нужен.

ROS(v1) в настоящее время лучше всего работает на Ubuntu. Он работает как изначально, так и в виртуальном боксе. В ROS2 есть поддержка Windows, но если у вас с ней проблемы, это другой вопрос.

Чтобы создать узел ROS для вашего кода Python, сначала поместите все это в отдельный класс/модуль; узел ROS должен иметь только шаблон интерфейса между "реальным кодом" и связью. Предполагая, что вы используете usb_cam_node для получения канала камеры, данные будут опубликованы в "теме" <camera_name>/image [sensor_msgs/Image], где <camera_name> — это usb_cam_node параметр. Тема похожа на глобальную переменную между всеми узлами ROS, считывается из Subscriber (с обратным вызовом) и публикуется в Publisher.

Затем вы должны решить, что из него публиковать. Поскольку это йоло, возможно, вам нужны ограничивающие рамки для каждого обнаружения. Существует множество предопределенных сообщений ROS (это (статические и строго типизированные) «типы» «тем»). Одним из них является geometry_msgs/PolygonStamped, который позволяет указать углы коробки и проштампуйте ее.

Вот пример кода, взятый из вики.

# yolo_boxes_node.py
import rospy
from std_msgs.msg import Header
from geometry_msgs.msg import PolygonStamped, Point32
from sensor_msgs.msg import Image
# This is your custom yolo code
import my_yolo as yolo # Assuming a method like as follows:
# yolo.evaluate(img_frame) -> 
#   boxes ([x,y,width,hight] list), confidences (list), classids (list)

# Subscribers
#     img_sub (sensor_msgs/Image): "webcam/image" #Comment: we document a name for the sub, the type, and the default topic for it

# Publishers
#     boxes_pub (geometry_msgs/PolygonStamped): "webcam/yolo/boxes"

# Publishers
boxes_pub = None

# Parameters
frequency = 100.0 # Hz

# Global Variables
img_frame = None
header = None

def img_callback(data): # data of type Image
    global img_frame
    global header
    img_frame = data.data
    header = data.header

def timer_callback(event): # This is to process data at a fixed rate, perhaps different from camera framerate
    # Convert img_frame somehow if needed
    if img_frame is None or boxes_pub is None:
        return
    boxes, confidences, classids = yolo.evaluate(img_frame)
    for b in boxes:
        msg = PolygonStamped()
        msg.header = header # You could use the header differently
        msg.polygon.points.append(Point32(x=b[0],y=b[1]))
        msg.polygon.points.append(Point32(x=b[0]+b[2],y=b[1]))
        msg.polygon.points.append(Point32(x=b[0],y=b[1]+b[3]))
        msg.polygon.points.append(Point32(x=b[0]+b[2],y=b[1]+b[3]))
        boxes_pub.publish(msg)

# In your main function, you subscribe to topics
def yolo_boxes_node():
    # Init ROS
    rospy.init_node('yolo_boxes_node', anonymous=True)

    # Parameters
    if rospy.has_param('~frequency'):
        frequency = rospy.get_param('~frequency')

    # Subscribers
    # Each subscriber has the topic, topic type, AND the callback!
    rospy.Subscriber('webcam/image', Image, img_callback)
    # Rarely/never need to hold onto the object with a variable: 
    #     img_sub = rospy.Subscriber(...)
    rospy.Timer(rospy.Duration(1.0/frequency), timer_callback)

    # Publishers
    boxes_pub = rospy.Publisher('webcam/yolo/boxes', PolygonStamped, queue_size = 100)
    # queue_size increases as buffer for msgs; if you have 1000s of boxes, might need bigger

    # spin() simply keeps python from exiting until this node is stopped
    # This is an infinite loop, the only code that gets ran are callbacks
    rospy.spin()
    # NO CODE GOES AFTER THIS, NONE! USE TIMER CALLBACKS!
    # unless you need to clean up resource allocation, close(), etc when program dies

if __name__ == '__main__':
    yolo_boxes_node()

Следовательно, пример файла запуска xml может быть:

<?xml version="1.0"?>
<!-- my_main_program.launch -->
<launch>
  <!--
    Pub: <camera_name>/image [sensor_msgs/Image]
  -->
  <node name="usb_cam_node" type="usb_cam_node" pkg="usb_cam" output="screen" restart="true">
    <param name="camera_name" value="webcam"/>
    <param name="video_device" value="/dev/video0"/>
  </node>

  <!--
    img_sub: webcam/image [sensor_msgs/Image]
    boxes_pub: webcam/yolo/boxes [geometry_msgs/PolygonStamped]
  -->
  <node name="yolo_boxes_node" type="yolo_boxes_node" pkg="my_pkg" output="screen">
    <param name="frequency" value="30.0"/>
  </node>
</launch>
person JWCS    schedule 30.10.2019
comment
Спасибо за ваш ответ. Я пытался понять ваш ответ, но понял, что мне не хватает некоторых знаний о ROS, поэтому я не могу понять часть информации, я снова увижу этот ответ после того, как получу некоторые знания о ROS. Еще раз спасибо! - person CAW; 13.11.2019
comment
Не стесняйтесь задавать вопросы о вещах, которые недостаточно ясно объяснены, и я могу улучшить это. ROS — это просто система соединения разных программ вместе для обмена данными с помощью сообщений. Если вы знаете, что вы хотите подключить и как, часть ROS не так уж сложна. - person JWCS; 14.11.2019