ROS 1 Noetic Vision-Anwendungen

Dieses Kapitel behandelt praktische ROS 1 Vision-Workflows auf dem reComputer Jetson, darunter Kameravorschau, QR-Code-Erkennung, Posenschätzung, Objekterkennung, AR-Marker, OpenCV und MediaPipe-Beispiele.

Lange lauffähige Beispiele sind unter ./code/ gespeichert, zugehörige Abbildungen unter ./images/.

Inhalt

7.2.2.1 Read This First

Es kommt auf die Nutzung an.

Die ROS-1-Umgebung befindet sich im Docker-Image und benötigt eine Docker-Basis, um vollständig funktionsfähig zu sein!

Hinweis: Docker-Images können visuelle Anwendungsfälle nur mit USB-Kameras ausführen!

In Docker einsteigen.

Öffnen Sie ein Terminal und geben Sie den folgenden Befehl in das Docker-Image für ROS 1 ein

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

Abbildungen

7.2.2.1 Read This First figure 1

7.2.2.2 Camera Preview

Kameravorschau

In das ROS 1 Docker-Image einsteigen

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

Von Kameras unterstützte Parameter anzeigen

Geben Sie den folgenden Befehl ein, um den Gerätenamen der USB-Kamera-Zuordnung anzuzeigen:

bash
ls /dev/video*

Sehen Sie sich Stream-Format, Bildrate und Auflösung der unterstützten USB-Kameras anhand der entsprechenden Geräteindexnummern (0 bis n) an:

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

Kameravorschau-Bild -- Terminalbefehl

Terminals können USB-Kameras mit ffplay öffnen

bash
ffplay -f v4l2 -i /dev/video0

Kameravorschau - Python-Skript

Führen Sie lokale USB-Kameras aus, um das Skript zu testen:

bash
 cd source_code/ROS 1/
 python3 CameraPreview.py

Das Skript durchläuft die verfügbaren USB-Kameras, zeigt sie an und gibt die Bildraten aus

Der Quellcode von CameraPreview.py lautet wie folgt:

Code-Datei: 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()

Abbildungen

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

Einführung zu 1 QR-Code

Der QR-Code ist einer der zweidimensionalen Barcodes, und QR steht als Abkürzung für das englische „Quick Response“, was schnelle Antwort bedeutet und auf den Wunsch eines Erfinders zurückgeht, den QR-Code schnell dekodierbar zu machen. Der QR-Code zeichnet sich nicht nur durch hohe Informationskapazität, Zuverlässigkeit und geringe Kosten aus, sondern ermöglicht es auch, vielfältige Textinformationen wie chinesische Schriftzeichen und Bilder vertraulich zu behandeln und Fälschungen leicht zu erkennen. Wichtiger noch: Die QR-Code-Technologie ist quelloffen.

Einführung zu QR

Eigenschaften des QR-Codes

Die Datenwerte im QR-Code enthalten redundante Informationen. Dadurch wird die Lesbarkeit des zweidimensionalen Codes selbst dann nicht beeinträchtigt, wenn bis zu 30 Prozent der Codestruktur zerstört sind. Der Speicherplatz des QR-Codes beträgt bis zu 7089 Bit bzw. 4296 Zeichen, einschließlich Satzzeichen und Sonderzeichen, die alle in den QR-Code eingeschrieben werden können. Neben Zahlen und Zeichen lassen sich auch Wörter und Phrasen (etwa Webseiten) codieren. Je mehr Daten dem QR-Code hinzugefügt werden, desto komplexer wird die Codestruktur und desto größer die Codegröße.

Erstellung und Erkennung von QR-2D-Codes

Installationsabhängigkeiten:

Code-Datei: 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

Erzeugt ein qrcode-Objekt; das Skript qrcode create.py lässt sich direkt im Verzeichnis ausführen:

bash
python3 qrcode_create.py

Im Arbeitsverzeichnis wird im figure-Ordner ein zweidimensionaler Code (QR-Code) mit festgelegtem Logo erzeugt. Auch der Speicherort des voreingestellten Logobilds befindet sich im figure-Ordner. Das Ergebnis des erzeugten 2D-Codes sieht wie folgt aus:

Der Quellcode von qrcode create.py lautet wie folgt:

Code-Datei: 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)

Die Bedeutung der Parameter für die QR-Code-Erstellung ist wie folgt:

Code-Datei: 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.
    '''

Nach dem Erzeugen eines zweidimensionalen Codes können Sie diesen ausdrucken (A4-Format genügt), um den 2D-Erkennungstest durchzuführen.

Der Codeabschnitt für die Erkennungsfunktion lautet wie folgt:

Code-Datei: 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

Starten Sie im Verzeichnis der QR-Code-Erkennung die Erkennung des zweidimensionalen Codes:

python
qrcode_parsing_usb.py

Die Testergebnisse sind unten dargestellt; nach der Erkennung des 2D-Codes wird ein Testrahmen gezeichnet.

Abbildungen

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

Menschliche Posenschätzung

Einführung

Die menschliche Posenschätzung ist eine computerbasierte Bildverarbeitungstechnik, die darauf abzielt, die Positionen der wichtigsten menschlichen Gelenke anhand von Bildern oder Videos automatisch zu erkennen, zu lokalisieren und die Skelettstruktur des menschlichen Körpers zu modellieren. Human Pose Estimation wird breit in den Bereichen Aktionserkennung, intelligente Überwachung, Mensch-Maschine-Interaktion, Bewegungsanalyse, Rehabilitation und virtuelle Realität eingesetzt und ist eine Schlüsseltechnologie, um „den menschlichen Körper zu sehen“ mit „menschliches Verhalten zu verstehen“ zu verbinden.

II. Funktionsprinzip

Zunächst werden die eingegebenen menschlichen Bilder an ein faltendes neuronales Netzwerk (CNN) zur Merkmalsextraktion gesendet, wodurch hochstufige semantische Merkmale entstehen. Die Netzwerkstruktur wird anschließend in zwei Zweige aufgeteilt: einen zur Vorhersage der Part Confidence Maps (Konfidenzkarten der Schlüsselpunkte), die die Wahrscheinlichkeitsverteilung der Positionen einzelner menschlicher Gelenke im Raum zeigen, und einen zur Vorhersage der Part Affinity Fields (PAFs, körperbezogene Assoziationsfelder), die Verbindungen und Richtungsinformationen zwischen verschiedenen Gelenken in Vektorform beschreiben. Auf Basis der Konfidenzkarte, die die Kandidatenpunkte erkennt, und unter Nutzung der von PAF bereitgestellten Richtungskonsistenzinformationen wird die Verbindung zwischen den Punkten als Bipartite-Matching-Problem im Diagramm modelliert, indem die zur selben Person gehörenden Gelenkpunkte korrekt zugeordnet werden und schrittweise das vollständige menschliche Skelett aufgebaut wird. Darüber hinaus lässt sich die Schätzung mehrerer Personenposen als Multi-Person-Parsing-Problem betrachten, das mehrpunktige Verbindungen in ein Graph-Matching-Problem überführt und mit klassischen zweidimensionalen Matching-Verfahren wie dem Ungarischen Algorithmus die beste Kombination von Gelenkpunkten findet, um eine genaue und stabile Schätzung mehrerer menschlicher Posen zu erreichen.

Beginn des Verfahrens

Zugriff auf ROS 1 Docker-Images

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

Installationsabhängigkeit

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__)"

Verwendung von Bildern zur Inferenz

Wechseln Sie in das Code-Dateiverzeichnis und führen Sie das Code-Skript aus

bash
cd sources_code/ROS 1
python3 target_pose_img.py

Verwendung von Videobildern zur Inferenz

Code-Skript ausführen

bash
undefined

Abbildungen

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

Objekterkennung

Im Deep Learning ist die Objekterkennung (Target Detection) eine der Kernaufgaben der maschinellen Bildverarbeitung und dient dazu, alle interessierenden Objekte im Bild zu identifizieren und zu markieren. Gängige Verfahren lassen sich in zwei Hauptkategorien einteilen:

Zweistufige Erkennung: Repräsentative Verfahren sind R-CNN, Fast R-CNN und Faster R-CNN. Dabei werden zunächst Region Proposals erzeugt, anschließend wird jeder Kandidatenbereich klassifiziert und die Begrenzung zurückgemeldet. Diese Verfahren sind sehr genau, jedoch relativ langsam und eignen sich für Szenarien, die hohe Genauigkeit erfordern.

Einstufige Erkennung: Repräsentative Verfahren sind YOLO (You Only Look Once) und SSD (Single Shot MultiBox Detector). Objektklassen und Begrenzungsrahmen werden direkt auf den Feature Maps vorhergesagt, ohne dass Kandidatenbereiche erzeugt werden müssen, was eine hohe Geschwindigkeit ermöglicht, die sich für Echtzeiterkennung eignet, wobei die Genauigkeit früherer Varianten etwas geringer ist als bei zweistufigen Verfahren.

In diesem Abschnitt wird gezeigt, wie sich mit dem dnn-Modul von OpenCV die Objekterkennung realisieren lässt

Programm starten

Inferenz mit Bildern

Wechseln Sie in das Code-Verzeichnis und führen Sie das Skript aus

bash
cd sources_code/ROS 1
python3 target_detect_img.py

Logische Kameras

Wechseln Sie in das Code-Verzeichnis und führen Sie das Skript aus

bash
cd sources_code/ROS 1
python3 target_detect_video.py

7.2.2.6 AR Vision

AR-Vision

Augmented Reality (AR) bezeichnet den Einsatz computerbasierter Bildverarbeitungstechnik, um virtuelle Informationen oder dreidimensionale Modelle in Echtzeit in Bilder oder Videos der realen Welt einzublenden und so die Wahrnehmung und Interaktionserfahrung der Nutzer mit ihrer Umgebung zu verbessern. Durch die Videoerfassung realer Szenen in Kombination mit Technologien wie Objekterkennung, Merkmalspunkt-Tracking und Tiefenschätzung wird die räumliche Ausrichtung und Echtzeitinteraktion zwischen virtuellen Objekten und der realen Welt erreicht. AR wird breit in Bereichen wie Unterhaltung, Industriedesign, Aus- und Weiterbildung sowie Navigation eingesetzt.

In ROS 1 Docker-Image einsteigen

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

Kamera kalibriert.

ROS stellt offiziell ein Kamerakalibrierungspaket bereit, mit dem sich USB-Kameras einfach kalibrieren lassen:

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

USB-Kamera-Node starten

bash
roslaunch usb_cam usb_cam-test.launch

Vorbereitung der Tafeln

Tafeln im A4-Format herunterladen und ausdrucken

Kalibrierungs-Node starten

Öffnen Sie ein weiteres Terminal im Docker-Image für ROS 1 und führen Sie den Kalibrierungs-Node aus

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

Parameterbeschreibung:

--size 8x6: Anzahl der inneren Ecken (Spalte x Zeile) (8x6 = 48 Ecken eines 9x7-Gitters)

--square 0.025: Kantenlänge jedes Quadrats, Einheit m (24 mm)

Bild-Topic

camera:=/usb_cam: Kamera-Namespace

Kalibrierungsoberfläche

X: Links-rechts-Bewegung des Schachbretts im Kamerabild

Y: Auf- und Abbewegung des Schachbretts im Kamerabild

Size: Vor- und Zurückbewegung des Boards im Kamerabild

Skew: Neigung des Schachbretts im Kamerabild

Nach erfolgreichem Start wird das Board mittig im Bild platziert und in verschiedene Positionen bewegt. Das System erkennt dies selbstständig; im Idealfall sollten die Balken unter X, Y, Size und Skew durch die Datenerfassung möglichst vollständig von Rot bis Gelb gefüllt sein.

Klicken Sie auf Calibrate, um die internen Kameraparameter zu berechnen. Die Oberfläche zeigt dabei möglicherweise keine Reaktion, das Terminal liefert jedoch weiterhin Ausgaben — bitte warten!

Nach erfolgreicher Berechnung zeigt das Terminal die Kameraparameter an; klicken Sie auf SAVE, um die Kameraparameter zu speichern.

Das Ergebnis wird standardmäßig unter /tmp/calibrationdata.tar.gz gespeichert

Entpacken Sie es und verschieben Sie die Datei tag parameters.yaml in das Skript-Code-Verzeichnis

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

Skript ausführen

Führen Sie das AR-Skript im ROS 1 Docker-Container aus:

bash
python3 simple_AR.py

Code-Datei: 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()

Abbildungen

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

OpenCV-Anwendung

Opencv apps ist eine von der ROS-Community gepflegte Sammlung von Funktionspaketen, die eine große Zahl an OpenCV-Bildverarbeitungs- und Bildverarbeitungsfunktionen in ROS-Nodes kapselt, sodass sich die Eingabe eines Standard-Topics direkt im ROS-System aufrufen lässt, ohne dass eigener OpenCV-Code geschrieben werden muss.

Opencv apps starten

Docker starten

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

Kamera aktivieren

bash
roslaunch usb_cam usb_cam-test.launch

Opencv apps verwenden

Es kann jeweils nur eine Funktion ausgeführt werden. Der Befehl muss ausgeführt werden, nachdem die Kamera aktiviert wurde:

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

Vorschau

Aktivieren Sie die Kamera und aktivieren Sie eine der Opencv apps-Funktionen, um das Bild wie folgt anzuzeigen.

Lokaler Zugriff

Geben Sie den folgenden Befehl ein und wählen Sie das entsprechende Topic, um das Ergebnis zu sehen:

rqt image view

Ansicht im LAN

Geben Sie im selben lokalen Netzwerk IP:Port (8080) in den Browser ein, zum Beispiel:

192.168.7.47:8080 # IP bezieht sich auf die Host-IP

Referenzen

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

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

Der Großteil des Codes stammt ursprünglich aus https://github.com/Itseez/opencv/tree/master/samples/cpp.

7.2.2.8 ROS + OpenCV Fundamentals

Funktionsübersicht

ROS bringt OpenCV (3.x und höher) bereits bei der Installation mit, und Bilder werden in ROS im Nachrichtenformat sensor msgs/Image übertragen und können nicht direkt mit OpenCV verarbeitet werden. Dafür stellt ROS cv bridge bereit für:

Eine effiziente Konvertierung zwischen ROS Image ↔ OpenCV Mat (numpy array) — die zentrale Brücke der ROS-Bildverarbeitung.

Konfiguration der Funktionspaketabhängigkeiten

package.xml

Code-Datei: 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 (minimierter Python-Node)

Code-Datei: 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}
)

USB-Kamera-Node starten

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

Farbbild-Subscriber-Node (vollständiger Code)

Dateiname: usb_cam_image.py

Code-Datei: 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()

Ausführungsrechte vergeben

bash
chmod +x usb_cam_image.py
cd /ros_ws
catkin_make

Beispiel ausführen

Multi-Terminal-Tool installieren

bash
apt-get install terminator
# Run
terminator

Öffnen Sie mit der Tastenkombination ctrl + Shift + o im aufgehenden Terminalfenster ein weiteres Terminal horizontal

Terminal 1: Kamera starten.

Roslaunch usb cam usb cam-test.launch

Terminal 2: Subscriber-Node ausführen

rosrun ros opencv demo usb_cam_image.py

Sie sehen ein OpenCV-Fenster, das die USB-Kamera in Echtzeit anzeigt.

Node-Kommunikation ansehen

Starten Sie einen weiteren Terminalvorgang:

bash
rqt_graph

Abbildungen

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

MediaPipe-Einführung

MediaPipe ist ein leistungsstarkes, plattformübergreifendes Open-Source-Framework von Google zur Sensor-Berechnung, das für den Aufbau von Echtzeit-Bildverarbeitungs- und multimodalen Verarbeitungspipelines entwickelt wurde. Es wird umfassend für Aufgaben wie menschliche Posenschätzung, Handerkennung, Gesichtserkennung und Schlüsselpunkt-Tracking eingesetzt, indem es mittels grafischer Berechnung (Graph) die Module für Kameraeingabe, Modellinferenz und Nachbearbeitung effizient miteinander verknüpft. MediaPipe integriert eine Vielzahl leichtgewichtiger, quantisierter Deep-Learning-Modelle, die Echtzeitinferenz auf der CPU unterstützen und sehr gut für eingebettete Plattformen (z. B. Jetson, mobile Geräte) geeignet sind — Entwickler können mit wenig Code schnell stabile, latenzarme Echtzeit-Wahrnehmungsanwendungen realisieren.

Deep-Learning-Lösungen in MediaPipe

Klicken Sie auf ein Bild, um die vollständige Übersichtstabelle anzuzeigen

Docker starten

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

Anwendungsfall

Handtest

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

Gesichtsprüfung.

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

Gesichtseffekte.

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

3D-Objekterkennung

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

Pinsel

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

Gestenerkennung.

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

Fingersteuerung.

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

Posenschätzung

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

Gesichtstest

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

Gesamttest

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

Fallsegmentierung

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

Abbildungen

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