Aplicaciones de Visión de ROS 1 Noetic

Este capítulo cubre flujos de trabajo prácticos de visión con ROS 1 en reComputer Jetson, incluyendo vista previa de cámara, reconocimiento de códigos QR, estimación de pose, detección de objetos, marcadores AR, OpenCV y ejemplos de MediaPipe.

Los ejemplos largos y ejecutables se guardan en ./code/, y las figuras relacionadas se guardan en ./images/.

Contenido

7.2.2.1 Lea esto primero

Todo depende del uso.

¡El entorno de ROS 1 está en la imagen Docker y necesita una base Docker para funcionar por completo!

Nota: ¡las imágenes Docker solo pueden ejecutar los casos visuales que usan cámaras USB!

Entrar en Docker.

Abra una terminal e introduzca el siguiente comando en la imagen 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

Figuras

7.2.2.1 Read This First figure 1

7.2.2.2 Vista previa de la cámara

Vista previa de la cámara

Entrar en la imagen 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

Ver los parámetros admitidos por las cámaras

Introduzca el siguiente comando para ver el nombre del dispositivo del mapa de la cámara USB:

bash
ls /dev/video*

Consulte el formato de flujo, los fotogramas y la resolución de las cámaras USB admitidas según los números de índice del dispositivo correspondientes (0 a 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

Imagen de vista previa de la cámara -- comando de terminal

Las terminales pueden abrir cámaras USB con ffplay

bash
ffplay -f v4l2 -i /dev/video0

Vista previa de la cámara - script de Python

Ejecute las cámaras USB locales para probar los scripts:

bash
 cd source_code/ROS 1/
 python3 CameraPreview.py

El script recorrerá las cámaras USB disponibles para mostrar e imprimir las tasas de fotogramas

El código fuente de CameraPreview.py es el siguiente:

Archivo de código: 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()

Figuras

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 Códigos QR

Introducción al código QR 1

El código QR es uno de los códigos de barras bidimensionales, y QR proviene del acrónimo en inglés "Quick Response", que significa respuesta rápida, y surge de la esperanza de su inventor de que el código QR pudiera decodificarse rápidamente. El código QR no solo tiene una gran capacidad de información, fiabilidad y coste, sino que también permite que múltiple información textual, como caracteres chinos e imágenes, sea confidencial y difícil de falsificar, y a la vez fácil de usar. Más importante aún, la tecnología del código QR es de código abierto.

Introducción al código QR

Características del código QR

Los valores de datos del código QR contienen información duplicada (valores de redundancia). De este modo, incluso si se destruye hasta un 30 % de la estructura del código bidimensional, no se afecta la legibilidad del código bidimensional. El espacio de almacenamiento del código QR es de hasta 7089 bits o 4296 caracteres, incluyendo puntuación y caracteres especiales, todos escritos en el código QR. Además de números y caracteres, es posible codificar palabras y frases (como direcciones web). La estructura del código se vuelve más compleja a medida que se añaden más datos al código QR y aumenta el tamaño del código.

Creación y reconocimiento del código QR 2D

Dependencia de instalación:

Archivo de código: 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

Crea un objeto qrcode, con el que se puede ejecutar directamente el script qr code create.py en el directorio:

bash
python3 qrcode_create.py

Se genera un código bidimensional (código QR) con un logotipo configurado en la carpeta de figuras dentro del directorio de trabajo. La ubicación de la imagen del logotipo preestablecido también está en la carpeta de figuras. El efecto del código 2D generado es el siguiente:

El código fuente de qrcode create.py es el siguiente:

Archivo de código: 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)

Los parámetros para crear el código QR significan lo siguiente:

Archivo de código: 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.
    '''

Al generar un código bidimensional, puede imprimirlo (basta con tamaño A4) para la prueba de reconocimiento bidimensional.

Los segmentos de código de la función de reconocimiento son los siguientes:

Archivo de código: 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

En el directorio de reconocimiento de código qr, inicie la detección del código bidimensional:

python
qrcode_parsing_usb.py

Los resultados de las pruebas se ilustran a continuación, y se dibuja un recuadro de prueba tras identificar el código 2D.

Figuras

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 Estimación de pose humana

Estimación de pose humana

Introducción

La evaluación de la postura humana es una tecnología de visión basada en computadora diseñada para identificar y localizar automáticamente la ubicación de las articulaciones clave del cuerpo humano a través de imágenes o videos, y para modelar la estructura ósea del cuerpo humano. La estimación de pose humana, ampliamente aplicada en las áreas de identificación de acciones, vigilancia inteligente, interacción humana, análisis de movimiento, rehabilitación y realidad virtual, son tecnologías clave para conectar "ver el cuerpo humano" y "comprender el comportamiento humano".

II. Fundamentos

Primero, las imágenes humanas ingresadas se envían a la red neuronal convolucional (CNN) para su caracterización, con perfiles semánticos de alto nivel; Luego la estructura de la red se dividió en dos ramas, una para predecir los Mapas de Confianza de Partes (Part Confidence Maps, gráfico de confianza de puntos clave), para mostrar la distribución de probabilidad de posiciones en el espacio para articulaciones humanas individuales, y la otra para predecir los Campos de Afinidad de Partes (Part Affinity Fields, PAFs, campos de asociación corporal), para describir los enlaces e información direccional entre diferentes articulaciones en forma vectorial. A partir del mapa de confianza, que detecta el nodo candidato, y utilizando la información de consistencia direccional proporcionada por PAF, se modela la conexión entre los nodos como el problema de emparejamiento bipartito (Matching) en el diagrama, emparejando correctamente los nodos articulares que pertenecen a la misma persona y construyendo gradualmente el esqueleto humano completo. Además, se estima que las poses de múltiples personas pueden considerarse como un problema de Multi-Person Parsing, que traduce las conexiones de múltiples puntos en problemas de emparejamiento gráfico, y utiliza el método clásico de emparejamiento bidimensional, como el Algoritmo Húngaro, para encontrar la mejor combinación de nodos articulares y así lograr estimaciones precisas y estables de las poses de múltiples personas.

Inicio del procedimiento

Acceso a las imágenes 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

Dependencia de instalación

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

Uso de imágenes para inferencia

Ingrese al directorio del archivo de código, ejecute el script de código

bash
cd sources_code/ROS 1
python3 target_pose_img.py

Uso de imágenes de video para inferencia

Ejecute el script de código

bash
undefined

Figuras

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 Detección de objetos

Detección de objetos

En el aprendizaje profundo, la Detección de Objetivos (Target Detection) es una de las tareas centrales de la visualización por computadora y está diseñada para identificar y marcar todos los objetos de interés en la imagen. Los métodos comunes se dividen en dos categorías principales:

Detección en dos etapas: El método de representación es R-CNN, Fast R-CNN, Fast R-CNN. Sr. Region Proposals, luego clasifica y devuelve cada área candidata. Estos métodos son muy precisos, pero relativamente lentos y adecuados para escenarios que requieren alta precisión.

Detección en una etapa: El método de representación es YOLO (You Only Look Once), SSD (Single Shot MultiBox Detector). Las categorías de objetos y los cuadros delimitadores se proyectan directamente sobre los mapas de características sin necesidad de generar áreas candidatas, a un ritmo rápido adecuado para la detección en tiempo real, pero con una precisión inicial ligeramente inferior a las dos etapas.

Este apartado demostrará cómo usar el módulo dnn de OpenCV para lograr la prueba de objetivos

Iniciar programa

Imágenes de inferencia

Ingrese al directorio de código, ejecute los scripts

bash
cd sources_code/ROS 1
python3 target_detect_img.py

Cámaras lógicas

Ingrese al directorio de código, ejecute los scripts

bash
cd sources_code/ROS 1
python3 target_detect_video.py

7.2.2.6 Visión AR

Visión AR

La realidad aumentada (AR, Augmented Reality) se refiere al uso de tecnología de visión basada en computadora para superponer información virtual o modelos tridimensionales en tiempo real sobre imágenes o videos del mundo real, mejorando así la percepción y experiencia interactiva del usuario con el entorno. Logra la alineación espacial y la interacción en tiempo real entre objetos virtuales y el mundo real mediante la captura de video de escenarios de la vida real, combinada con tecnologías como la detección de objetivos, el seguimiento de puntos característicos y la estimación de profundidad, y se usa ampliamente en áreas como el ocio y el entretenimiento, el diseño industrial, la formación educativa y la navegación.

Entrar en la imagen 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

Calibración de la cámara.

ROS ofrece oficialmente un paquete de calibración de cámara para calibrar fácilmente cámaras USB:

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

Iniciar los nodos de la cámara USB

bash
roslaunch usb_cam usb_cam-test.launch

Preparación de los tableros

Descargue e imprima tableros de tamaño A4

Iniciar los nodos de calibración

Abra otra terminal para entrar en la imagen docker de ROS 1, ejecute los nodos de calibración

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

Descripción de parámetros:

--size 8x6: número de esquinas internas (columna x fila) (8x6 = 48 esquinas de una cuadrícula de 9x7)

--square 0.025: longitud de cada cuadrado, unidad m (24mm)

Tema de imagen

Camera: =/usb_cam: espacio de nombres de la cámara

Interfaz de calibración

X: movimiento del tablero de ajedrez a izquierda y derecha en la vista de la cámara

Y: movimiento del tablero de ajedrez hacia arriba y abajo en la vista de la cámara

Size: movimiento hacia adelante y atrás del tablero en la vista de la cámara

Skew: inclinación del tablero de ajedrez en la vista de la cámara

Tras un inicio exitoso, el tablero se coloca en el centro de la imagen, cambiando de posición. El sistema se autoidentificará; lo ideal es que las líneas de X, Y, Size, Skew se llenen lo máximo posible con la recopilación de datos, pasando de rojo a amarillo.

Haga clic en Calibrate para calcular los parámetros internos de la cámara; puede que la interfaz no muestre respuesta, pero la terminal seguirá mostrando salida, ¡espere!

Tras un cálculo exitoso, la terminal muestra los parámetros de la cámara; haga clic en SAVE para guardar los parámetros de la cámara.

El resultado se almacenará por defecto en /tmp/calibrationdata.tar.gz

Descomprímalo y mueva el archivo yaml de parámetros de calibración al directorio de código del script

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

Ejecutar script

Ejecute el script AR dentro del contenedor Docker de ROS 1:

bash
python3 simple_AR.py

Archivo de código: 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()

Figuras

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 Aplicaciones de OpenCV

Aplicación de OpenCV

Opencv apps es un conjunto de paquetes de funcionalidad mantenido por la comunidad ROS, que encapsula una gran cantidad de procesamiento de imágenes de OpenCV y visualizaciones por computadora en nodos ROS, permitiendo que la entrada de un tema estándar se invoque directamente en el sistema ROS, sin tener que preparar el propio código de OpenCV.

Iniciar Opencv apps

Iniciar 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

Instalación

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

Activar la cámara

bash
roslaunch usb_cam usb_cam-test.launch

Usar Opencv apps

Solo se puede ejecutar una función a la vez. El comando debe ejecutarse después de activar la cámara:

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

Vista previa

Active la cámara y active una de las funciones de Opencv apps para ver la imagen de la siguiente manera.

Acceso local

Introduzca el siguiente comando y seleccione el tema correspondiente para ver el efecto:

rqt image view

Visualización en LAN

En la misma red de área local, introduzca IP:puerto (8080) en el navegador, por ejemplo:

192.168.7.47:8080 # IP se refiere a la IP del host

Referencias

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

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

La mayor parte del código se tomó originalmente de https://github.com/Itseez/opencv/tree/master/samples/cpp.

7.2.2.8 Fundamentos de ROS + OpenCV

Descripción general de la función

ROS ya integra OpenCV (3.x y superior) durante la instalación, y las imágenes se transmiten en ROS en formato de mensaje sensor msgs/Image y no se pueden procesar directamente con OpenCV. Para ello, ROS proporciona cv bridge para:

Una conversión eficiente entre ROS Image ↔ OpenCV Mat (arreglo numpy) es el puente central para el procesamiento de imágenes en ROS.

Configuración de dependencias del paquete funcional

package.xml

Archivo de código: 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 (nodo Python minimizado)

Archivo de código: 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}
)

Iniciar el nodo de la cámara USB

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

Nodo de suscripción de imagen a color (código completo)

Nombre de archivo: usb_cam_image.py

Archivo de código: 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()

Otorgar permisos de ejecución

bash
chmod +x usb_cam_image.py
cd /ros_ws
catkin_make

Ejecutar ejemplo

Instale la herramienta multiterminal

bash
apt-get install terminator
# Run
terminator

Abra otra terminal horizontalmente usando el atajo ctrl + Shift + o en la interfaz de terminal emergente

Terminal 1: Iniciar la cámara.

Roslaunch usb cam usb cam-test.launch

Terminal 2: Ejecutar el nodo de suscripción

rosrun ros opencv demo usb_cam_image.py

Verá una ventana de OpenCV mostrando cámaras USB en tiempo real.

Ver comunicaciones de nodos

Inicie otra operación de terminal:

bash
rqt_graph

Figuras

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 Desarrollo con MediaPipe

Introducción a MediaPipe

MediaPipe es un marco de cálculo de sensores multiplataforma de alto rendimiento de código abierto de Google, dedicado a la construcción de líneas de procesamiento en tiempo real de visión y multimodales. Se usa extensamente para tareas como la estimación de la postura humana, el reconocimiento de manos, la detección de rostros y el seguimiento de puntos clave, mediante un cálculo gráfico (Graph) que vincula eficientemente los módulos de entrada de cámara, inferencia de modelos y reprocesamiento. MediaPipe incorpora una variedad de modelos de aprendizaje profundo ligeros y cuantitativos que admiten inferencia en tiempo real en CPU y son muy amigables con plataformas embebidas (por ejemplo, Jetson, móviles), y los desarrolladores pueden lograr rápidamente aplicaciones sensoriales en tiempo real estables y de baja latencia con poco código.

Soluciones de aprendizaje profundo en MediaPipe

Haga clic en una imagen para ver la hoja de cálculo completa

Iniciar 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

Casos de uso

Prueba de manos

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

Verificación facial.

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

Efectos faciales.

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

Identificación de objetos D

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

Pincel

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

Reconocimiento de gestos.

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

Control por dedos.

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

Estimación de postura

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

Prueba facial

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

Prueba integral

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

Segmentación de casos

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

Figuras

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