This tutorial is created by Robotics Ambassador 023 Enzo
Rosbotics Ambassador Program https://www.theconstruct.ai/rosbotics-ambassador/)
Cours: ROS2 Basics in 5 Days C++: https://app.theconstructsim.com/courses/133
Cours: ROS2 Basics in 5 Days Python: https://app.theconstruct.ai/courses/ros2-basics-in-5-days-humble-python-132
Introduction
Le but de ce tutoriel est d’apprendre à utiliser la library OpenCV dans vos nodes C++ et Python. OpenCV (Open Source Computer Vision Library) est une bibliothèque de traitement d’images open source. Elle offre des fonctionnalités avancées pour la manipulation, l’analyse et la reconnaissance d’images, y compris la détection d’objets, le suivi, la segmentation, et bien plus encore. Cette library est très répendu et peut s’averer utile pour de nombreuses applications en robotique. Nous allons donc voir ensemble comment utiliser OpenCV à l’aide de la library cv_bridge dans vos nodes ROS2 C++ et Python.
Prérequis: Utiliser une installation ROS2 avec Gazebo et OpenCV¶
Installation ROS2
Vous pouvez vous connecter au site TheConstruct pour accéder à des machines virtuelles préconfigurées avec une installation ROS. Pour lancer et tester le code, vous devez lancer la simulation du turtlebot3 sur gazebo. Pour faire cela, entez les commandes suivantes dans le terminal:
# Declare le model de turtlebot3 à simuler
export TURTLEBOT3_MODEL=waffle_pi
# Lance la simulation du turtlebot dans gazebo
ros2 launch turtlebot3_gazebo turtlebot3_world.launch.py
Une fois la simulation du turtlebot3 lancée, celle-ci va publier sur le topic /camera/image_raw que nous allons utiliser dans les codes d’exemples.
Après avoir exécuté ces commandes, appuyez sur le bouton de l’interface gazebo et selectionnez Open Gazebo.

Vous devriez obtenir le résultat suivant:
Si vous voulez effectuer le tutoriel sur votre installation local, vous devez avoir ROS2 installé (https://docs.ros.org/en/humble/Installation.html), avoir configuré un workspace (https://docs.ros.org/en/humble/Tutorials/Beginner-Client-Libraries/Creating-A-Workspace/Creating-A-Workspace.html) et avoir installé le turtlebot3.
# pour installer tous les packages du turtlebot3
# remplacez humble par votre distro ROS2
sudo apt-get install ros-humble-turtlebot3*
# n'oubliez pas d'exporter le modèle de Turtlebot3 que vous souhaitez utiliser
export TURTLEBOT3_MODEL=waffle_pi
Installer OpenCV
Par défault, toutes les installations de ROS incluent OpenCV mais on peut quand même verifier:
# Pour OpenCV C++ et Python
sudo apt install libopencv-dev python3-opencv
Partie 1: Créer un node C++ utilisant OpenCV
Nous allons commencer par créer un package ROS2 pour compiler et executer les nodes Python et C++ du tutorial.
cd ros2_ws/src/
# Créer le package
ros2 pkg create cv_bridge_tutorial
Nous allons maintenant créer le ficher C++ qui va contenir notre node:
cd ~/ros2_ws/src/cv_bridge_tutorial/src
touch cvbridge_example_cpp.cpp
Une fois le fichier créer, ouvrez le dans votre éditeur de code et copiez y le code suivant:
// cvbridge_example_cpp.cpp// La library ROS2 C++#include "rclcpp/rclcpp.hpp"// Le message ROS image#include "sensor_msgs/msg/image.hpp"// Cette bibliothèque fournit le bridge permettant de faire la convertion ROS image <-> OpenCV#include "cv_bridge/cv_bridge.h"// La bibliothèque utilisée pour le traitement d'image#include "opencv2/opencv.hpp"class ImageProcessor : public rclcpp::Node {public:    ImageProcessor() : Node("image_processor") {        // Subscribe au topic /camera/image_raw du turtlebot3        subscription_ = this->create_subscription<sensor_msgs::msg::Image>(            "/camera/image_raw", 10, std::bind(&ImageProcessor::imageCallback, this, std::placeholders::_1));        // Créer un publisher pour republier les images après traitement        publisher_ = this->create_publisher<sensor_msgs::msg::Image>("processed_image_topic_cpp", 10);    }private:    void imageCallback(const sensor_msgs::msg::Image::SharedPtr msg) {        try {            // Créer un cv_brigde pointer            cv_bridge::CvImagePtr cv_ptr;            // Convertir l'image message ROS reçue en image OpenCV en utilisant toCvCopy            // L'image OpenCV est accessible via cv_ptr->image            cv_ptr = cv_bridge::toCvCopy(msg, sensor_msgs::image_encodings::BGR8);            /*            Une fois que votre image est convertie au format OpenCV, vous pouvez utiliser toutes            les methodes fournies par la library C++ opencv2/opencv.            */            // Créer un objec cv::Mat (OpenCV Object) qui va contenir l'image            cv::Mat grayscale_image;            // Convertit l'image du bridge en greyscale et l'assigne dans grayscale_image            cv::cvtColor(cv_ptr->image, grayscale_image, cv::COLOR_BGR2GRAY);            // Créer un autre objet cv::Mat pour recevoir une nouvelle image            cv::Mat thresholded_image;            // Effectue un thresholdeding sur l'image greyscale et assigne l'image            // de sortie dans thresholded_image            cv::threshold(grayscale_image, thresholded_image, 128, 255, cv::THRESH_BINARY);            // Convertit l'image OpenCV en image message ROS             sensor_msgs::msg::Image::SharedPtr processed_msg = cv_bridge::CvImage(                std_msgs::msg::Header(), sensor_msgs::image_encodings::MONO8, thresholded_image).toImageMsg();            // Publie l'image obtenue sur le topic processed_image_topic            publisher_->publish(*processed_msg);        } catch (cv_bridge::Exception& e) {            RCLCPP_ERROR(this->get_logger(), "cv_bridge exception: %s", e.what());            return;        }    }    rclcpp::Subscription<sensor_msgs::msg::Image>::SharedPtr subscription_;    rclcpp::Publisher<sensor_msgs::msg::Image>::SharedPtr publisher_;};int main(int argc, char** argv) {    rclcpp::init(argc, argv);    auto node = std::make_shared<ImageProcessor>();    rclcpp::spin(node);    rclcpp::shutdown();}Dans ce node exemple, on souscrit à l’image publié par le turtlebot3 sur le topic /camera/image_raw, on utilise ensuite un cv_bridge pour la convertir dans un format attendu par les méthodes de la library OpenCV. On utilise la methode cv::threshold qui applique un thresholding à l’image (https://docs.opencv.org/4.x/db/d8e/tutorial_threshold.html). On reconvertit à l’aide du cv_bridge l’image dans le format Image message de ROS et on republit cette image sur le topic /processed_image_topic_cpp.
Pour l’encodage, si vous indiquez “passthrough” dans le parametre encoding du CV_bridge, l’image de sortie aura le même encodage que l’image d’entrée. Une grande partie des fonctions d’OpenCV attendent en entrée des images possèdant un de ces deux encodages: mono8 and bgr8.
On doit ensuite éditer le CMakeList.txt pour pouvoir indiquer les dépendences necessaire à la compilation du node:
cmake_minimum_required(VERSION 3.8)project(cv_bridge_tutorial)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")  add_compile_options(-Wall -Wextra -Wpedantic)endif()# Toutes les dépendances requisesfind_package(ament_cmake REQUIRED)find_package(rclcpp REQUIRED)find_package(std_msgs REQUIRED)find_package(sensor_msgs REQUIRED)find_package(cv_bridge REQUIRED)find_package(OpenCV REQUIRED)# uncomment the following section in order to fill in# further dependencies manually.# find_package(<dependency> REQUIRED)add_executable(cvbridge_example_cpp src/cvbridge_example_cpp.cpp)ament_target_dependencies(cvbridge_example_cpp rclcpp std_msgs sensor_msgs cv_bridge OpenCV)install(PROGRAMS  DESTINATION lib/${PROJECT_NAME})install(TARGETS  cvbridge_example_cpp  DESTINATION lib/${PROJECT_NAME})ament_package()Vous pouvez build votre workspace pour verifier si la configuration du CmakeList.txt fonctionne:
cd ~/ros2_ws
colcon build
source install/setup.bash
Partie 2: Créer un node Python utilisant OpenCV
Nous allons utiliser le package crée dans la partie précedante. On va d’abord créer un dossier script et y ajouter le fichier cvbridge_example_py.py qui va contenir notre node:
cd ~/ros2_ws/src/cv_bridge_tutorial/
mkdir scripts
cd scripts
touch cvbridge_example_py.py
Une fois le fichier créer, ouvrez le dans votre éditeur de code et copiez y le code suivant:
#!/usr/bin/python3# La library ROS2 Pythonimport rclpy# La classe modele de node Pythonfrom rclpy.node import Node# Le message ROS imagefrom sensor_msgs.msg import Image# Cette bibliothèque fournit le bridge permettant de faire la convertion ROS image <-> OpenCVfrom cv_bridge import CvBridge# La bibliothèque utilisée pour le traitement d'imageimport cv2class ImageProcessorNode(Node):    def __init__(self):        super().__init__('image_processor_node')        # Subscribe au topic /camera/image_raw du turtlebot3        self.subscription = self.create_subscription(            Image,            '/camera/image_raw',            self.image_callback,            10)        self.subscription  # prevent unused variable warning        # Créer un publisher pour republier les images après traitement        self.publisher = self.create_publisher(            Image,            '/processed_image_topic_python',            10)        # Créer un attribut de class CVBridge        self.cv_bridge = CvBridge()    def image_callback(self, msg):        try:            # Utilise la methode imgmsg_to_cv2 du cv_bridge pour convertir l'image du format ROS image            # à une image OpenCV            cv_image = self.cv_bridge.imgmsg_to_cv2(msg, desired_encoding='bgr8')        except Exception as e:            self.get_logger().error(f"Error converting image: {e}")            return        """        Une fois que votre image est convertie au format OpenCV, vous pouvez utiliser toutes        les methodes fournies par la library python cv2.        """        # Convertit l'image OpenCV en grayscale        gray_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)        # Effectue un thresholding sur l'image et assigne le résultat à thresholded_image        _, thresholded_image = cv2.threshold(gray_image, 128, 255, cv2.THRESH_BINARY)        # Convertit l'image OpenCV en image message ROS        processed_msg = self.cv_bridge.cv2_to_imgmsg(thresholded_image, encoding='mono8')        # Republie l'image sur ROS        self.publisher.publish(processed_msg)def main(args=None):    rclpy.init(args=args)    image_processor_node = ImageProcessorNode()    rclpy.spin(image_processor_node)    image_processor_node.destroy_node()    rclpy.shutdown()if __name__ == '__main__':    main()
Une fois le node python écrit, on doit modifier le CmakeLists.txt créer dans la partie précédente pour pouvoir l’executer:
cmake_minimum_required(VERSION 3.8)project(cv_bridge_tutorial)if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")  add_compile_options(-Wall -Wextra -Wpedantic)endif()# find dependenciesfind_package(ament_cmake REQUIRED)find_package(rclcpp REQUIRED)find_package(std_msgs REQUIRED)find_package(sensor_msgs REQUIRED)find_package(cv_bridge REQUIRED)find_package(OpenCV REQUIRED)# uncomment the following section in order to fill in# further dependencies manually.# find_package(<dependency> REQUIRED)add_executable(cvbridge_example_cpp src/cvbridge_example_cpp.cpp)ament_target_dependencies(cvbridge_example_cpp rclcpp std_msgs sensor_msgs cv_bridge OpenCV)install(PROGRAMS  # Ajouter le scripts aux programmes à installer  scripts/cvbridge_example_py.py  DESTINATION lib/${PROJECT_NAME})install(TARGETS  cvbridge_example_cpp  DESTINATION lib/${PROJECT_NAME})ament_package()
On peut maintenant compiler le package avec les commandes suivantes:
cd ~/ros2_ws
colcon build
source install/setup.bash
Partie 3: Tester les nodes écrits précedemment
Les deux nodes du tutorial souscrivent au topic /camera/image_raw publié par le turtlebot3. Vous pouvez verifier que la simulation lancée durant l’introduction publie toujours ce topic avec la commande ros2 topic echo ou en lançant rviz2. Un fichier de configuration rviz2 est enregistré à la racine du workspace si vous utilisez le Rosject du tutorial. Vous pouvez lancer rviz2 avec cette configuration en utilisant la commande suivante:
rviz2 -d ~/ros2_ws/src/tutorial_config.rviz
Rviz2 devrait s’ouvrir avec l’interface suivante:

Vous pouvez lancer les nodes avec les commandes suivantes:
source install/setup.bash
# Pour le node python
ros2 run cv_bridge_tutorial cvbridge_example_py.py
Dans un autre terminal:
source install/setup.bash
# Pour le node C++
ros2 run cv_bridge_tutorial cvbridge_example_cpp
Vous devriez pourvoir visualiser le résultat des thresholding publiés par les nodes d’exemples:
 
				






0 Comments