Objetivo y caso de uso
Qué construirás: Un sistema “opencv-csi-motion-detection” que captura en tiempo real desde la cámara CSI IMX219 en un Jetson Orin Nano y detecta movimiento con OpenCV. Mostrará cuadros delimitadores y FPS en pantalla y registrará eventos cuando haya actividad.
Para qué sirve
- Vigilancia de pasillos/entradas: registrar cada cruce con marca de tiempo.
- Monitorización de línea de producción: detectar interrupciones o presencia/ausencia de piezas en una ROI.
- Detección de intrusión en zona restringida: activar una acción (p. ej., guardar clip) en una franja horaria.
- Conteo orientativo de eventos (cruces) en un área definida del plano.
- Auto-grabación de clips breves sólo cuando hay movimiento para ahorrar espacio.
Resultado esperado
- FPS estable de 25–30 a 1280×720 con IMX219, con sobreimpresión de cuadros cuando hay movimiento.
- Al menos 90% de eventos reales detectados en condiciones de luz normales (falsos positivos limitados ajustando umbrales).
- Latencia fin a fin por debajo de 120 ms a 720p.
Público objetivo: makers, ingenieros de visión/IoT edge y equipos de operaciones; Nivel: intermedio.
Arquitectura/flujo: IMX219 (CSI) → GStreamer/nvarguscamerasrc → OpenCV VideoCapture → preprocesado (grayscale+blur) → sustracción de fondo/diferencia de frames → contornos y cuadros → cálculo de FPS → filtros (ROI/horario) → logger de eventos y grabación opcional → display con overlay (objetivo: 25–30 FPS, <120 ms a 720p).
Prerrequisitos (SO y toolchain concreta)
Usaremos el NVIDIA Jetson Orin Nano Developer Kit con JetPack 6.1 (L4T r36.3), que incluye Ubuntu 22.04 aarch64 y los stacks multimedia/IA de NVIDIA. Asegúrate de arrancar con JetPack 6.x (no 5.x).
- Sistema:
- JetPack: 6.1 (L4T r36.3.0)
- Ubuntu: 22.04 LTS (aarch64)
- Toolchain y librerías (suministradas por JetPack 6.1 o instaladas):
- CUDA 12.2
- TensorRT 8.6.3
- OpenCV 4.8.0 (compilada con soporte GStreamer y, en general, con aceleración Jetson)
- GStreamer 1.20.x (plugins base, good, bad, nvvidconv, nvarguscamerasrc)
- Python 3.10.12
- NumPy 1.26.x
- (Opcional, solo para referencia de GPU en validación) trtexec de TensorRT 8.6.3
Verifica versiones:
# JetPack / L4T
cat /etc/nv_tegra_release
# Alternativa (si instalado):
jetson_release -v
# Kernel y paquetes NVIDIA/TensorRT
uname -a
dpkg -l | grep -E 'nvidia|tensorrt|cuda|cudnn'
# OpenCV en Python
python3 -c "import cv2; import numpy as np; print('OpenCV:', cv2.__version__); print('NumPy:', np.__version__)"
# GStreamer
gst-launch-1.0 --version
Ejemplo de salida esperada (puede variar levemente por parches menores, pero mantenemos coherencia con 6.1):
– L4T R36.3
– CUDA 12.2
– TensorRT 8.6.3 (libnvinfer8)
– OpenCV 4.8.0
– GStreamer 1.20.x
– Python 3.10.12
Paquetes a instalar/confirmar:
sudo apt update
sudo apt install -y \
python3-opencv python3-numpy python3-pip \
gstreamer1.0-tools gstreamer1.0-plugins-base \
gstreamer1.0-plugins-good gstreamer1.0-plugins-bad \
v4l-utils tegrastats
# Asegurar pip reciente
python3 -m pip install --upgrade pip
Ajuste de rendimiento (opcional pero recomendado para mediciones):
# Consultar modo actual
sudo nvpmodel -q
# Poner en MAXN (modo 0 normalmente es el de mayor rendimiento en Orin Nano)
sudo nvpmodel -m 0
# Fijar clocks al máximo temporalmente (revertir al final)
sudo jetson_clocks
Advertencia térmica: al usar jetson_clocks, vigila temperaturas (tegrastats) y asegúrate de una ventilación adecuada.
Materiales
- NVIDIA Jetson Orin Nano Developer Kit + Raspberry Pi Camera Module v2 (Sony IMX219).
- Cable FFC de 15 pines para la cámara (incluido normalmente con la cámara).
- Tarjeta microSD de al menos 64 GB (si usas el slot microSD) o NVMe M.2 para sistema.
- Fuente de alimentación 5V/4A USB-C de calidad.
- Acceso a red (Ethernet o Wi-Fi) para instalar paquetes.
- Opcional: monitor HDMI y teclado/ratón; aunque los pasos usan solo terminal.
Preparación y conexión
Conexión de la cámara CSI (IMX219) al Jetson Orin Nano
- El Jetson Orin Nano Developer Kit dispone de un conector CSI de 15 pines compatible con la Raspberry Pi Camera v2.
- Desenergiza la placa antes de conectar la cámara.
- La orientación del cable FFC es crítica: la cara con contactos suele ir hacia el conector (lado del conector HDMI; revisa el “CAM0/CAM1” impreso en la placa). Inserta el FFC recto y bloquea la pestaña.
Tabla (referencial) de elementos de conexión y verificación:
| Elemento | Puerto/Conector en Jetson | Detalle/Acción | Resultado esperado |
|---|---|---|---|
| Cámara RPi v2 (IMX219) | CSI “CAM0” (15 pines) | Insertar FFC, cerrar clip | FFC firme y recto |
| Alimentación | USB-C 5V/4A | Encender Jetson | LED encendido, boot correcto |
| Verificación sensor | nvargus-daemon | Servicio activo por defecto | Sin errores al usar nvarguscamerasrc |
| Test rápido GStreamer | nvarguscamerasrc | Ver pipeline básico | Se muestra video o fakesink sin errores |
Verifica que la cámara responde (prueba básica, sin GUI):
# Prueba: tomar 100 frames y descartar (fakesink)
gst-launch-1.0 -e nvarguscamerasrc num-buffers=100 ! 'video/x-raw(memory:NVMM), width=1280, height=720, framerate=30/1' ! fakesink
Si no hay errores, el sensor IMX219 es detectado por Argus.
Código completo (Python + OpenCV con GStreamer CSI)
Implementaremos un detector de movimiento básico con:
– Captura GStreamer desde CSI (nvarguscamerasrc).
– Conversión a BGR para OpenCV (appsink).
– Sustracción de fondo MOG2 + operaciones morfológicas.
– Detección de contornos y filtrado por área mínima.
– Overlay: rectángulos, texto con FPS y estado.
– Registro de eventos con timestamp.
– Opcional: guardado de video cuando se detecta movimiento.
Guarda este script como opencv_csi_motion_detection.py:
#!/usr/bin/env python3
import argparse
import time
import sys
import cv2
import numpy as np
from collections import deque
from datetime import datetime
def gstreamer_pipeline(
sensor_id=0,
width=1280,
height=720,
framerate=30,
flip_method=0
):
# Pipeline NVArgus -> NVMM -> nvvidconv -> BGRx -> videoconvert -> BGR -> appsink
# Ajusta flip_method si necesitas rotación (0 sin flip)
return (
f"nvarguscamerasrc sensor-id={sensor_id} ! "
f"video/x-raw(memory:NVMM), width={width}, height={height}, "
f"format=NV12, framerate={framerate}/1 ! "
f"nvvidconv flip-method={flip_method} ! "
f"video/x-raw, format=BGRx ! "
f"videoconvert ! "
f"video/x-raw, format=BGR ! "
f"appsink drop=1 max-buffers=1"
)
def main():
parser = argparse.ArgumentParser(description="OpenCV CSI Motion Detection (IMX219 on Jetson Orin Nano)")
parser.add_argument("--sensor-id", type=int, default=0, help="ID del sensor CSI (0 por defecto)")
parser.add_argument("--width", type=int, default=1280, help="Ancho de captura")
parser.add_argument("--height", type=int, default=720, help="Alto de captura")
parser.add_argument("--fps", type=int, default=30, help="FPS de captura")
parser.add_argument("--flip", type=int, default=0, help="flip-method nvvidconv (0 sin flip)")
parser.add_argument("--display", type=int, default=1, help="Mostrar ventana (1 si, 0 no)")
parser.add_argument("--record", type=int, default=0, help="Grabar cuando haya movimiento (1 si, 0 no)")
parser.add_argument("--min-area", type=int, default=1500, help="Área mínima del contorno para considerarlo movimiento")
parser.add_argument("--dilate-iter", type=int, default=2, help="Iteraciones de dilatación")
parser.add_argument("--erode-iter", type=int, default=1, help="Iteraciones de erosión")
parser.add_argument("--roi", type=str, default="", help="ROI 'x,y,w,h' (opcional)")
parser.add_argument("--warmup-sec", type=float, default=1.0, help="Tiempo de calentamiento del sustractor de fondo")
args = parser.parse_args()
pipeline = gstreamer_pipeline(
sensor_id=args.sensor_id,
width=args.width,
height=args.height,
framerate=args.fps,
flip_method=args.flip
)
cap = cv2.VideoCapture(pipeline, cv2.CAP_GSTREAMER)
if not cap.isOpened():
print("ERROR: No se pudo abrir la cámara CSI con GStreamer.")
sys.exit(1)
# Sustractor de fondo (MOG2)
backsub = cv2.createBackgroundSubtractorMOG2(history=500, varThreshold=25, detectShadows=True)
# Opcional: parsear ROI
roi = None
if args.roi:
try:
x, y, w, h = [int(v) for v in args.roi.split(",")]
roi = (x, y, w, h)
except Exception as e:
print(f"Advertencia: ROI inválida ({args.roi}). Se ignora. Error: {e}")
# Grabador de video cuando hay movimiento
fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = None
recording = False
record_queue = deque(maxlen=30) # buffer para pre-captura (1 segundo aprox a 30 FPS)
# Métricas
prev_time = time.perf_counter()
fps = 0.0
frame_count = 0
motion_events = 0
warmup_end = time.perf_counter() + args.warmup_sec
print("Inicializando... Presiona 'q' para salir.")
while True:
ret, frame = cap.read()
if not ret:
print("ERROR: frame no válido. Saliendo.")
break
frame_count += 1
now = time.perf_counter()
dt = now - prev_time
if dt > 0.5:
fps = frame_count / dt
frame_count = 0
prev_time = now
# Aplicar ROI si existe
proc = frame
if roi:
x, y, w, h = roi
proc = frame[y:y+h, x:x+w]
# Sustracción de fondo
fgmask = backsub.apply(proc)
# Saltar detección durante warmup para estabilizar el modelo
in_warmup = (now < warmup_end)
# Morfología
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3))
fgmask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel, iterations=1)
if args.erode_iter > 0:
fgmask = cv2.erode(fgmask, None, iterations=args.erode_iter)
if args.dilate_iter > 0:
fgmask = cv2.dilate(fgmask, None, iterations=args.dilate_iter)
# Umbralización para binario puro
_, th = cv2.threshold(fgmask, 200, 255, cv2.THRESH_BINARY)
# Contornos
contours, _ = cv2.findContours(th, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# Detección de movimiento (filtrado por área)
movement_detected = False
for c in contours:
area = cv2.contourArea(c)
if area < args.min_area:
continue
movement_detected = True
x2, y2, w2, h2 = cv2.boundingRect(c)
# Ajustar coordenadas si hay ROI
if roi:
x2 += roi[0]
y2 += roi[1]
cv2.rectangle(frame, (x2, y2), (x2 + w2, y2 + h2), (0, 255, 0), 2)
cv2.putText(frame, f"Area:{int(area)}", (x2, y2 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 200, 0), 1)
# Estado y métricas en overlay
status_text = "WARMUP" if in_warmup else ("MOVIMIENTO" if movement_detected else "OK")
color = (0, 255, 255) if in_warmup else ((0, 0, 255) if movement_detected else (255, 255, 255))
cv2.putText(frame, f"{status_text} | FPS:{fps:.1f}", (10, 25),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2)
# Gestión de grabación
if args.record:
# Guardar en buffer circular
record_queue.append(frame.copy())
if movement_detected and not in_warmup:
if not recording:
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"motion_{ts}.mp4"
out = cv2.VideoWriter(filename, fourcc, args.fps, (frame.shape[1], frame.shape[0]))
# Vuelca el buffer para no perder lo previo al evento
for f in record_queue:
out.write(f)
recording = True
motion_events += 1
print(f"[{ts}] Movimiento detectado -> Grabando en {filename}")
# Seguir grabando
out.write(frame)
else:
# Si no hay movimiento, cierra si estaba grabando
if recording:
out.release()
out = None
recording = False
# Mostrar ventana si procede
if args.display:
cv2.imshow("CSI Motion Detection (IMX219)", frame)
# También podemos ver la máscara con:
# cv2.imshow("FG Mask", th)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
break
# Limpieza
if out is not None:
out.release()
cap.release()
cv2.destroyAllWindows()
print(f"Eventos de movimiento contados: {motion_events}")
if __name__ == "__main__":
main()
Puntos clave del código:
– gstreamer_pipeline utiliza nvarguscamerasrc para capturar la IMX219 por CSI y entrega BGR a OpenCV mediante appsink.
– El sustractor MOG2 es suficiente para nivel básico; podría trocarse por KNN.
– ROI opcional para concentrar la detección en un área.
– Grabación basada en eventos y buffer de pre-captura para no perder el inicio del movimiento.
– Overlay con estado y FPS.
Compilación/flash/ejecución
No hay compilación; es Python. Reproduce exactamente:
1) Clona o crea el archivo:
nano opencv_csi_motion_detection.py
# (Pega el código anterior, guarda con Ctrl+O y sal con Ctrl+X)
chmod +x opencv_csi_motion_detection.py
2) Ejecuta (720p a 30 FPS, con ventana y sin grabación):
./opencv_csi_motion_detection.py --width 1280 --height 720 --fps 30 --display 1 --record 0
3) Variantes:
– Desactivar ventana (headless), útil para solo medir:
./opencv_csi_motion_detection.py --display 0
- Activar grabación de clips al detectar movimiento:
./opencv_csi_motion_detection.py --record 1
- Definir una ROI (por ejemplo, rectángulo desde x=200,y=120, tamaño 500×300):
./opencv_csi_motion_detection.py --roi 200,120,500,300
4) Ajuste de rendimiento y telemetría (opcional):
– Asegura MAXN y clocks:
sudo nvpmodel -m 0
sudo jetson_clocks
- Corre tu script y, en otra terminal, observa recursos:
tegrastats
- Para revertir jetson_clocks cuando termines:
sudo systemctl restart nvfancontrol || true
sudo /usr/sbin/jetson_clocks --restore
Validación paso a paso
1) Validar cámara CSI por GStreamer:
– Comando:
bash
gst-launch-1.0 -e nvarguscamerasrc num-buffers=120 ! 'video/x-raw(memory:NVMM), width=1280, height=720, framerate=30/1' ! nvvidconv ! fakesink
– Esperado: termina sin errores tras procesar 120 buffers. Sin mensajes “no sensor found” ni fallos de nvargus-daemon.
2) Validar OpenCV con pipeline CSI:
– Comando:
bash
python3 - << 'PY'
import cv2
pipeline = "nvarguscamerasrc ! video/x-raw(memory:NVMM), width=640, height=480, framerate=30/1 ! nvvidconv ! video/x-raw, format=BGRx ! videoconvert ! video/x-raw, format=BGR ! appsink drop=1"
cap = cv2.VideoCapture(pipeline, cv2.CAP_GSTREAMER)
print("Opened:", cap.isOpened())
ret, frame = cap.read()
print("Frame:", ret, "shape:" if ret else "", frame.shape if ret else "")
cap.release()
PY
– Esperado: Opened: True y al menos un frame con shape razonable (por ejemplo, (480, 640, 3)).
3) Ejecutar el detector de movimiento y observar overlays:
– Comando:
bash
./opencv_csi_motion_detection.py --width 1280 --height 720 --fps 30 --display 1
– Esperado:
– En los primeros ~1 s, estado “WARMUP”.
– Al mover la mano frente a la cámara, aparecen rectángulos verdes y “MOVIMIENTO”.
– FPS entre 25 y 30 en 720p (según condiciones y carga).
– Si activas –record 1, verás en consola líneas del tipo:
“[YYYYMMDD_HHMMSS] Movimiento detectado -> Grabando en motion_YYYYMMDD_HHMMSS.mp4”.
4) Métricas objetivas:
– FPS: mostrado en overlay y estable >25 FPS a 1280×720. Puedes registrar promedio ejecutando en headless 60 s y midiendo FPS medios por logs si agregas prints, o añadiendo contador simple.
– Latencia: si se requiere, añade marcas de tiempo en overlay (time.perf_counter()) y calcula delta con tegrastats para observar coherencia.
– Área: en overlay “Area:xxxx” por cada contorno. Ajusta –min-area hasta limitar falsos positivos (ruido).
– Porcentaje CPU/GPU/memoria: con tegrastats:
bash
tegrastats
Observa campos como GR3D (GPU), EMC y RAM durante la ejecución.
5) Validación de aceleración GPU (ruta A: TensorRT + ONNX, solo como referencia de stack IA):
– Descarga un modelo ONNX ligero (ResNet50-v2):
bash
wget -O resnet50-v2-7.onnx https://github.com/onnx/models/raw/main/vision/classification/resnet/model/resnet50-v2-7.onnx
– Construye motor FP16 con trtexec (TensorRT 8.6.3):
bash
trtexec --onnx=resnet50-v2-7.onnx \
--saveEngine=resnet50_fp16.plan \
--fp16 \
--workspace=2048 \
--shapes=data:1x3x224x224 \
--timingCacheFile=trt_timing.cache \
--separateProfileRun
– Mide rendimiento:
bash
trtexec --loadEngine=resnet50_fp16.plan \
--shapes=data:1x3x224x224 \
--iterations=200 --avgRuns=100 --streams=1
– Esperado: Latencias medias de 2–5 ms por inferencia (200–500 FPS) en Orin Nano con FP16 (los valores exactos varían). Los logs de trtexec informan “Throughput” y “Mean latency”.
Criterios de éxito del caso:
– El script detecta movimiento de manera fiable en un entorno real, con overlay y FPS visibles.
– Las métricas obtenidas (FPS, latencia aproximada, porcentaje de falso positivo) cumplen las metas enunciadas.
– Se confirma que el stack multimedia (nvarguscamerasrc) y el stack de IA (TensorRT) están funcionales y acelerados por GPU.
Troubleshooting (errores típicos y soluciones)
1) No se abre la cámara CSI en OpenCV (cap.isOpened() == False):
– Causa: pipeline GStreamer incorrecto o falta de nvarguscamerasrc.
– Solución: verifica que gstreamer1.0 está instalado; prueba con gst-launch-1.0 nvarguscamerasrc … y ajusta el pipeline exactamente como en el código. Asegúrate de no instalar opencv-python de pip que sobreescriba la versión de apt (sin soporte GStreamer). Si lo hiciste por error, desinstala con pip y reinstala python3-opencv desde apt.
2) Error “no sensor found” o “nvargus-daemon” falla:
– Causa: cámara mal conectada, cable invertido o conector suelto.
– Solución: apaga, reconecta FFC (cara de contactos orientada correctamente), usa el conector CSI correcto (CAM0), arranca de nuevo. Ejecuta “sudo systemctl restart nvargus-daemon” y prueba otra vez.
3) Ventana negra o latencia muy alta:
– Causa: pipeline sin caps adecuados, conversiones innecesarias o hardware acelerado deshabilitado.
– Solución: usa exactamente la cadena propuesta: nvarguscamerasrc → nvvidconv → BGRx → videoconvert → BGR → appsink. Evita resoluciones/frame rates no soportados por el sensor (IMX219 soporta 1280×720 a 60/30, 1920×1080 a 30, etc., según modos).
4) FPS bajo (<15 FPS en 720p):
– Causa: modo de energía bajo, CPU/GPU limitados o tegrastats muestra throttling.
– Solución: “sudo nvpmodel -m 0” y “sudo jetson_clocks” (temporal). Asegura ventilación. Cierra procesos intensivos. Reduce operaciones morfológicas o aumenta min-area para reducir contornos pequeños.
5) Muchos falsos positivos (ruido):
– Causa: iluminación variable, sombras o reflejos.
– Solución: incrementa –min-area, usa detectShadows=True (ya activado) y eleva varThreshold en MOG2 si modificas el código. Añade ROI para limitar zonas problemáticas. Aplica un blur ligero antes del sustractor de fondo.
6) Error al compilar/run trtexec o ONNX:
– Causa: falta de modelo o shapes incorrectos.
– Solución: verifica el nombre de input del modelo (data:1x3x224x224 en resnet50-v2-7.onnx). Asegura TensorRT instalado (JetPack 6.1) y que trtexec está en PATH (normalmente /usr/src/tensorrt/bin o /usr/bin con enlaces). Revisa dpkg -l | grep tensorrt.
7) “Segmentation fault” al cerrar:
– Causa: recursos no liberados o conflicto de ventanas.
– Solución: asegura cap.release() y cv2.destroyAllWindows() se ejecutan; cierra con ‘q’. Evita cerrar la terminal abruptamente. No mezcles threads sin necesidad.
8) Instalé OpenCV por pip y perdí soporte GStreamer:
– Causa: el wheel de pip suele venir sin GStreamer.
– Solución: “pip3 uninstall opencv-python opencv-contrib-python” y “sudo apt install –reinstall python3-opencv”. Verifica con “cv2.getBuildInformation()” que GStreamer esté “YES” si deseas confirmación (opcional).
Mejoras/variantes
- Refinar el sustractor:
- Probar KNN (cv2.createBackgroundSubtractorKNN) para entornos con variación lenta de iluminación.
-
Aplicar un pre-blur (cv2.GaussianBlur) sobre proc antes de apply().
-
Post-procesado:
- Añadir seguimiento simple (centroid tracking) y conteo de “cruces de línea”.
-
Filtrar contornos por relación de aspecto o perímetro para ignorar ruido.
-
Gestión de eventos:
- Guardar snapshots (JPEG) solo cuando movimiento inicia o termina, además de los clips mp4.
-
Enviar notificaciones vía MQTT o HTTP al detectar movimiento.
-
Rendimiento:
- Reducir resolución a 960×540 o 640×480 si se requiere latencia aún menor.
- Ajustar dilate/erode para balancear ruido y coste de CPU.
-
Utilizar colas y timers para calcular FPS con más precisión a intervalos fijos.
-
IA acelerada (futuras extensiones coherentes con Jetson):
- Integrar un detector de personas ligero (por ejemplo, PeopleNet con TensorRT) para disparar eventos sólo cuando se detecte una persona, reduciendo falsos positivos.
- Migrar a un pipeline GStreamer con DeepStream si prefieres una arquitectura más modular para producción.
Checklist de verificación
- [ ] Confirmé versiones: JetPack 6.1 (L4T r36.3), Ubuntu 22.04, CUDA 12.2, TensorRT 8.6.3, OpenCV 4.8.0, Python 3.10.12, GStreamer 1.20.x.
- [ ] Instalé paquetes vía apt (python3-opencv, gstreamer, v4l-utils, tegrastats) sin errores.
- [ ] Conecté la Raspberry Pi Camera Module v2 (IMX219) correctamente al puerto CSI (CAM0) con FFC bien orientado.
- [ ] Verifiqué la cámara con gst-launch-1.0 nvarguscamerasrc … sin errores.
- [ ] Ejecuté opencv_csi_motion_detection.py y vi overlay con FPS y rectángulos al mover la mano.
- [ ] Ajusté –min-area, ROI y morfología hasta reducir falsos positivos en mi entorno.
- [ ] Medí recursos con tegrastats y, si fue necesario, ajusté nvpmodel/jetson_clocks (recordando revertir al finalizar).
- [ ] Verifiqué el stack de IA con trtexec y un modelo ONNX, observando throughput esperable.
- [ ] Guardé clips con –record 1 y comprobé que se crean archivos MP4 con marcas de tiempo.
Notas finales sobre coherencia de hardware/software
- Este caso práctico está diseñado específicamente para NVIDIA Jetson Orin Nano Developer Kit con Raspberry Pi Camera Module v2 (Sony IMX219), usando su puerto CSI y la cadena nvarguscamerasrc de NVIDIA.
- Toolchain exacta empleada y validada: JetPack 6.1 (L4T r36.3), CUDA 12.2, TensorRT 8.6.3, OpenCV 4.8.0, GStreamer 1.20.x, Python 3.10.12, NumPy 1.26.x.
- El objetivo “opencv-csi-motion-detection” se cubre con captura acelerada por hardware (NVMM, nvvidconv) y procesamiento en OpenCV, más una referencia clara de aceleración IA con TensorRT para asegurar el entorno GPU.
Encuentra este producto y/o libros sobre este tema en 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.




