Inteligencia artificial aplicada 14 min lectura

Visión por computadora profesional con Python: cámara, detección de objetos, tracking y eventos con YOLO

Un prototipo serio de visión por computadora no debe limitarse a “dibujar cuadros” sobre la webcam. Debe capturar video de forma estable, usar modelos modernos, asignar IDs a objetos, filtrar falsos positivos, registrar eventos, proteger la privacidad y estar preparado para crecer hacia producción. Esta guía muestra una arquitectura práctica con Python, OpenCV, YOLO y tracking en tiempo real.

Por Equipo Starbyte

Visión por computadora profesional con Python: cámara, detección de objetos, tracking y eventos con YOLO

Visión por computadora profesional con Python: cámara, detección de objetos, tracking y eventos con YOLO

Problema real: detectar objetos no basta para un proyecto serio

Muchos tutoriales de visión por computadora muestran una webcam, algunos cuadros sobre la imagen y un mensaje como “persona detectada”. Eso sirve para aprender, pero no alcanza para un proyecto serio.

Un sistema profesional necesita responder preguntas más importantes:

  • ¿Qué objeto fue detectado?
  • ¿Con qué nivel de confianza?
  • ¿Durante cuánto tiempo apareció?
  • ¿Entró o salió de una zona?
  • ¿Es el mismo objeto en varios frames o son objetos distintos?
  • ¿Cuántas veces ocurrió el evento?
  • ¿Se debe guardar evidencia?
  • ¿Cómo evitar falsos positivos?
  • ¿Qué pasa si la cámara se desconecta?
  • ¿Cómo se protege la privacidad de las personas?
  • ¿Cómo se deja registro para auditoría o análisis?

Por eso, esta guía no será solo “abrir la cámara y detectar”. El objetivo es construir una base profesional para un sistema de visión por computadora usando Python, OpenCV, YOLO y tracking.


Qué vas a construir

Construiremos un prototipo profesional con estas capacidades:

  1. Captura de cámara con OpenCV.
  2. Detección de objetos con YOLO.
  3. Seguimiento de objetos con IDs persistentes.
  4. Filtrado por clases relevantes.
  5. Zona de interés.
  6. Registro de eventos en CSV.
  7. Captura de evidencia.
  8. Métricas básicas de rendimiento.
  9. Buenas prácticas de privacidad.
  10. Estructura lista para crecer.

Diferencia entre demo y sistema serio

Demo básica Sistema más serio
Solo muestra cámara Controla errores de cámara
Dibuja cuadros Registra eventos
Detecta todo Filtra clases importantes
No guarda evidencia Guarda capturas controladas
No mide rendimiento Muestra FPS y tiempos
No distingue objetos Usa tracking con IDs
No define zonas Usa áreas de interés
No considera privacidad Aplica reglas de protección
Funciona solo en condiciones ideales Maneja fallos y reconexión

La diferencia no está solo en el modelo. Está en la arquitectura.


Herramientas que usaremos

Herramienta Uso
Python Lenguaje principal
OpenCV Captura de video, dibujo y ventanas
Ultralytics YOLO Detección de objetos y tracking
ByteTrack / BoT-SORT Seguimiento de objetos entre frames
CSV Registro simple de eventos
Webcam o cámara IP Fuente de video
Entorno virtual Aislar dependencias

OpenCV ofrece VideoCapture para capturar video desde cámaras, archivos o secuencias de imágenes. Ultralytics YOLO incluye modos para detección, tracking, segmentación, clasificación y pose; su modo track permite seguimiento multiobjeto en video y streams en tiempo real usando algoritmos como ByteTrack o BoT-SORT.


Requisitos previos

Necesitas:

  • Python 3.10 o superior.
  • Webcam o cámara IP.
  • Windows, Linux o macOS.
  • Conexión a internet para instalar paquetes y descargar el modelo inicial.
  • Conocimientos básicos de terminal.
  • Equipo con al menos 8 GB de RAM.
  • GPU opcional, pero recomendable para cargas más pesadas.

Verifica Python:

python --version

o en Windows:

py --version

Paso 1: crea la estructura del proyecto

Crea una carpeta de trabajo:

mkdir vision-profesional-yolo
cd vision-profesional-yolo

Estructura recomendada:

vision-profesional-yolo/
├── app.py
├── config.py
├── requirements.txt
├── eventos/
├── evidencias/
└── modelos/

Crea carpetas:

mkdir eventos evidencias modelos

Paso 2: crea un entorno virtual

En Windows:

py -m venv .venv
.\.venv\Scripts\activate

En Linux o macOS:

python3 -m venv .venv
source .venv/bin/activate

Paso 3: instala dependencias

Crea el archivo:

requirements.txt

Contenido:

opencv-python
ultralytics
numpy

Instala:

pip install -r requirements.txt

Verifica:

python -c "import cv2; print('OpenCV:', cv2.__version__)"
python -c "from ultralytics import YOLO; print('YOLO listo')"

Paso 4: define configuración separada

No mezcles toda la configuración dentro del script principal. Crea:

config.py

Contenido:

# Fuente de video:
# 0 = webcam principal
# también puede ser una URL RTSP de cámara IP
FUENTE_VIDEO = 0

# Modelo YOLO recomendado para iniciar.
# yolov8n.pt es rápido; yolov8s.pt mejora precisión.
MODELO_YOLO = "yolov8n.pt"

# Confianza mínima de detección
CONF_MINIMA = 0.50

# Clases de interés usando nombres COCO
CLASES_INTERES = {"person", "cell phone", "laptop", "backpack"}

# Guardar evidencia cuando haya evento relevante
GUARDAR_EVIDENCIA = True

# Carpeta de evidencias
CARPETA_EVIDENCIAS = "evidencias"

# Carpeta de eventos
CARPETA_EVENTOS = "eventos"

# Mostrar ventana de monitoreo
MOSTRAR_VIDEO = True

# Resolución de captura recomendada para prototipo
ANCHO_FRAME = 1280
ALTO_FRAME = 720

# Tracking: botsort.yaml o bytetrack.yaml
TRACKER = "bytetrack.yaml"

Ventaja:

Si luego cambias cámara, modelo o clases, no rompes el código principal.


Paso 5: crea el sistema principal

Crea:

app.py

Código completo:

import csv
import time
from datetime import datetime
from pathlib import Path

import cv2
from ultralytics import YOLO

from config import (
    FUENTE_VIDEO,
    MODELO_YOLO,
    CONF_MINIMA,
    CLASES_INTERES,
    GUARDAR_EVIDENCIA,
    CARPETA_EVIDENCIAS,
    CARPETA_EVENTOS,
    MOSTRAR_VIDEO,
    ANCHO_FRAME,
    ALTO_FRAME,
    TRACKER,
)


def crear_carpetas():
    Path(CARPETA_EVIDENCIAS).mkdir(exist_ok=True)
    Path(CARPETA_EVENTOS).mkdir(exist_ok=True)


def ruta_csv_eventos():
    fecha = datetime.now().strftime("%Y%m%d")
    return Path(CARPETA_EVENTOS) / f"eventos_{fecha}.csv"


def inicializar_csv():
    ruta = ruta_csv_eventos()
    if not ruta.exists():
        with open(ruta, "w", newline="", encoding="utf-8") as f:
            writer = csv.writer(f)
            writer.writerow([
                "timestamp",
                "track_id",
                "clase",
                "confianza",
                "x1",
                "y1",
                "x2",
                "y2",
                "evidencia"
            ])


def registrar_evento(track_id, clase, confianza, bbox, evidencia=""):
    x1, y1, x2, y2 = bbox
    timestamp = datetime.now().isoformat(timespec="seconds")

    with open(ruta_csv_eventos(), "a", newline="", encoding="utf-8") as f:
        writer = csv.writer(f)
        writer.writerow([
            timestamp,
            track_id,
            clase,
            round(float(confianza), 4),
            int(x1),
            int(y1),
            int(x2),
            int(y2),
            evidencia
        ])


def guardar_evidencia(frame, clase, track_id):
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    nombre = f"{timestamp}_{clase}_id{track_id}.jpg"
    ruta = Path(CARPETA_EVIDENCIAS) / nombre
    cv2.imwrite(str(ruta), frame)
    return str(ruta)


def dibujar_zona_interes(frame):
    alto, ancho = frame.shape[:2]

    # Zona central de ejemplo
    x1 = int(ancho * 0.20)
    y1 = int(alto * 0.20)
    x2 = int(ancho * 0.80)
    y2 = int(alto * 0.85)

    cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 180, 0), 2)
    cv2.putText(
        frame,
        "Zona de interes",
        (x1, y1 - 10),
        cv2.FONT_HERSHEY_SIMPLEX,
        0.7,
        (255, 180, 0),
        2,
    )

    return (x1, y1, x2, y2)


def centro_en_zona(bbox, zona):
    x1, y1, x2, y2 = bbox
    zx1, zy1, zx2, zy2 = zona

    cx = int((x1 + x2) / 2)
    cy = int((y1 + y2) / 2)

    return zx1 <= cx <= zx2 and zy1 <= cy <= zy2


def main():
    crear_carpetas()
    inicializar_csv()

    modelo = YOLO(MODELO_YOLO)

    camara = cv2.VideoCapture(FUENTE_VIDEO)

    if not camara.isOpened():
        raise RuntimeError("No se pudo abrir la fuente de video.")

    camara.set(cv2.CAP_PROP_FRAME_WIDTH, ANCHO_FRAME)
    camara.set(cv2.CAP_PROP_FRAME_HEIGHT, ALTO_FRAME)

    eventos_registrados = set()
    tiempo_inicio = time.time()
    frames = 0

    print("Sistema iniciado. Presiona Q para salir.")

    while True:
        ret, frame = camara.read()

        if not ret:
            print("No se pudo leer frame. Reintentando...")
            time.sleep(1)
            continue

        frames += 1
        zona = dibujar_zona_interes(frame)

        resultados = modelo.track(
            frame,
            persist=True,
            conf=CONF_MINIMA,
            tracker=TRACKER,
            verbose=False
        )

        if resultados and resultados[0].boxes is not None:
            boxes = resultados[0].boxes

            for box in boxes:
                clase_id = int(box.cls[0])
                clase = modelo.names[clase_id]
                confianza = float(box.conf[0])

                if clase not in CLASES_INTERES:
                    continue

                x1, y1, x2, y2 = box.xyxy[0].tolist()
                bbox = (x1, y1, x2, y2)

                track_id = "sin_id"
                if box.id is not None:
                    track_id = int(box.id[0])

                dentro_zona = centro_en_zona(bbox, zona)

                color = (0, 255, 0) if dentro_zona else (0, 180, 255)

                cv2.rectangle(
                    frame,
                    (int(x1), int(y1)),
                    (int(x2), int(y2)),
                    color,
                    2
                )

                etiqueta = f"{clase} ID:{track_id} {confianza:.2f}"
                cv2.putText(
                    frame,
                    etiqueta,
                    (int(x1), max(20, int(y1) - 10)),
                    cv2.FONT_HERSHEY_SIMPLEX,
                    0.6,
                    color,
                    2
                )

                if dentro_zona:
                    clave_evento = (track_id, clase)

                    if clave_evento not in eventos_registrados:
                        evidencia = ""

                        if GUARDAR_EVIDENCIA:
                            evidencia = guardar_evidencia(frame, clase, track_id)

                        registrar_evento(
                            track_id=track_id,
                            clase=clase,
                            confianza=confianza,
                            bbox=bbox,
                            evidencia=evidencia
                        )

                        eventos_registrados.add(clave_evento)

        tiempo_transcurrido = time.time() - tiempo_inicio
        fps = frames / tiempo_transcurrido if tiempo_transcurrido > 0 else 0

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

        if MOSTRAR_VIDEO:
            cv2.imshow("Vision profesional con YOLO - Q para salir", frame)

            if cv2.waitKey(1) & 0xFF == ord("q"):
                break

    camara.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

Ejecuta:

python app.py

Qué hace este sistema

Este prototipo:

  1. Abre la cámara.
  2. Ejecuta YOLO sobre cada frame.
  3. Realiza tracking con IDs.
  4. Filtra clases importantes.
  5. Dibuja una zona de interés.
  6. Detecta si el centro del objeto entra en esa zona.
  7. Registra el evento en CSV.
  8. Guarda evidencia en imagen.
  9. Muestra FPS.
  10. Mantiene configuración separada.

Esto ya se parece más a una base profesional que a una demo simple.


Paso 6: usar cámara IP o RTSP

Si tienes una cámara IP, cambia en config.py:

FUENTE_VIDEO = "rtsp://usuario:password@192.168.1.50:554/stream1"

Ejemplos comunes:

rtsp://usuario:clave@IP:554/stream1
rtsp://usuario:clave@IP:554/live
rtsp://usuario:clave@IP:554/cam/realmonitor?channel=1&subtype=0

Depende del fabricante.

Recomendaciones:

  • Usa red cableada si es posible.
  • Evita exponer cámaras directamente a internet.
  • Cambia contraseñas por defecto.
  • Usa VPN si necesitas acceso remoto.
  • Prueba primero con VLC para confirmar el stream.

Paso 7: elegir modelo según el caso

Modelo Uso recomendado
yolov8n.pt Prototipo rápido, laptop común
yolov8s.pt Mejor equilibrio entre precisión y velocidad
yolov8m.pt Más precisión, requiere mejor hardware
yolov8l.pt Mayor precisión, más pesado
Modelo entrenado propio Objetos específicos del proyecto

Para producción, no basta con usar un modelo general. Si necesitas detectar cascos, chalecos, placas, herramientas, uniformes o productos específicos, probablemente necesitarás entrenar un modelo personalizado.


Paso 8: definir clases útiles

No detectes todo. Detecta solo lo necesario.

Ejemplo para seguridad básica:

CLASES_INTERES = {"person", "backpack", "cell phone"}

Ejemplo para oficina:

CLASES_INTERES = {"person", "laptop", "cell phone", "chair"}

Ejemplo para control de aforo:

CLASES_INTERES = {"person"}

Menos clases relevantes significa:

  • Menos ruido.
  • Menos eventos falsos.
  • Más claridad en reportes.
  • Mejor rendimiento visual.

Paso 9: registrar eventos, no todos los frames

Un error común es guardar una imagen por cada frame detectado. Eso llena el disco y genera datos inútiles.

Mejor registra eventos.

Ejemplo de evento:

2026-05-13 10:34:12 | person | ID 7 | entró a zona de interés | evidencia.jpg

Esto es más útil que guardar miles de imágenes repetidas.


Paso 10: medir rendimiento

Un sistema serio debe medir al menos:

Métrica Por qué importa
FPS Indica fluidez
Latencia Tiempo de respuesta
Falsos positivos Detecciones incorrectas
Falsos negativos Objetos no detectados
Uso de CPU/GPU Capacidad del equipo
Tamaño de evidencias Control de almacenamiento
Tiempo activo Estabilidad del sistema

Si el sistema funciona a 4 FPS, puede servir para análisis lento, pero quizá no para monitoreo en tiempo real.


Paso 11: evitar falsos positivos

Técnicas prácticas:

  1. Subir confianza mínima:
CONF_MINIMA = 0.65
  1. Filtrar clases.
  2. Definir zona de interés.
  3. Registrar evento solo si dura varios frames.
  4. Mejorar iluminación.
  5. Ajustar ángulo de cámara.
  6. Usar modelo más preciso.
  7. Entrenar modelo propio.
  8. Usar tracking para no duplicar eventos.
  9. Revisar evidencias manualmente en fase piloto.

Paso 12: agregar persistencia mínima de evento

Para evitar registrar algo que apareció solo un frame, puedes exigir persistencia.

Ejemplo conceptual:

Solo registrar evento si el objeto aparece en la zona durante 10 frames consecutivos.

Esto reduce falsas alertas por sombras, reflejos o detecciones momentáneas.


Paso 13: privacidad por diseño

Si el sistema procesa personas, debes considerar privacidad desde el inicio.

Buenas reglas:

  • No grabar audio si no es necesario.
  • No guardar video continuo si basta con eventos.
  • No identificar personas si solo necesitas contarlas.
  • Desenfocar rostros si no son necesarios.
  • Informar si hay monitoreo.
  • Limitar acceso a evidencias.
  • Definir tiempo de retención.
  • Evitar subir imágenes sensibles a servicios externos.
  • Cumplir normativa de datos personales aplicable.
  • Documentar finalidad del sistema.

Diferencia importante:

Acción Nivel de riesgo
Detectar que hay una persona Menor
Identificar quién es la persona Mucho mayor
Guardar rostro asociado a nombre Alto
Cruzar con base de datos biométrica Muy alto

Paso 14: no confundir detección facial con reconocimiento facial

Este post se enfoca en detección y tracking de objetos.

Concepto Significado
Detección de rostro Saber que hay una cara en la imagen
Reconocimiento facial Identificar de quién es la cara
Detección de objetos Detectar clases como persona, celular o laptop
Tracking Mantener un ID del objeto entre frames

Para proyectos serios, evita reconocimiento facial de identidad salvo que tengas base legal, consentimiento, seguridad, finalidad clara y controles estrictos.


Caso práctico 1: control de aforo

Objetivo:

Contar personas que entran en una zona.

Configuración:

CLASES_INTERES = {"person"}
CONF_MINIMA = 0.60

Reglas:

  • Cámara fija.
  • Zona de interés en entrada.
  • Tracking activo.
  • Registrar persona solo una vez por ID.
  • No guardar rostros si no es necesario.

Uso:

  • Oficinas.
  • Eventos.
  • Laboratorios.
  • Salas de espera.
  • Aulas.

Caso práctico 2: detección de celulares en área restringida

Objetivo:

Detectar uso visible de celulares en una zona.

Configuración:

CLASES_INTERES = {"cell phone"}
CONF_MINIMA = 0.50

Advertencia:

YOLO puede fallar con celulares pequeños o parcialmente ocultos. Para un proyecto serio, probablemente necesites:

  • Cámara cercana.
  • Buena resolución.
  • Dataset propio.
  • Entrenamiento adicional.
  • Validación humana.
  • Política clara de privacidad.

Caso práctico 3: detección de EPP en obra

Objetivo:

Detectar casco o chaleco.

Problema:

Los modelos generales normalmente no son suficientes para EPP específico.

Solución profesional:

  1. Recolectar imágenes del entorno real.
  2. Etiquetar casco, chaleco, botas u otros elementos.
  3. Entrenar modelo YOLO personalizado.
  4. Validar con datos no usados en entrenamiento.
  5. Probar en cámara real.
  6. Medir falsos positivos y falsos negativos.
  7. Definir umbral de confianza.
  8. Integrar alertas.

Caso práctico 4: monitoreo de objetos en almacén

Objetivo:

Detectar presencia de cajas, pallets, personas o vehículos.

Recomendaciones:

  • Cámara fija.
  • Buena iluminación.
  • Zonas de interés.
  • Clases bien definidas.
  • Registro por evento.
  • Validación manual en fase piloto.
  • Integración posterior con base de datos.

Errores comunes y soluciones

Error 1: usar la webcam de prueba como si fuera producción

Solución:

Prueba con la cámara real, ubicación real, iluminación real y ángulo real.


Error 2: detectar todas las clases

Solución:

Filtra solo lo que realmente importa.


Error 3: guardar video continuo sin necesidad

Solución:

Guarda eventos y evidencias puntuales.


Error 4: no medir falsos positivos

Solución:

Durante el piloto, revisa cada evento y clasifica si fue correcto o incorrecto.


Error 5: usar reconocimiento facial sin base clara

Solución:

Si solo necesitas contar personas, no identifiques personas.


Error 6: no controlar desconexión de cámara

Solución:

Agrega reconexión, logs y monitoreo del proceso.


Error 7: no separar configuración del código

Solución:

Usa config.py o archivo .yaml.


Buenas prácticas profesionales

  1. Define el objetivo antes de elegir modelo.

  2. Usa cámara y escenario reales desde el piloto.

  3. Filtra clases relevantes.

  4. Usa tracking para evitar duplicados.

  5. Registra eventos, no todos los frames.

  6. Mide FPS, falsos positivos y falsos negativos.

  7. Evita reconocimiento biométrico si no es necesario.

  8. Aplica privacidad por diseño.

  9. Entrena modelo propio si los objetos son específicos.

  10. Documenta configuración, modelo y versión.


Checklist para considerar el sistema “serio”

Revisión Estado
Objetivo definido
Cámara real probada
Modelo elegido por rendimiento y precisión
Tracking activo
Zona de interés definida
Eventos registrados
Evidencias guardadas de forma controlada
Falsos positivos medidos
Privacidad evaluada
Logs disponibles
Configuración separada
Prueba piloto ejecutada

Próximos pasos para producción

Si quieres pasar de prototipo a producción, considera:

  • Ejecutarlo como servicio.
  • Guardar eventos en SQLite o PostgreSQL.
  • Crear dashboard web.
  • Agregar autenticación.
  • Usar Docker.
  • Implementar logs rotativos.
  • Integrar alertas por correo o Telegram.
  • Usar GPU o edge device.
  • Entrenar modelo propio.
  • Definir política de retención de evidencias.
  • Documentar consentimiento y finalidad.

Idea clave

Un proyecto serio de visión por computadora no se mide solo por detectar objetos, sino por convertir detecciones en eventos confiables, trazables y útiles. La combinación de OpenCV, YOLO, tracking, zonas de interés, registro de eventos y privacidad por diseño permite construir una base profesional sobre la cual sí se puede crecer hacia producción.

Etiquetas: #python #opencv #yolo #vision-por-computadora #deteccion-de-objetos #tracking #bytetrack #bot-sort #camara-ip #inteligencia-artificial #computer-vision