ROS 1 Noetic Vision Applications

Ce chapitre couvre les workflows pratiques de vision ROS 1 sur reComputer Jetson, notamment l'aperçu caméra, la reconnaissance QR, l'estimation de pose, la détection d'objets, les marqueurs AR, ainsi que des exemples OpenCV et MediaPipe.

Les exemples longs et exécutables sont enregistrés sous ./code/, et les figures associées sont enregistrées sous ./images/.

Contents

7.2.2.1 Read This First

Tout est une question d'usage.

L'environnement ROS 1 se trouve dans l'image Docker et nécessite une base Docker pour fonctionner pleinement !

Remarque : les images Docker ne peuvent exécuter que des cas visuels utilisant des caméras USB !

Entrer dans Docker.

Ouvrez un terminal pour saisir la commande suivante dans l'image docker de ROS 1

bash
sudo docker run -it \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

Figures

7.2.2.1 Read This First figure 1

7.2.2.2 Camera Preview

Aperçu caméra

Entrer dans l'image Docker ROS 1

bash
sudo docker run -it \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

Consulter les paramètres pris en charge par les caméras

Saisissez la commande suivante pour voir le nom de périphérique associé à la caméra USB :

bash
ls /dev/video*

Consultez le format de flux, la fréquence d'images et la résolution pris en charge par les caméras USB selon les numéros d'index de périphérique correspondants (0 à n) :

bash
# Install v4l2 utilities if they are not already installed:
apt update
apt install v4l-utils ffmpeg
bash
v4l2-ctl -d /dev/video0 --list-formats-ext

Image d'aperçu caméra -- commande terminal

Les terminaux peuvent ouvrir des caméras USB avec ffplay

bash
ffplay -f v4l2 -i /dev/video0

Aperçu caméra - script Python

Exécutez les caméras USB locales pour tester les scripts :

bash
 cd source_code/ROS 1/
 python3 CameraPreview.py

Le script va parcourir les caméras USB disponibles pour les afficher et imprimer les fréquences d'images

Le code source de CameraPreview.py est le suivant :

Fichier de code : 7-2-2-2-camera-preview-CameraPreview.py

python
#!/usr/bin/env python3
import cv2
import glob
import time
import os

def list_video_devices():
    """Return the /dev/video* device list."""
    devs = sorted(glob.glob("/dev/video*"))
    return devs

def try_open_camera(dev):
    """Try to open a camera device."""
    cap = cv2.VideoCapture(dev, cv2.CAP_V4L2)
    if not cap.isOpened():
        cap.release()
        return None
    return cap

def main():
    devices = list_video_devices()
    if not devices:
        print("❌ No /dev/video* found")
        return

    print("🔍 Found video devices:")
    for d in devices:
        print("  ", d)

    cams = []
    for dev in devices:
        cap = try_open_camera(dev)
        if cap:
            print(f"✅ Opened {dev}")
            cams.append((dev, cap))
        else:
            print(f"❌ Failed {dev}")

    if not cams:
        print("❌ No usable cameras")
        return

    cam_index = 0
    last_time = time.time()
    fps = 0.0

    print("\nControls:")
    print("  n: next camera")
    print("  p: previous camera")
    print("  q / ESC: quit\n")

    while True:
        dev, cap = cams[cam_index]

        ret, frame = cap.read()
        if not ret:
            cv2.putText(
                frame,
                "Camera read failed",
                (30, 50),
                cv2.FONT_HERSHEY_SIMPLEX,
                1,
                (0, 0, 255),
                2,
            )
        else:
            now = time.time()
            fps = 1.0 / (now - last_time)
            last_time = now

            # FPS display
            cv2.putText(
                frame,
                f"FPS: {fps:.2f}",
                (20, 40),
                cv2.FONT_HERSHEY_SIMPLEX,
                1,
                (0, 255, 0),
                2,
            )

            # Device name display
            cv2.putText(
                frame,
                dev,
                (20, frame.shape[0] - 20),
                cv2.FONT_HERSHEY_SIMPLEX,
                0.7,
                (255, 255, 255),
                2,
            )

        cv2.imshow("CameraPreview", frame)

        key = cv2.waitKey(1) & 0xFF
        if key in [27, ord("q")]:  # ESC / q
            break
        elif key == ord("n"):
            cam_index = (cam_index + 1) % len(cams)
            print(f"➡ Switch to {cams[cam_index][0]}")
            time.sleep(0.2)
        elif key == ord("p"):
            cam_index = (cam_index - 1) % len(cams)
            print(f"⬅ Switch to {cams[cam_index][0]}")
            time.sleep(0.2)

    for _, cap in cams:
        cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

Figures

7.2.2.2 Camera Preview figure 1

7.2.2.2 Camera Preview figure 2

7.2.2.2 Camera Preview figure 3

7.2.2.2 Camera Preview figure 4

7.2.2.2 Camera Preview figure 5

7.2.2.2 Camera Preview figure 6

7.2.2.3 QR Codes

1 Introduction au QR code

Le QR code est l'un des codes-barres bidimensionnels ; QR provient de l'acronyme anglais « Quick Response », qui signifie réponse rapide, et vient de l'espoir de son inventeur que le QR code soit décodé rapidement. Le QR code présente non seulement une grande capacité d'information, une fiabilité et un coût élevés, mais permet aussi d'encoder de manière confidentielle diverses informations textuelles, telles que des caractères chinois et des images, qui sont difficiles à falsifier et faciles à utiliser. Plus important encore, la technologie du QR code est open source.

Introduction au QR

Caractéristiques du QR code

Les valeurs de données du QR code contiennent des informations dupliquées (valeurs de redondance). Ainsi, même si jusqu'à 30 % de la structure du code bidimensionnel est détruite, cela n'affecte pas la lisibilité du code bidimensionnel. L'espace de stockage du QR code atteint jusqu'à 7089 bits ou 4296 caractères, ponctuation et caractères spéciaux compris, tous inscrits dans le QR code. Outre les chiffres et les caractères, il est possible d'encoder des mots et des phrases (comme des adresses de sites web). La structure du code devient plus complexe à mesure que davantage de données sont ajoutées au QR code et que la taille du code augmente.

Création et reconnaissance de codes QR 2D

Dépendance d'installation :

Fichier de code : 7-2-2-3-qr-codes-install-deps.sh

bash
sudo apt update
sudo apt install -y python3-pip libzbar-dev
python3 -m pip install qrcode pyzbar

Crée un objet qrcode, ce qui permet d'exécuter directement le script qr code create.py dans le répertoire :

bash
python3 qrcode_create.py

Un code bidimensionnel (QR-code) avec un logo défini est généré dans le dossier figure du répertoire de travail. L'emplacement de l'image de logo préréglée se trouve également dans le dossier figure. L'effet du code 2D généré est le suivant :

Le code source de qrcode create.py est le suivant :

Fichier de code : 7-2-2-3-qr-codes-create.py

python
#!/usr/bin/env python3
import os
import qrcode
from PIL import Image
from pathlib import Path


def add_logo(img, logo_path):
    # Add logo, open logo image
    icon = Image.open(    logo_path)
    img_w, img_h = img.size
    # Set the size of the logo
    factor = 6
    size_w = int(img_w / factor)
    size_h = int(img_h / factor)
    icon_w, icon_h = icon.size
    if icon_w > size_w: icon_w = size_w
    if icon_h > size_h: icon_h = size_h
    # Resize the logo
    icon = icon.resize((icon_w, icon_h), Image.Resampling.LANCZOS)
    # Center the logo
    w = int((img_w - icon_w) / 2)
    h = int((img_h - icon_h) / 2)
    # Paste the logo
    img.paste(icon, (w, h), mask=None)
    return img


def create_qrcode(data, file_name, logo_path):
    '''
    version: Integer from 1 to 40, controls the size of the QR code.
    error_correction: Controls the error correction function. Can be one of the following:
        ERROR_CORRECT_L: About 7% or fewer errors can be corrected.
        ERROR_CORRECT_M (default): About 15% or fewer errors can be corrected.
        ERROR_CORRECT_H: About 30% or fewer errors can be corrected.
    box_size: Controls the number of pixels in each box of the QR code.
    border: Controls the number of boxes for the border (the default is 4).
    '''
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=10,
        border=4)
    # Add data to the QR code
    qr.add_data(data)
    print(data)
    qr.make(fit=True)
    img = qr.make_image(fill_color="green", back_color="white")
    # Add logo if file exists
    if Path(logo_path).is_file():
        img = add_logo(img, logo_path)
    # Save and show the image
    img.save(file_name)
    img.show()
    return img


if __name__ == '__main__':
    file_path = "./figures"
    logo_path = file_path + "/seeed_logo.png"
    out_img = file_path + '/seeed_logo_qr.jpg'
    text = input("Please enter:")
    create_qrcode(text, out_img, logo_path)

La signification des paramètres pour la création du QR-code est la suivante :

Fichier de code : 7-2-2-3-qr-codes-example-03.py

python
'''
    Parameters:
    version:integer from 1 to 40 that controls QR-code size.
             use None with fit if you want the library to choose automatically.
    error_correction:controls QR-code error correction.
    ERROR_CORRECT_L:about 7% or fewer errors can be corrected.
    ERROR_CORRECT_M (default): about 15% or fewer errors can be corrected.
    ROR_CORRECT_H:about 30% or fewer errors can be corrected.
    box_size:controls the pixel size of each QR-code cell.
    border:controls the border width in cells; the default 4 is the standard minimum.
    '''

Lorsque vous générez un code bidimensionnel, vous pouvez l'imprimer (une taille A4 suffit) pour le test de reconnaissance bidimensionnelle.

Les segments de code de la fonction de reconnaissance sont les suivants :

Fichier de code : 7-2-2-3-qr-codes-example-04.py

python
def decodeDisplay(image, font_path):
    gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
    # Convert decoded text to Unicode before drawing it on the image.
    barcodes = pyzbar.decode(gray)
    for barcode in barcodes:
        # Extract the QR code bounding box.
        (x, y, w, h) = barcode.rect
        # Draw the barcode bounding box on the image.
        cv.rectangle(image, (x, y), (x + w, y + h), (225, 0, 0), 5)
        encoding = 'UTF-8'
        # Convert the decoded bytes to a string before drawing.
        barcodeData = barcode.data.decode(encoding)
        barcodeType = barcode.type
        # Draw the decoded data and type on the image.
        pilimg = Image.fromarray(image)
        # Create a drawing object.
        draw = ImageDraw.Draw(pilimg)
        # Parameter 1: font file path. Parameter 2: font size.
        fontStyle = ImageFont.truetype(font_path, size=12, encoding=encoding)
        # Parameter 1: text position. Parameter 2: text. Parameter 3: text color. Parameter 4: font.
        draw.text((x, y - 25), str(barcode.data, encoding), fill=(255, 0, 0), font=fontStyle)
        # Convert the PIL image back to an OpenCV image.
        image = cv.cvtColor(np.array(pilimg), cv.COLOR_RGB2BGR)
        # Print barcode data and type to the terminal.
        print("[INFO] Found {} barcode: {}".format(barcodeType, barcodeData))
    return image

Dans le répertoire de reconnaissance de codes QR, lancez la détection du code bidimensionnel :

python
qrcode_parsing_usb.py

Les résultats des tests sont illustrés ci-dessous, et un cadre de test est dessiné une fois le code 2D identifié.

Figures

7.2.2.3 QR Codes figure 1

7.2.2.3 QR Codes figure 2

7.2.2.3 QR Codes figure 3

7.2.2.4 Human Pose Estimation

Estimation de pose humaine

Introduction

L'estimation de la posture humaine est une technologie de vision basée sur l'informatique conçue pour identifier et localiser automatiquement l'emplacement des articulations clés du corps humain à travers des images ou des vidéos, et pour modéliser la structure osseuse du corps humain. L'estimation de pose humaine (Human Pose Estimation), largement appliquée dans les domaines de la reconnaissance d'action, de la surveillance intelligente, de l'interaction humaine, de l'analyse motrice, de la rééducation et de la réalité virtuelle, constitue une technologie clé reliant « voir le corps humain » et « comprendre le comportement humain ».

II. Principe de fonctionnement

Tout d'abord, les images humaines saisies sont envoyées au réseau neuronal convolutif (CNN) pour caractérisation, avec des profils sémantiques de haut niveau ; la structure du réseau est ensuite divisée en deux branches, l'une pour prédire les Part Confidence Maps (cartes de confiance des points clés), afin de montrer la distribution de probabilité des positions dans l'espace pour chaque articulation humaine, et l'autre pour prédire les Part Affinity Fields (PAF, champs d'affinité des parties du corps), afin de décrire les liens et les informations directionnelles entre les différentes articulations sous forme vectorielle. Sur la base de la carte de confiance, qui détecte le nœud candidat, et en utilisant les informations de cohérence directionnelle fournies par le PAF, la connexion entre les nœuds est modélisée comme un problème d'appariement biparti (bipartite matching) dans le diagramme, en associant correctement les nœuds articulaires appartenant à la même personne et en construisant progressivement le squelette humain complet. En outre, l'estimation de gestes multi-personnes peut être considérée comme un problème d'analyse multi-personnes (Multi-Person Parsing), qui traduit les connexions multi-points en problèmes d'appariement graphique, et utilise la méthode classique d'appariement bidimensionnel, telle que l'algorithme hongrois (Hungarian Algorithm), pour trouver la meilleure combinaison de nœuds articulaires et ainsi obtenir des estimations précises et stables de multiples postures humaines.

Lancement de la procédure

Accès aux images docker ROS 1

bash
sudo docker run -it \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

Dépendance d'installation

bash
apt-get update
apt-get install -y libatlas-base-dev libprotobuf-dev protobuf-build
apt-get install python3-pip
pip install \
  https://files.pythonhosted.org/packages/c0/b7/20228024ef7bcfaa9cad2cb2514f3f7cc7a2c2c16715dc65cb01c793693c/mediapipe-0.10.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl

# Check whether the installation succeeded.
python3 -c "import mediapipe as mp; print(mp.__version__)"

Utilisation d'images pour l'inférence

Entrez dans le répertoire des fichiers de code, exécutez le script de code

bash
cd sources_code/ROS 1
python3 target_pose_img.py

Utilisation de l'inférence sur images vidéo

Exécutez le script de code

bash
undefined

Figures

7.2.2.4 Human Pose Estimation figure 1

7.2.2.4 Human Pose Estimation figure 2

7.2.2.4 Human Pose Estimation figure 3

7.2.2.5 Object Detection

Détection d'objets

En apprentissage profond, la détection de cibles (Target Detection) est l'une des tâches centrales de la vision par ordinateur et vise à identifier et marquer tous les objets d'intérêt dans l'image. Les méthodes courantes se divisent en deux grandes catégories :

Détection en deux étapes : Les méthodes représentatives sont R-CNN, Fast R-CNN, Faster R-CNN. On génère d'abord des régions candidates (Region Proposals), puis on classifie et on régresse chaque région candidate. Ces méthodes offrent une précision élevée, mais sont relativement lentes et adaptées aux scénarios exigeant une haute précision.

Détection en une étape : Les méthodes représentatives sont YOLO (You Only Look Once), SSD (Single Shot MultiBox Detector). Les catégories d'objets et les cadres de délimitation sont projetés directement sur les cartes de caractéristiques sans avoir besoin de générer des régions candidates, ce qui les rend rapides et adaptées à la détection en temps réel, mais avec une précision légèrement inférieure à celle des méthodes en deux étapes.

Ce titre démontrera comment utiliser le module dnn d'OpenCV pour réaliser le test de cible

Démarrer le programme

Inférence sur images

Entrez dans le répertoire de code, exécutez les scripts

bash
cd sources_code/ROS 1
python3 target_detect_img.py

Caméras logiques

Entrez dans le répertoire de code, exécutez les scripts

bash
cd sources_code/ROS 1
python3 target_detect_video.py

7.2.2.6 AR Vision

Vision AR

La réalité augmentée (AR, Augmented Reality) désigne l'utilisation de technologies de vision basées sur l'informatique pour superposer en temps réel des informations virtuelles ou des modèles tridimensionnels dans des images ou des vidéos du monde réel, améliorant ainsi la perception et l'expérience interactive de l'utilisateur avec l'environnement. Elle réalise l'alignement spatial et l'interaction en temps réel entre objets virtuels et monde réel grâce à la capture vidéo de scènes réelles, combinée à des technologies telles que la détection de cibles, le suivi de points caractéristiques et l'estimation de profondeur, et est largement utilisée dans des domaines tels que les loisirs et le divertissement, la conception industrielle, la formation éducative et la navigation.

Entrer dans l'image Docker ROS 1

bash
sudo docker run -it \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

Calibration de la caméra.

ROS fournit officiellement un package d'étalonnage de caméra pour marquer facilement les caméras USB :

bash
apt install ros-noetic-camera-calibration
apt install ros-noetic-usb-cam

Lancer les nœuds de la caméra USB

bash
roslaunch usb_cam usb_cam-test.launch

Préparation des mires

Téléchargez et imprimez les mires au format A4

Démarrer les nœuds d'étalonnage

Ouvrez un autre terminal dans l'image docker de ROS 1, exécutez les nœuds d'étalonnage

bash
sudo docker run -it \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

  rosrun camera_calibration cameracalibrator.py \
  --size 8x6 --square 0.025 image:=/usb_cam/image_raw camera:=/usb_cam

Description des paramètres :

--size 8x6 : nombre d'angles internes (colonne x rangée) (8x6 = 48 angles d'une grille 9x7)

--square 0.025 : longueur de chaque carré, unité m (24 mm)

Sujet image

Camera:=/usb_cam : espace de noms de la caméra

Interface d'étalonnage

X : mouvement gauche-droite de la mire dans la vue caméra

Y : mouvement haut-bas de la mire dans la vue caméra

Size : avant-arrière de la mire dans la vue caméra

Skew : inclinaison de la mire dans la vue caméra

Après un démarrage réussi, placez la mire au centre de l'image, en changeant de position. Le système s'identifiera automatiquement ; l'idéal est que les barres sous X, Y, Size, Skew soient remplies autant que possible, avec une collecte de données passant du rouge au jaune.

Cliquez sur Calibrate pour calculer les paramètres internes de la caméra ; il se peut que l'interface semble ne pas répondre, mais le terminal continue d'afficher une sortie, patientez !

Après un calcul réussi, le terminal affiche les paramètres de la caméra, cliquez sur SAVE pour enregistrer les paramètres de la caméra.

Le résultat sera stocké par défaut dans /tmp/calibrationdata.tar.gz

Décompressez-le et déplacez le fichier yaml des paramètres d'étalonnage vers le répertoire du code du script

bash
mv tmp/ost.yaml /source_code/ROS 1/sources

Exécuter le script

Exécutez le script AR dans le conteneur Docker ROS 1 :

bash
python3 simple_AR.py

Fichier de code : 7-2-2-6-ar-vision-example-01.py

python
#!/usr/bin/env python3
# simple_AR.py
# common lib
import os
import sys
import time
import cv2 as cv
import numpy as np
import yaml

print("import done")

cv_edition = cv.__version__
print("cv_edition: ",cv_edition)

def load_camera_from_ost(yaml_path: str):
    with open(yaml_path, 'r') as f:
        params = yaml.safe_load(f)
    camera_data = params['camera_matrix']['data']
    dist_data = params['distortion_coefficients']['data']
    camera_matrix = np.array(camera_data, dtype=np.float32).reshape(3, 3)
    dist_coeffs = np.array(dist_data, dtype=np.float32).reshape(-1, 1)
    return camera_matrix, dist_coeffs

def draw_stickman(img, img_pts):
    cv.line(img, tuple(img_pts[18]), tuple(img_pts[4]), (0, 0, 255), 3)
    cv.line(img, tuple(img_pts[18]), tuple(img_pts[6]), (0, 0, 255), 3)
    cv.line(img, tuple(img_pts[18]), tuple(img_pts[21]), (0, 0, 255), 3)
    cv.line(img, tuple(img_pts[21]), tuple(img_pts[19]), (0, 0, 255), 3)
    cv.line(img, tuple(img_pts[21]), tuple(img_pts[20]), (0, 0, 255), 3)
    cv.line(img, tuple(img_pts[21]), tuple(img_pts[22]), (0, 0, 255), 3)
    cv.circle(img, tuple(img_pts[22]), 15, (0, 0, 255), -1)
    cv.line(img, tuple(img_pts[74]), tuple(img_pts[72]), (0, 255, 0), 3)
    cv.line(img, tuple(img_pts[74]), tuple(img_pts[73]), (0, 255, 0), 3)
    cv.line(img, tuple(img_pts[74]), tuple(img_pts[37]), (0, 255, 0), 3)
    cv.line(img, tuple(img_pts[37]), tuple(img_pts[76]), (0, 255, 0), 3)
    cv.line(img, tuple(img_pts[37]), tuple(img_pts[77]), (0, 255, 0), 3)
    cv.line(img, tuple(img_pts[37]), tuple(img_pts[75]), (0, 255, 0), 3)
    cv.circle(img, tuple(img_pts[75]), 15, (0, 255, 0), -1)
    return img

def main():
    print("start")

    pattern_size = (8,6)
    yaml_path = os.path.join(os.path.dirname(__file__), 'sources', 'ost.yaml')
    camera_matrix, dist_coeffs = load_camera_from_ost(yaml_path)

    object_points = np.zeros((pattern_size[0] * pattern_size[1], 3), np.float32)
    object_points[:,:2] = np.mgrid[0:pattern_size[0], 0:pattern_size[1]].T.reshape(-1, 2)

    axis = np.float32([
            [0, 0, -1], [0, 8, -1], [5, 8, -1], [5, 0, -1],
            [1, 2, -1], [1, 6, -1], [4, 2, -1], [4, 6, -1],
            [1, 0, -4], [1, 8, -4], [4, 0, -4], [4, 8, -4],
            [1, 2, -4], [1, 6, -4], [4, 2, -4], [4, 6, -4],
            [0, 1, -4], [3, 2, -1], [2, 2, -3], [3, 2, -3],
            [1, 2, -3], [2, 2, -4], [2, 2, -5], [0, 4, -4],
            [2, 3, -4], [1, 3, -4], [4, 3, -5], [4, 5, -5],
            [1, 2, -3], [1, 6, -3], [5, 2, -3], [5, 6, -3],
            [3, 4, -5], [0, 6, -4], [5, 6, -4], [2, 8, -4],
            [3, 8, -4], [2, 6, -4], [2, 0, -4], [1, 5, -4],
            [3, 0, -4], [3, 2, -4], [0, 3, -4], [1, 2, -4],
            [4, 2, -4], [5, 3, -4], [2, 7, -4], [3, 7, -4],
            [3, 3, -1], [3, 5, -1], [1, 5, -1], [1, 3, -1],
            [3, 3, -3], [3, 5, -3], [1, 5, -3], [1, 3, -3],
            [1, 3, -6], [1, 5, -6], [3, 3, -4], [3, 5, -4],
            [0, 0, -4], [3, 1, -4], [1, 1, -4], [0, 2, -4],
            [2, 4, -4], [4, 4, -4], [0, 8, -4], [5, 8, -4],
            [5, 0, -4], [0, 4, -5], [5, 4, -4], [5, 4, -5],
            [2, 5, -1], [2, 7, -1], [2, 6, -3], [2, 6, -5],
            [2, 5, -3], [2, 7, -3]
            ])

    capture = cv.VideoCapture(0)
    if cv_edition[0] == '3':
        capture.set(cv.CAP_PROP_FOURCC, cv.VideoWriter_fourcc(*'XVID'))
    else:
        capture.set(cv.CAP_PROP_FOURCC, cv.VideoWriter.fourcc('M', 'J', 'P', 'G'))
    capture.set(6, cv.VideoWriter_fourcc('M', 'J', 'P', 'G'))
    capture.set(cv.CAP_PROP_FRAME_WIDTH, 640)
    capture.set(cv.CAP_PROP_FRAME_HEIGHT, 480)

    last_time = time.time()
    fps = 0.0

    while True:
        ret, frame = capture.read()
        if not ret:
            break

        now = time.time()
        fps = 1.0 / max(1e-6, (now - last_time))
        last_time = now
        gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)

        retval, corners = cv.findChessboardCorners(
            gray,
            pattern_size,
            None,
            flags=cv.CALIB_CB_ADAPTIVE_THRESH + cv.CALIB_CB_NORMALIZE_IMAGE + cv.CALIB_CB_FAST_CHECK,
        )

        if retval:
            corners = cv.cornerSubPix(
                gray,
                corners,
                (11, 11),
                (-1, -1),
                (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001),
            )
            retval, rvec, tvec, _inliers = cv.solvePnPRansac(
                object_points,
                corners,
                camera_matrix,
                dist_coeffs,
            )
            if retval:
                image_points, _jacobian = cv.projectPoints(
                    axis,
                    rvec,
                    tvec,
                    camera_matrix,
                    dist_coeffs,
                )
                img_pts = np.int32(image_points).reshape(-1, 2)
                frame = draw_stickman(frame, img_pts)

                cv.putText(frame, "AR Active - 2 Stickman", (10, 60), cv.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)
            else:
                cv.putText(frame, "Pose estimation failed", (10, 60), cv.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)
        else:
            cv.putText(frame, "No chessboard detected", (10, 60), cv.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2)

        cv.putText(frame, f"FPS: {fps:.1f}", (10, 30), cv.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
        cv.imshow('frame', frame)

        action = cv.waitKey(1) & 0xFF
        if action == ord('q') or action == 113:
            break

    capture.release()
    cv.destroyAllWindows()

if __name__ == "__main__":
    main()

Figures

7.2.2.6 AR Vision figure 1

7.2.2.6 AR Vision figure 2

7.2.2.6 AR Vision figure 3

7.2.2.6 AR Vision figure 4

7.2.2.6 AR Vision figure 5

7.2.2.6 AR Vision figure 6

7.2.2.6 AR Vision figure 7

7.2.2.7 OpenCV Applications

Application OpenCV

Opencv apps est un ensemble de packages fonctionnels maintenus par la communauté ROS, qui encapsule un grand nombre de traitements d'images OpenCV et de visualisations informatiques en nœuds ROS, permettant d'appeler directement l'entrée d'un topic standard dans le système ROS, sans avoir à préparer soi-même le code OpenCV.

Démarrer Opencv apps

Démarrer docker

bash
sudo docker run -it \
  --name ros_noetic \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

Installation

bash
apt install ros-noetic-opencv-apps
apt install -y ros-noetic-usb-cam


# Check whether the installation succeeded.
roscd opencv_apps
# Open another terminal.
sudo docker exec -it ros_noetic bash

rosrun opencv_apps face_detection image:=/usb_cam/image_raw

Activer la caméra

bash
roslaunch usb_cam usb_cam-test.launch

Utiliser Opencv apps

Une seule fonction peut être exécutée à la fois. La commande doit être exécutée après l'activation de la caméra :

bash
roslaunch opencv_apps face_recognition.launch image:=/usb_cam/image_raw          # Face recognition
roslaunch opencv_apps corner_harris.launch image:=/usb_cam/image_raw             # Harris corner detection
roslaunch opencv_apps camshift.launch image:=/usb_cam/image_raw                  # Object tracking
roslaunch opencv_apps contour_moments.launch image:=/usb_cam/image_raw           # Contour moments
roslaunch opencv_apps convex_hull.launch image:=/usb_cam/image_raw               # Convex hull
roslaunch opencv_apps discrete_fourier_transform.launch image:=/usb_cam/image_raw # Discrete Fourier transform
roslaunch opencv_apps edge_detection.launch image:=/usb_cam/image_raw            # Edge detection
roslaunch opencv_apps face_detection.launch image:=/usb_cam/image_raw            # Face detection
roslaunch opencv_apps fback_flow.launch image:=/usb_cam/image_raw                # Optical flow detection
roslaunch opencv_apps find_contours.launch image:=/usb_cam/image_raw             # Contour detection
roslaunch opencv_apps general_contours.launch image:=/usb_cam/image_raw          # General contour detection
roslaunch opencv_apps goodfeature_track.launch image:=/usb_cam/image_raw         # Feature point tracking
roslaunch opencv_apps hls_color_filter.launch image:=/usb_cam/image_raw          # HLS color filtering
roslaunch opencv_apps hough_circles.launch image:=/usb_cam/image_raw             # Hough circle detection
roslaunch opencv_apps hough_lines.launch image:=/usb_cam/image_raw               # Hough line detection
roslaunch opencv_apps hsv_color_filter.launch image:=/usb_cam/image_raw          # HSV color filtering
roslaunch opencv_apps lk_flow.launch image:=/usb_cam/image_raw                   # LKoptical flow algorithm
roslaunch opencv_apps people_detect.launch image:=/usb_cam/image_raw             # People detection
roslaunch opencv_apps phase_corr.launch image:=/usb_cam/image_raw                # Phase correlation displacement detection
roslaunch opencv_apps pyramids.launch image:=/usb_cam/image_raw                  # Image pyramid
roslaunch opencv_apps rgb_color_filter.launch image:=/usb_cam/image_raw          # RGB color filtering
roslaunch opencv_apps segment_objects.launch image:=/usb_cam/image_raw           # Foreground segmentation
roslaunch opencv_apps simple_flow.launch image:=/usb_cam/image_raw               # Simple optical flow
roslaunch opencv_apps smoothing.launch image:=/usb_cam/image_raw                 # Smoothing filter
roslaunch opencv_apps threshold.launch image:=/usb_cam/image_raw                 # Thresholding
roslaunch opencv_apps watershed_segmentation.launch image:=/usb_cam/image_raw    # Watershed segmentation

Aperçu

Activez la caméra et activez l'une des fonctionnalités d'Opencv apps pour visualiser l'image de la manière suivante.

Accès local

Saisissez la commande suivante et sélectionnez le topic correspondant pour voir l'effet :

rqt image view

Visualisation sur réseau local

Sur le même réseau local, saisissez IP:port (8080) dans le navigateur, par exemple :

192.168.7.47:8080 # IP refers to host IP

Références

wiki : http://wiki.ros.org/opencv_apps

Source : https://github.com/ros-perception/opencv_apps.git

La plupart des codes proviennent à l'origine de https://github.com/Itseez/opencv/tree/master/samples/cpp.

7.2.2.8 ROS + OpenCV Fundamentals

Présentation des fonctionnalités

ROS a déjà intégré OpenCV (3.x et versions supérieures) lors de l'installation, et les images sont transmises dans ROS au format de message sensor_msgs/Image, qui ne peut pas être traité directement avec OpenCV. À cette fin, ROS fournit cv_bridge pour :

Une conversion efficace entre ROS Image ↔ OpenCV Mat (tableau numpy) est le pont central du traitement d'images ROS.

Configuration des dépendances du package fonctionnel

package.xml

Fichier de code : 7-2-2-8-ros-plus-opencv-fundamentals-package.xml

bash
<?xml version="1.0"?>
<package format="2">
  <name>ros_opencv_demo</name>
  <version>0.0.1</version>
  <description>
    ROS + OpenCV sample package that uses cv_bridge to subscribe to USB camera images and process them with OpenCV.
  </description>

  <!-- maintainer information -->
  <maintainer email="you@example.com">your_name</maintainer>

  <!-- open-source license -->
  <license>BSD</license>

  <!-- build tool -->
  <buildtool_depend>catkin</buildtool_depend>

  <!-- ================= core dependencies ================= -->

  <!-- Python / ROS -->
  <depend>rospy</depend>

  <!-- ROS messages -->
  <depend>std_msgs</depend>
  <depend>sensor_msgs</depend>

  <!-- image-related dependencies -->
  <depend>cv_bridge</depend>
  <depend>image_transport</depend>

  <!-- Optional: enable this if you use PCL later. -->
  <!-- <depend>pcl_ros</depend> -->

  <!-- ================= optional exports ================= -->
  <export>
  </export>

</package>

CMakeLists.txt (nœud Python minimisé)

Fichier de code : 7-2-2-8-ros-plus-opencv-fundamentals-example-02.cmake

bash
cmake_minimum_required(VERSION 3.0.2)
project(ros_opencv_demo)
find_package(catkin REQUIRED COMPONENTS
  roscpp
  rospy
  std_msgs
  sensor_msgs
  cv_bridge
  image_transport
)
catkin_package()
include_directories(
  ${catkin_INCLUDE_DIRS}
)

Démarrer le nœud caméra USB

bash
# Install dependencies if needed.
apt install -y ros-noetic-usb-cam
roslaunch usb_cam usb_cam-test.launch

Nœud d'abonnement aux images couleur (code complet)

Nom de fichier : usb_cam_image.py

Fichier de code : 7-2-2-8-ros-plus-opencv-fundamentals-usb_cam_image.py

bash
#!/usr/bin/env python3

import rospy
import cv2
from sensor_msgs.msg import Image
from cv_bridge import CvBridge, CvBridgeError


class UsbCamImageNode:
    def __init__(self):
        rospy.init_node("usb_cam_image_node", anonymous=True)

        self.bridge = CvBridge()

        # subscribe to USB camera images
        self.image_sub = rospy.Subscriber(
            "/usb_cam/image_raw",
            Image,
            self.image_callback,
            queue_size=1
        )

        rospy.loginfo("USB Camera Image Subscriber Started")

    def image_callback(self, msg):
        try:
            # ROS Image → OpenCV BGR
            frame = self.bridge.imgmsg_to_cv2(msg, desired_encoding="bgr8")
        except CvBridgeError as e:
            rospy.logerr(e)
            return

        # display the image
        cv2.imshow("USB Camera Image", frame)
        cv2.waitKey(1)


if __name__ == "__main__":
    try:
        UsbCamImageNode()
        rospy.spin()
    except rospy.ROSInterruptException:
        pass
    finally:
        cv2.destroyAllWindows()

Accorder les droits d'exécution

bash
chmod +x usb_cam_image.py
cd /ros_ws
catkin_make

Exécuter l'exemple

Installer l'outil multi-terminal

bash
apt-get install terminator
# Run
terminator

Ouvrez un autre terminal horizontalement à l'aide du raccourci ctrl + Shift + o dans l'interface du terminal contextuel

Terminal 1 : lancer la caméra.

Roslaunch usb cam usb cam-test.launch

Terminal 2 : exécuter le nœud d'abonnement

rosrun ros opencv demo usb_cam_image.py

Vous verrez une fenêtre OpenCV affichant la caméra USB en temps réel.

Consulter les communications entre nœuds

Démarrez une autre opération de terminal :

bash
rqt_graph

Figures

7.2.2.8 ROS + OpenCV Fundamentals figure 1

7.2.2.8 ROS + OpenCV Fundamentals figure 2

7.2.2.8 ROS + OpenCV Fundamentals figure 3

7.2.2.9 MediaPipe Development

Introduction à MediaPipe

MediaPipe est un framework de calcul de capteurs multiplateforme haute performance open source de Google, dédié à la construction de flux de traitement de vision et multimodaux en temps réel. Il est largement utilisé pour des tâches telles que l'estimation de pose humaine, la reconnaissance des mains, la détection de visage et le suivi de points clés, grâce à un calcul graphique (Graph) qui relie efficacement les modules d'entrée caméra, d'inférence de modèle et de post-traitement. MediaPipe intègre divers modèles d'apprentissage profond légers et quantifiés, prenant en charge l'inférence en temps réel sur CPU et très adaptés aux plateformes embarquées (par exemple Jetson, mobile) ; les développeurs peuvent rapidement mettre en œuvre des applications sensorielles en temps réel stables et à faible latence avec peu de code.

Solutions d'apprentissage profond dans MediaPipe

Cliquez sur une image pour consulter le tableau complet

Démarrer docker

bash
sudo docker run -it \
  --net=host \
  --privileged \
  -v /dev:/dev \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -e DISPLAY=$DISPLAY \
  -e QT_X11_NO_MITSHM=1 \
  ros:noetic

Cas d'utilisation

Test de la main

bash
cd sources_code/ROS 1/mediapipe
python3 hand.py

Vérification faciale.

bash
cd sources_code/ROS 1/mediapipe
python3 face_detection.py

Effets faciaux.

bash
cd sources_code/ROS 1/mediapipe
python3 face_effect.py

Identification d'objets D

bash
cd sources_code/ROS 1/mediapipe
python3 object_reg.py

Pinceau

bash
cd sources_code/ROS 1/mediapipe
python3 virtual_brush.py

Reconnaissance de gestes.

bash
cd sources_code/ROS 1/mediapipe
python3 gesture_recognition.py

Contrôle par les doigts.

bash
cd sources_code/ROS 1/mediapipe
python3 hand_control.py

Posture

bash
cd sources_code/ROS 1/mediapipe
python3 pose_estimation.py

Test de visage

bash
cd sources_code/ROS 1/mediapipe
python3 face_mesh.py

Test global

bash
cd sources_code/ROS 1/mediapipe
python3 holistic.py

Segmentation de cas

bash
cd sources_code/ROS 1/mediapipe
python3 selfie_segmentation.py

Figures

7.2.2.9 MediaPipe Development figure 1

7.2.2.9 MediaPipe Development figure 2

7.2.2.9 MediaPipe Development figure 3

7.2.2.9 MediaPipe Development figure 4

7.2.2.9 MediaPipe Development figure 5

7.2.2.9 MediaPipe Development figure 6

7.2.2.9 MediaPipe Development figure 7

7.2.2.9 MediaPipe Development figure 8

7.2.2.9 MediaPipe Development figure 9

7.2.2.9 MediaPipe Development figure 10

7.2.2.9 MediaPipe Development figure 11

7.2.2.9 MediaPipe Development figure 12

7.2.2.9 MediaPipe Development figure 13