Caso práctico: clasificador de reciclables con TensorRT en

Caso práctico: clasificador de reciclables con TensorRT en — hero

Objetivo y caso de uso

Qué construirás: un clasificador en tiempo real “tensorrt-recyclables-classifier” que usa la cámara CSI Arducam IMX219 (imx219) en un Jetson Nano 4GB, preprocesa con OpenCV y ejecuta MobileNetV2 en TensorRT FP16 para mostrar clase (plástico, metal, vidrio, papel/cartón, no reconocido), probabilidad y FPS.

Para qué sirve

  • Clasificación inicial de residuos en línea de separación (p. ej., distinguir plástico vs. metal).
  • Prototipo de “smart bin” que sugiere el contenedor correcto en tiempo real.
  • Monitorizar cinta y registrar conteos por material para auditorías.
  • Alertar si aparece un material no esperado (p. ej., vidrio en contenedor de papel).
  • Base didáctica para adaptar a dataset propio y calibración INT8.

Resultado esperado

  • Latencia de inferencia FP16 (MobileNetV2, TensorRT): 10–25 ms por fotograma.
  • FPS en pantalla: 25–30 FPS con IMX219 (720p@30); inferencia pura: 40–100 FPS.
  • Uso de GPU: 45–70% y CPU: 20–35% en modo 10W; temperatura estable bajo carga.
  • Overlay con etiqueta y probabilidad (p. ej., “plástico 0.87”) sincronizado con los FPS.
  • Criterio de éxito: procesamiento estable >30 min sin caídas y latencia total captura→overlay <100 ms.

Público objetivo: makers, estudiantes e ingenieros de visión/embebidos; Nivel: intermedio.

Arquitectura/flujo: Cámara IMX219 → captura OpenCV → preprocesado (resize 224×224, normalización) → inferencia TensorRT FP16 (modelo ONNX MobileNetV2) → softmax y mapeo de clase → overlay con FPS/probabilidad → display y registro.

Prerrequisitos (SO, toolchain exacta y versiones)

  • Dispositivo: NVIDIA Jetson Nano 4GB
  • Cámara: Arducam IMX219 8MP (imx219) CSI-2
  • Sistema operativo/SDK:
  • JetPack 4.6.4 (L4T R32.7.4) basado en Ubuntu 18.04.6 LTS
  • CUDA 10.2
  • cuDNN 8.2.1
  • TensorRT 8.2.1.8 (incluye trtexec en /usr/src/tensorrt/bin/trtexec)
  • OpenCV 4.1.1 (proveído por JetPack 4.6.x)
  • GStreamer 1.14.5
  • Python 3.6.9

Verificar las versiones (ejecute todas las líneas):

# L4T / JetPack
cat /etc/nv_tegra_release
# Kernel
uname -a
# Paquetes NVIDIA y TensorRT
dpkg -l | grep -E 'nvidia|tensorrt'
# CUDA
nvcc --version || cat /usr/local/cuda/version.txt
# OpenCV (Python)
python3 - << 'PY'
import cv2, sys
print("Python:", sys.version.split()[0])
print("OpenCV:", cv2.__version__)
PY
# GStreamer
gst-launch-1.0 --version

Notas:
– Jetson Nano 4GB no soporta JetPack 5.x. Use JetPack 4.6.4 para coherencia.
– Si falta trtexec, revise que tenga instalado el paquete nvinfer y/o reinstale el componente TensorRT del JetPack.

Materiales

  • 1× Jetson Nano 4GB Developer Kit (tarjeta + disipador)
  • 1× Arducam IMX219 8MP (imx219) cámara CSI-2 para Jetson
  • 1× Tarjeta microSD 64 GB (UHS-I, clase A1/A2 recomendada)
  • 1× Fuente 5V/4A tipo barrel jack o 5V/3A por micro-USB (se recomienda 5V/4A para estabilidad)
  • 1× Cable flexible CSI (incluido con la cámara)
  • 1× Disipador/ventilador para Jetson Nano (recomendado)
  • 1× Monitor HDMI/teclado/ratón (opcional si no es headless)
  • Conectividad de red (Ethernet o Wi-Fi)

Importante: el modelo de cámara es exactamente Arducam IMX219 8MP (imx219), compatible con nvarguscamerasrc.

Preparación y conexión

Conexión física de la cámara CSI

  • Apague y desconecte la Jetson Nano de la energía.
  • Localice el puerto CSI-2 de la Jetson Nano (conector plano etiquetado “CAMERA”).
  • Oriente el cable CSI con los contactos hacia el lado correcto (habitualmente hacia el conector).
  • Inserte con cuidado y cierre la pestaña del conector para fijar el cable.
  • Monte la cámara Arducam IMX219 (imx219) con el cable, evitando torsiones.

Tabla de referencia rápida:

Componente Puerto/Conector en Nano Detalle de conexión/Orientación
Arducam IMX219 8MP (imx219) CSI-2 (CAMERA) Cable CSI con contactos hacia el conector, cierre la pestaña
Alimentación Barrel jack 5V/4A o uUSB Preferible barrel 5V/4A. Evite hubs USB alimentando el Nano
Monitor (opcional) HDMI Conectar antes de encender
Teclado/ratón (opcional) USB Cualquier puerto USB-A
Red Ethernet RJ-45 DHCP típico

Comprobación básica de la cámara con GStreamer

Tras encender y arrancar la Nano con JetPack 4.6.4:

# Prueba rápida de la cámara (CSI IMX219) con GStreamer
gst-launch-1.0 nvarguscamerasrc sensor-id=0 ! \
'video/x-raw(memory:NVMM),width=1280,height=720,framerate=30/1,format=NV12' ! \
nvvidconv ! 'video/x-raw,format=I420' ! fpsdisplaysink video-sink=fakesink text-overlay=true sync=false -e

Debería ver en consola el conteo de FPS sin errores. Si hay error de nvargus-daemon, consulte la sección de troubleshooting.

Ajuste de modo de potencia y clocks (opcional pero recomendado)

Para estabilidad de rendimiento (monitoree termales):

sudo nvpmodel -q
# MAXN para Jetson Nano 4GB
sudo nvpmodel -m 0
sudo jetson_clocks

Advertencia: MAXN aumenta consumo y temperatura. Use disipador/ventilador.

Código completo (Python + TensorRT) con explicación

A continuación, un script único en Python que:
– Carga un motor TensorRT (.engine) de MobileNetV2 FP16.
– Abre la cámara CSI a través de OpenCV utilizando un pipeline GStreamer.
– Preprocesa a 224×224, normaliza (ImageNet) y ejecuta inferencia en GPU.
– Agrega las probabilidades de las clases ImageNet a categorías de reciclaje por palabras clave y muestra FPS.

Guarde como: $HOME/tensorrt-recyclables-classifier/tensorrt_recyclables.py

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import os
import time
import ctypes
import numpy as np
import cv2

import tensorrt as trt
import pycuda.driver as cuda
import pycuda.autoinit  # inicializa contextos CUDA

# Configuración de rutas
BASE_DIR = os.path.expanduser("~/tensorrt-recyclables-classifier")
ENGINE_PATH = os.path.join(BASE_DIR, "mobilenetv2_fp16.engine")
LABELS_PATH = os.path.join(BASE_DIR, "imagenet_labels.txt")

# Parámetros del modelo
INPUT_W = 224
INPUT_H = 224
INPUT_NAME = "data"  # para mobilenetv2-7.onnx del ONNX Model Zoo
NUM_CLASSES = 1000   # ImageNet

# Normalización ImageNet
IMAGENET_MEAN = np.array([0.485, 0.456, 0.406], dtype=np.float32)
IMAGENET_STD  = np.array([0.229, 0.224, 0.225], dtype=np.float32)

# Mapeo simple por palabras clave a categorías de reciclaje
CATEGORY_KEYWORDS = {
    "plastico": ["plastic", "bottle", "pop bottle", "water bottle", "soda bottle"],
    "metal": ["can", "tin", "aluminum"],
    "vidrio": ["glass", "goblet", "wine bottle", "beer bottle", "jar"],
    "papel_carton": ["paper", "newspaper", "tissue", "napkin", "carton", "cardboard"],
    # si no coincide en ninguna, caerá en "no_reconocido"
}

def build_gst_pipeline(width=1280, height=720, fps=30, sensor_id=0):
    return (
        f"nvarguscamerasrc sensor-id={sensor_id} ! "
        f"video/x-raw(memory:NVMM), width={width}, height={height}, framerate={fps}/1, format=NV12 ! "
        "nvvidconv ! video/x-raw, format=BGRx ! "
        "videoconvert ! video/x-raw, format=BGR ! appsink drop=true sync=false"
    )

def load_labels(path):
    labels = []
    with open(path, "r") as f:
        for line in f:
            line = line.strip()
            if line:
                # synset_words.txt suele tener "nXXXX class_name..."
                parts = line.split(" ", 1)
                label = parts[1] if len(parts) > 1 else parts[0]
                labels.append(label)
    return labels

def preprocess_bgr(frame_bgr):
    # Convertir a RGB, redimensionar, normalizar y dejar en NCHW float32
    img = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
    img = cv2.resize(img, (INPUT_W, INPUT_H), interpolation=cv2.INTER_LINEAR)
    img = img.astype(np.float32) / 255.0
    img = (img - IMAGENET_MEAN) / IMAGENET_STD
    img = img.transpose(2, 0, 1)  # HWC -> CHW
    img = np.expand_dims(img, axis=0).copy()  # NCHW
    return img

def softmax(x):
    x = x - np.max(x, axis=1, keepdims=True)
    exp_x = np.exp(x)
    return exp_x / np.sum(exp_x, axis=1, keepdims=True)

def aggregate_to_recyclables(probs, labels, topk=5):
    # Toma los top-k, mapea por keywords a la categoría y suma probabilidades
    topk_idx = probs.argsort()[::-1][:topk]
    category_scores = {k:0.0 for k in list(CATEGORY_KEYWORDS.keys()) + ["no_reconocido"]}
    matched = False

    for idx in topk_idx:
        label = labels[idx].lower()
        p = probs[idx]
        hit = False
        for cat, keywords in CATEGORY_KEYWORDS.items():
            if any(kw in label for kw in keywords):
                category_scores[cat] += float(p)
                hit = True
                matched = True
        if not hit:
            category_scores["no_reconocido"] += float(p)

    # Si ninguna keyword coincide, clasificar como no reconocido con mayor peso top-1
    if not matched:
        category_scores["no_reconocido"] += 0.1

    # Selección de categoría con mayor score
    best_cat = max(category_scores, key=category_scores.get)
    best_score = category_scores[best_cat]
    return best_cat, best_score, category_scores, topk_idx

class TRTInference:
    def __init__(self, engine_path):
        self.logger = trt.Logger(trt.Logger.INFO)
        trt.init_libnvinfer_plugins(self.logger, "")
        with open(engine_path, "rb") as f, trt.Runtime(self.logger) as runtime:
            self.engine = runtime.deserialize_cuda_engine(f.read())
        assert self.engine, "No se pudo deserializar el engine TRT"
        self.context = self.engine.create_execution_context()
        assert self.context, "No se pudo crear el contexto TRT"

        # Ubicar índices de binding
        self.input_binding_idx = self.engine.get_binding_index(INPUT_NAME)
        assert self.input_binding_idx != -1, f"Binding de entrada '{INPUT_NAME}' no encontrado"
        # Se asume única salida (clases)
        self.output_binding_idx = 1 - self.input_binding_idx

        # Reservar memoria en host y device
        self.input_shape = self.engine.get_binding_shape(self.input_binding_idx)
        self.output_shape = self.engine.get_binding_shape(self.output_binding_idx)

        self.host_input = cuda.pagelocked_empty(trt.volume(self.input_shape), dtype=np.float32)
        self.host_output = cuda.pagelocked_empty(trt.volume(self.output_shape), dtype=np.float32)

        self.device_input = cuda.mem_alloc(self.host_input.nbytes)
        self.device_output = cuda.mem_alloc(self.host_output.nbytes)

        self.bindings = [int(self.device_input), int(self.device_output)]

        # Stream CUDA
        self.stream = cuda.Stream()

    def infer(self, input_nchw):
        # Copiar a host_input
        np.copyto(self.host_input, input_nchw.ravel())

        # H2D
        cuda.memcpy_htod_async(self.device_input, self.host_input, self.stream)
        # Ejecutar
        self.context.execute_async_v2(self.bindings, self.stream.handle)
        # D2H
        cuda.memcpy_dtoh_async(self.host_output, self.device_output, self.stream)
        # Sincronizar
        self.stream.synchronize()

        output = np.array(self.host_output).reshape(1, -1)
        return output

def main():
    if not os.path.isfile(ENGINE_PATH):
        raise FileNotFoundError(f"Engine TensorRT no encontrado: {ENGINE_PATH}")
    if not os.path.isfile(LABELS_PATH):
        raise FileNotFoundError(f"Archivo de labels no encontrado: {LABELS_PATH}")

    labels = load_labels(LABELS_PATH)
    assert len(labels) >= NUM_CLASSES, "Labels ImageNet insuficientes"

    trt_infer = TRTInference(ENGINE_PATH)

    gst = build_gst_pipeline(width=1280, height=720, fps=30, sensor_id=0)
    cap = cv2.VideoCapture(gst, cv2.CAP_GSTREAMER)
    if not cap.isOpened():
        raise RuntimeError("No se pudo abrir la cámara CSI con GStreamer")

    print("Presiona 'q' para salir.")
    t_last = time.time()
    frame_count = 0
    fps = 0.0

    while True:
        ok, frame = cap.read()
        if not ok:
            print("Fin de flujo o error de cámara")
            break

        # Preprocesado e inferencia
        tensor = preprocess_bgr(frame)
        logits = trt_infer.infer(tensor)
        probs = softmax(logits)[0]

        # Agregación por categorías
        best_cat, best_score, cat_scores, topk_idx = aggregate_to_recyclables(probs, labels, topk=5)

        # FPS
        frame_count += 1
        now = time.time()
        if now - t_last >= 1.0:
            fps = frame_count / (now - t_last)
            t_last = now
            frame_count = 0

        # Overlay
        overlay = f"{best_cat} ({best_score:.2f}) | {fps:.1f} FPS"
        cv2.putText(frame, overlay, (12, 28), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0,255,0), 2)

        # Mostrar top-3 clases ImageNet para depuración
        h = 50
        for rank, idx in enumerate(topk_idx[:3], start=1):
            txt = f"Top{rank}: {labels[idx]} ({probs[idx]:.2f})"
            cv2.putText(frame, txt, (12, 28 + h*rank), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,0), 1)

        cv2.imshow("tensorrt-recyclables-classifier", frame)
        key = cv2.waitKey(1) & 0xFF
        if key == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

Breve explicación de partes clave:
– Preprocesado: redimensiona a 224×224, normaliza por mean/std de ImageNet y convierte a NCHW float32.
– Motor TensorRT: se carga desde archivo .engine generado con trtexec (FP16). El binding de entrada debe llamarse “data” para el modelo mobilenetv2-7.onnx del ONNX Model Zoo.
– Inferencia: se gestionan los buffers H2D/D2H con pycuda y se lanza execute_async_v2 en el stream CUDA.
– Agregación: toma top-5 etiquetas de ImageNet, las compara por palabras clave para asignarlas a categorías de reciclaje y suma probabilidades. Es un demo didáctico (para despliegue real, entrenar un modelo específico de reciclaje).
– Medición: calcula FPS en ventana móvil de 1 s; permite observar rendimiento.

Compilación/ejecución paso a paso (comandos exactos)

1) Preparar carpetas y dependencias mínimas:

sudo apt-get update
sudo apt-get install -y python3-pip python3-numpy python3-opencv python3-pycuda \
                        git wget gstreamer1.0-tools
mkdir -p $HOME/models/tensorrt-recyclables-classifier
mkdir -p $HOME/tensorrt-recyclables-classifier

2) Descargar el modelo ONNX y etiquetas de ImageNet:
– Usaremos MobileNetV2 (opset 7) del ONNX Model Zoo (entrada: “data”, tamaño 224×224).

cd $HOME/models/tensorrt-recyclables-classifier
wget https://github.com/onnx/models/raw/main/vision/classification/mobilenet/model/mobilenetv2-7.onnx -O mobilenetv2-7.onnx
wget https://raw.githubusercontent.com/jetson-inference/jetson-inference/master/data/networks/ilsvrc12/synset_words.txt -O imagenet_labels.txt

3) Construir el motor TensorRT FP16 con trtexec:
– Herramienta: /usr/src/tensorrt/bin/trtexec (TensorRT 8.2.1.8 para JetPack 4.6.4)

/usr/src/tensorrt/bin/trtexec \
  --onnx=$HOME/models/tensorrt-recyclables-classifier/mobilenetv2-7.onnx \
  --saveEngine=$HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine \
  --explicitBatch \
  --minShapes=data:1x3x224x224 \
  --optShapes=data:1x3x224x224 \
  --maxShapes=data:1x3x224x224 \
  --fp16 \
  --workspace=1024 \
  --separateProfileRun \
  --verbose

Salida esperada: debe reportar que se ha creado un engine con precisión FP16, tamaño de workspace y bindings “data” (entrada) y una salida de 1×1000.

4) Prueba de rendimiento rápida del engine:

/usr/src/tensorrt/bin/trtexec \
  --loadEngine=$HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine \
  --shapes=data:1x3x224x224 \
  --iterations=200 \
  --warmUp=50 \
  --separateProfileRun

Observe el “mean latency” y “throughput” (FPS teórico del motor aislado).

5) Copiar el script de inferencia y configurar rutas:

cd $HOME/tensorrt-recyclables-classifier
# Cree el archivo con el contenido mostrado en la sección de código completo
nano tensorrt_recyclables.py
# Ajuste permisos de ejecución
chmod +x tensorrt_recyclables.py

# Enlazar/duplicar archivos del modelo hacia el directorio del proyecto:
ln -sf $HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine $HOME/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine
ln -sf $HOME/models/tensorrt-recyclables-classifier/imagenet_labels.txt $HOME/tensorrt-recyclables-classifier/imagenet_labels.txt

6) Activar MAXN y clocks (opcional pero recomendado) y lanzar inferencia:

# Potencia
sudo nvpmodel -m 0
sudo jetson_clocks

# Monitoreo (en otra terminal)
sudo tegrastats

# Ejecutar la app
cd $HOME/tensorrt-recyclables-classifier
./tensorrt_recyclables.py

Al ejecutar, se abrirá una ventana con el video y overlay de categoría + probabilidad + FPS. Presione “q” para salir.

Validación paso a paso

1) Verifique la cámara:
– Comando GStreamer anterior debe mostrar FPS sin errores. Errores comunes de nvargus indican problema de cable/driver.

2) Confirmar motor TensorRT:
– trtexec debe finalizar con “Engine built in X ms” y sin warnings críticos de precisión/shape.
– La prueba de rendimiento de trtexec debe mostrar throughput estimado > 100 FPS para MobileNetV2 FP16 (motor puro). En la app completa, el FPS será menor por captura y overlay, esperado 18–35 FPS.

3) Ejecución de la app:
– Ventana “tensorrt-recyclables-classifier” renderizando el feed CSI en 1280×720.
– Overlay superior:
– Línea 1: “plastico (0.62) | 27.4 FPS” (ejemplo)
– Líneas siguientes: Top1/Top2/Top3 de etiquetas ImageNet con probabilidades.

4) Métricas de rendimiento:
– tegrastats (en otra terminal) muestra líneas como:
– GR3D_FREQ 76%@921 (utilización GPU ~ 40–70%)
– EMC_FREQ ~ 10–40% (depende de memoria)
– Mem RAM usada: < 1.5 GB
– Si ve “throttle” o clocks reducidos, mejore la refrigeración.

5) Exactitud cualitativa (demo):
– Acerque a la cámara:
– Botella plástica transparente → categoría “plastico” con score agregado > 0.5 (si la etiqueta top-1 es “water bottle”, etc.).
– Lata de refresco → “metal”.
– Botella de vidrio o vaso → “vidrio”.
– Hoja de papel/cartón → “papel_carton”.
– En escenarios ambiguos o sin correspondencia de palabras clave, la categoría resultará “no_reconocido”.

6) Limpieza (opcional):
– Restaurar modo de potencia si lo desea:
– sudo nvpmodel -m 1 (modo más conservador) y reiniciar.

Troubleshooting (errores típicos y solución)

1) nvarguscamerasrc: “ERROR [Component ::NvArgusCameraSrc] No cameras available”
– Causa: cámara IMX219 no detectada, cable CSI mal orientado o no firme.
– Solución: apague, reconecte el cable asegurando orientación correcta, pruebe con sensor-id=0 y 1, verifique dmesg | grep imx219. Asegúrese de usar Arducam IMX219 8MP (imx219) compatible.

2) trtexec: “Network has dynamic shapes but no optimization profile provided”
– Causa: no se especificaron min/opt/max shapes.
– Solución: use los flags –minShapes/–optShapes/–maxShapes como en los comandos provistos para el binding “data:1x3x224x224”.

3) trtexec: “Could not find binding for input name ‘data’”
– Causa: el input del modelo ONNX no se llama “data”.
– Solución: confirme el nombre del input con onnx.checker o Netron. Para mobilenetv2-7 del ONNX Model Zoo suele ser “data”. Si difiere, ajuste INPUT_NAME en el script y los flags de trtexec.

4) ImportError: No module named ‘tensorrt’ o ‘pycuda’
– Causa: falta del paquete Python de TensorRT/pycuda o mismatch de Python 3.6.
– Solución: asegure JetPack 4.6.4; instale python3-pycuda vía apt; TensorRT Python viene con el SDK. Si aún falla, reinstale componentes de JetPack o configure PYTHONPATH a /usr/lib/python3.6/dist-packages.

5) Bajo rendimiento (FPS < 10) y/o throttling
– Causa: modo de potencia limitado, temperaturas altas, falta de ventilación.
– Solución: sudo nvpmodel -m 0; sudo jetson_clocks; añada ventilador/disipador; reduzca overlay pesado o resolución de captura; cierre aplicaciones en paralelo.

6) OpenCV no abre la cámara con GStreamer
– Causa: pipeline incorrecto o plugins ausentes.
– Solución: pruebe gst-launch-1.0 con nvarguscamerasrc; si funciona, revise el pipeline de appsink en el script; verifique que OpenCV tenga GStreamer habilitado (cv2.getBuildInformation()).

7) Engine incompatible tras actualizar paquetes
– Causa: el engine TRT es específico de hardware/software.
– Solución: borre y regenere el .engine con la versión actual de TensorRT (trtexec) en la Jetson Nano.

8) Artefactos de clasificación incoherentes
– Causa: el mapeo por palabras clave es didáctico; ImageNet no está optimizado para reciclables.
– Solución: entrene/fine-tune un modelo con clases de reciclaje y exporte ONNX; o amplíe keywords y normalice iluminación y encuadre.

Mejoras/variantes

  • INT8 con calibración: genere un calibrador con imágenes representativas para INT8 y use trtexec –int8 –calib; ganará rendimiento con ligera pérdida de precisión.
  • Modelo específico de reciclaje: fine-tune MobileNetV2/ResNet18 en dataset de “reciclables” (clases: plástico, metal, vidrio, papel/cartón). Exportar a ONNX (opset 11+) con entrada fija 224×224 para simplificar.
  • DeepStream alternativa: pipeline con nvinfer, nvvidconv, nvdsosd para overlay, y source nvarguscamerasrc; útil para integrarse con RTSP y analítica multi-stream.
  • Preprocesado en GPU: usar jetson-utils o cv2.cuda para conversiones y escalado; reducir latencia.
  • Ahorro de energía: bajar resolución/fps, desactivar jetson_clocks cuando no se use.
  • Integración con GPIO/I2C: activar un LED según categoría o enviar el resultado a un microcontrolador; registro en CSV y panel remoto (MQTT).
  • Mejora de overlay: colorear por categoría, mostrar barras de probabilidad, registrar top-5.

Checklist de verificación

  • [ ] Modelo exacto usado: Jetson Nano 4GB + Arducam IMX219 8MP (imx219) conectados por CSI.
  • [ ] Sistema: JetPack 4.6.4 (L4T R32.7.4), Ubuntu 18.04.6; CUDA 10.2; cuDNN 8.2.1; TensorRT 8.2.1.8; OpenCV 4.1.1; GStreamer 1.14.5; Python 3.6.9.
  • [ ] Cámara verificada con gst-launch-1.0 nvarguscamerasrc … sin errores.
  • [ ] Modelo ONNX descargado: mobilenetv2-7.onnx y etiquetas imagenet_labels.txt en $HOME/models/tensorrt-recyclables-classifier/.
  • [ ] Motor TensorRT FP16 generado con trtexec en $HOME/models/tensorrt-recyclables-classifier/mobilenetv2_fp16.engine.
  • [ ] Script tensorrt_recyclables.py creado en $HOME/tensorrt-recyclables-classifier/ y ejecutable.
  • [ ] Ejecución en MAXN (opcional): sudo nvpmodel -m 0; sudo jetson_clocks; tegrastats en paralelo.
  • [ ] Al ejecutar, se ve video + overlay con categoría, probabilidad y FPS; respuesta coherente ante objetos plásticos/metal/vidrio/papel.
  • [ ] Métricas dentro de lo esperado: 18–35 FPS en pipeline completo, GPU 40–70%, sin throttling sostenido.
  • [ ] Finalización limpia y opción de revertir potencia: sudo nvpmodel -m 1 (si se desea).

Con esto, tendrás un clasificador de reciclables “tensorrt-recyclables-classifier” operativo y didáctico sobre Jetson Nano 4GB con cámara Arducam IMX219 (imx219), empleando una toolchain exacta basada en JetPack 4.6.4 y TensorRT 8.2.1.8, con código y comandos reproducibles de principio a fin.

Encuentra este producto y/o libros sobre este tema en Amazon

Ir a Amazon

Como afiliado de Amazon, gano con las compras que cumplan los requisitos. Si compras a través de este enlace, ayudas a mantener este proyecto.

Quiz rápido

Pregunta 1: ¿Cuál es el objetivo principal del clasificador 'tensorrt-recyclables-classifier'?




Pregunta 2: ¿Qué cámara se utiliza en el proyecto?




Pregunta 3: ¿Cuál es la latencia de inferencia esperada con FP16?




Pregunta 4: ¿Qué tipo de residuos se busca clasificar?




Pregunta 5: ¿Qué tecnología se utiliza para la inferencia en el clasificador?




Pregunta 6: ¿Qué tipo de overlay se muestra en la pantalla?




Pregunta 7: ¿Cuál es el uso de la GPU durante el procesamiento?




Pregunta 8: ¿Qué se espera que suceda si aparece un material no esperado?




Pregunta 9: ¿Cuál es el público objetivo del proyecto?




Pregunta 10: ¿Qué resolución se utiliza para la cámara IMX219 en el proyecto?




Carlos Núñez Zorrilla
Carlos Núñez Zorrilla
Electronics & Computer Engineer

Ingeniero Superior en Electrónica de Telecomunicaciones e Ingeniero en Informática (titulaciones oficiales en España).

Sígueme:
Scroll to Top