Computer VisionIA

Cómo funciona un contador de personas por video: YOLO, tracking y cruce de línea

Alejandro Chain

Alejandro Chain

Analista

15 min de lectura visitas
Cómo funciona un contador de personas por video: YOLO, tracking y cruce de línea

Este es el anexo técnico de Contá cuánta gente entra a tu local con la cámara que ya tenés. Si buscabas la guía práctica para poner a andar el contador, empezá por ahí. Acá bajamos al detalle de ingeniería.

Explicamos, de punta a punta, cómo un sistema simple convierte el video de una cámara WiFi común en un conteo de personas que entran y salen. Lenguaje técnico, pero pensado para que se entienda.

1. El recorrido completo (pipeline)

Todo el sistema es una cadena de pasos. Cada frame de video pasa por acá:

  Cámara WiFi
      │  (video por RTSP, red local)

  [1] Captura de frames  ──►  imagen (una foto cada ~1/15 seg)

  [2] Detección (YOLO)   ──►  "hay personas acá, acá y acá" (cajas + confianza)

  [3] Seguimiento (tracker) ─► "esta persona es la MISMA que en el frame anterior" (#ID)

  [4] Lógica de conteo   ──►  ¿algún ID cruzó la línea? ¿en qué sentido?

  [5] Registro           ──►  fila en CSV / Google Sheets (entrada o salida)

Las tres piezas interesantes son la [2] detección, el [3] seguimiento y la [4] lógica de conteo. El resto es “plomería” (importante, pero conocida).

2. Cómo llega el video: RTSP

Las cámaras IP (incluidas las chinas baratas tipo iCSee, V380, Yoosee) transmiten video en la red local con un protocolo estándar: RTSP (Real-Time Streaming Protocol), casi siempre en el puerto 554. La URL tiene esta forma:

rtsp://usuario:clave@192.168.1.50:554/ruta_del_stream

Dos detalles prácticos que aparecen en el mundo real:

  • La contraseña del dispositivo no es la de la app. La app (iCSee, etc.) usa una cuenta en la nube; RTSP valida contra la contraseña local de la cámara. Son cosas distintas y es la causa #1 de “no me conecta”.
  • Forzar TCP. RTSP puede ir por UDP (más rápido, pero se “pixela” y pierde paquetes en WiFi) o TCP (estable). Forzamos TCP para que la imagen no se rompa.

La mayoría de estas cámaras dan dos calidades: un stream principal (alta resolución, pesado) y un sub-stream (baja resolución, liviano). Para contar personas usamos el sub-stream: alcanza de sobra y consume mucho menos.

3. Detección de objetos: qué hace YOLO

3.1. Detección ≠ clasificación

  • Clasificar una imagen responde: “¿qué hay?” → “hay una persona”. Una etiqueta para toda la foto.
  • Detectar responde: “¿qué hay y DÓNDE?” → “hay una persona en este rectángulo, otra en aquel, con esta confianza cada una”.

Para contar necesitamos detección: nos importa la posición de cada persona (su rectángulo, o bounding box), no solo saber que hay gente.

3.2. Por qué se llama YOLO

YOLO = “You Only Look Once” (mirás una sola vez). Es el nombre de una familia de modelos de detección. La idea que lo hizo famoso:

  • Los métodos viejos eran de dos etapas: primero proponían cientos de regiones “candidatas” y después clasificaban cada una. Preciso, pero lento.
  • YOLO lo hace en una sola pasada de una red neuronal: divide la imagen en una grilla y, para cada celda, predice al mismo tiempo dónde hay objetos (las cajas) y qué son (la clase) y con qué confianza. Una imagen entra, todas las detecciones salen, de un saque.

Esa “una sola mirada” es lo que lo hace rápido, y por eso sirve para tiempo real (video), que es justo lo que necesitamos.

Por dentro es una red neuronal convolucional (CNN): capas que aprenden a reconocer, primero bordes y texturas, y en capas más profundas, formas y objetos completos (la silueta de una persona, por ejemplo).

3.3. No entrenamos nada: usamos un modelo preentrenado

Acá está la clave de por qué esto es “fácil”: no entrenamos ningún modelo. Usamos pesos ya entrenados sobre COCO, un dataset público con ~330.000 imágenes etiquetadas en 80 categorías cotidianas (personas, autos, sillas, perros…).

  • Un “peso” (archivo .pt) es el modelo ya aprendido: los millones de números que la red ajustó durante el entrenamiento. Lo descargás y ya “sabe” ver personas.
  • De las 80 clases de COCO, a nosotros nos interesa solo la clase 0 = person. Le decimos al modelo “reportá únicamente personas” y listo.

3.4. Qué significan “26”, los tamaños, y los parámetros

  • YOLO26 es simplemente la versión/generación del modelo (cada versión mejora precisión y velocidad). Usamos la implementación de la librería Ultralytics, que empaqueta todo esto en pocas líneas de código.
  • Cada versión viene en tamaños: n (nano) → smlx. Es un balance velocidad ↔ precisión: el nano es el más chico y veloz (ideal para correr local y en tiempo real), el x es el más preciso pero pesado. Nosotros usamos yolo26n (nano).
  • Dos “perillas” que ajustamos:
    • conf (confianza): umbral mínimo para aceptar una detección. Bajo = detecta más pero con más falsos positivos; alto = más estricto.
    • imgsz: a qué resolución se analiza cada frame. Más grande = ve mejor lo chico/lejano, pero más lento.

3.5. Corre 100% local (y eso importa)

El modelo corre en la misma máquina, sin mandar video a ninguna nube:

  • Privacidad: el video nunca sale del local. Para un negocio, esto es enorme.
  • Costo: no se paga por API ni por frame procesado.
  • Hardware: la inferencia usa la GPU si hay (Apple Silicon vía mps, o NVIDIA vía CUDA) y si no, la CPU. El sistema lo detecta solo. En CPU va más lento (unos pocos frames por segundo), pero para gente caminando alcanza.

4. Seguimiento (tracking): mantener la identidad

La detección trabaja frame por frame, y es “amnésica”: en cada frame te da cajas nuevas, sin saber que “la persona de arriba a la izquierda es la misma que en el frame anterior”. Para contar cruces necesitamos seguir a cada persona a lo largo del tiempo — o sea, darle un ID estable.

De eso se encarga el tracker. Usamos ByteTrack, que funciona así:

  1. Predice dónde debería estar cada persona ya conocida en el nuevo frame (con un filtro de Kalman, que modela el movimiento: si venías yendo a la derecha, seguís yendo a la derecha).
  2. Asocia las detecciones nuevas con las personas que venía siguiendo, emparejando por cercanía y superposición de cajas (métrica IoU). Ese emparejamiento óptimo es un problema de asignación lineal (lo resuelve el paquete lap).
  3. Lo distintivo de ByteTrack: también usa las detecciones de baja confianza para no “perder” a alguien que por un instante quedó medio tapado. Eso da IDs más estables.

Resultado: cada persona lleva un #ID consistente frame a frame. Ahora sí podemos seguir su trayectoria y preguntarnos si cruzó la línea.

5. La lógica de conteo por cruce de línea

Definimos una línea virtual (un segmento A-B) sobre el umbral de la puerta. Para cada persona seguimos un punto de referencia: elegimos los pies (el centro de la base de su caja), porque es lo que realmente “pisa” el umbral —contar por el centro del cuerpo daría cruces adelantados o atrasados.

En cada frame comparamos la posición anterior y la actual de cada #ID:

  • ¿Cruzó? Chequeamos si el segmento de su movimiento (anterior → actual) se interseca con el segmento de la línea. Matemáticamente se resuelve con el signo del producto cruzado: nos dice de qué lado de la línea está un punto. Si entre un frame y otro el punto cambió de lado y el cruce cae dentro del segmento (no en su prolongación), hubo cruce real.
  • ¿En qué sentido? El lado desde el que venía define si es entrada o salida. Un parámetro invertir permite dar vuelta el criterio si quedó al revés (por la orientación de la cámara).
  • Filtro anti-ruido (min_historia): una detección tiene que haberse visto algunos frames seguidos antes de poder contar. Esto descarta parpadeos y falsos positivos fugaces.

Es geometría simple sobre trayectorias confiables — y funciona justamente porque el tracker nos da esas trayectorias.

6. Cómo se integra todo (arquitectura)

Piezas de software, cada una con una responsabilidad:

  • Lectura de video en un hilo aparte. La red puede entregar frames con latencia; si leyéramos “en línea” con el resto, la interfaz se trabaría. Un hilo dedicado mantiene siempre “el último frame disponible” y el resto trabaja sobre eso.
  • Configuración en un archivo YAML (cámara, línea, sensibilidad, destino de los datos), que además se relee en caliente: podés mover la línea o cambiar el sentido sin reiniciar nada.
  • Registro. Cada cruce se escribe siempre en un CSV local (fuente de verdad, a prueba de cortes de red) y, opcionalmente, se sube a Google Sheets por lotes (para no golpear la cuota de la API).
  • Dos modos de uso:
    • Asistente web: un servidor local muestra el video anotado en el navegador (streaming MJPEG) con los contadores en vivo. Ideal para configurar y demostrar.
    • Modo headless (segundo plano): sin ventana ni web, solo el conteo. Consume menos y se deja corriendo todo el día.
  • Multiplataforma: lanzadores de doble clic para Mac y Windows; el navegador lo abre el propio programa; el hardware (GPU/CPU) se detecta automáticamente.

7. Rendimiento y límites (lo honesto)

  • Velocidad: con GPU, tiempo real cómodo. En CPU pura (una PC de local sin placa de video) bajan los FPS; para gente caminando por una puerta alcanza, pero conviene procesar 1 de cada N frames y usar el sub-stream.
  • Ángulo de cámara: lo ideal es una vista bastante cenital sobre la puerta. Muy de costado, la gente se tapa entre sí (oclusión) y se cuenta peor.
  • La línea, ni al borde ni sobre un obstáculo: dejar aire a ambos lados para que el tracker “vea” a la persona antes y después de cruzar.
  • No es infalible: dos personas muy juntas pueden fusionarse en una caja; alguien que se queda justo sobre la línea puede generar dobles conteos. Se mitiga con la posición de la línea, min_historia y el umbral de confianza.

8. Para profundizar (técnico avanzado)

Esta sección es opcional y baja al detalle de ingeniería. Podés saltearla si solo querés la idea general.

8.1. Anatomía de un detector YOLO

Una red YOLO moderna tiene tres bloques:

  • Backbone — extrae features (características) de la imagen. Es una CNN que, capa a capa, va de píxeles crudos a representaciones cada vez más abstractas (bordes → texturas → partes → objetos). Reduce resolución espacial y aumenta “profundidad semántica”.
  • Neck — fusiona features de distintas escalas (típicamente estructuras tipo FPN + PAN). ¿Por qué? Porque una persona cercana ocupa muchos píxeles y una lejana muy pocos: combinar escalas permite detectar objetos grandes y chicos con la misma red.
  • Head — la capa de salida que produce, por cada ubicación, las cajas (coordenadas), la clase y un score de confianza.

Las YOLO actuales son anchor-free: en vez de partir de “cajas ancla” de tamaños predefinidos, predicen la geometría de la caja directamente (por ejemplo, la distancia de cada punto a los cuatro lados de la caja). Menos hiperparámetros, menos cajas redundantes.

Un detalle de las versiones nuevas: tienden a ser NMS-free o a integrar el post-proceso, lo que baja la latencia (ver 8.2).

8.2. De la salida cruda al resultado: IoU y NMS

La red no escupe “3 personas” directamente: produce muchísimas cajas candidatas solapadas para el mismo objeto. Hacen falta dos herramientas:

  • IoU (Intersection over Union): métrica de cuánto se solapan dos cajas = (área de intersección) / (área de unión). 1 = idénticas, 0 = no se tocan. Es la regla con la que se decide “estas dos cajas son el mismo objeto”.
  • NMS (Non-Max Suppression): de un grupo de cajas muy solapadas (IoU alto) para el mismo objeto, se queda con la de mayor score y descarta el resto. Así, de 200 cajas candidatas quedan las 3 personas reales.

(Cuando el modelo es “NMS-free”, aprende a no generar esos duplicados y se ahorra este paso — más rápido en producción.)

8.3. Cómo se entrena (aunque nosotros no entrenemos)

Nosotros usamos pesos preentrenados, pero conviene saber qué hay detrás:

  • Aprendizaje supervisado: se le muestran imágenes con las cajas correctas dibujadas a mano (las labels). La red predice, se mide el error y se ajustan los pesos por descenso de gradiente (backpropagation), millones de veces.
  • Función de pérdida (loss) compuesta por tres términos: error de caja (qué tan lejos está la caja predicha de la real, con IoU loss tipo CIoU/DFL), error de clasificación (clase correcta) y error de objetividad/score.
  • Data augmentation: durante el entrenamiento las imágenes se transforman (recortes, cambios de color, y el clásico mosaic que pega 4 imágenes en una) para que el modelo generalice mejor y no memorice.
  • Transfer learning / fine-tuning: este es el punto comercial. Se puede tomar el modelo preentrenado y reentrenarlo con datos propios (ej.: imágenes de tu local, o para detectar “empleado con uniforme” vs “cliente”). Con pocos cientos de ejemplos etiquetados ya se logra especializar el detector. Acá es donde una consultora aporta: armar el dataset, etiquetar, entrenar y validar.

8.4. Métricas: cómo se mide si un detector es “bueno”

  • Precision: de lo que detecté, ¿cuánto era correcto? (penaliza falsos positivos).
  • Recall: de lo que había, ¿cuánto detecté? (penaliza falsos negativos).
  • Una detección “cuenta como acierto” si su IoU con la caja real supera un umbral (ej. 0.5).
  • mAP (mean Average Precision): la métrica estándar. Resume el balance precision/recall promediado sobre las clases.
    • mAP@0.5 — con umbral de IoU 0.5 (más permisivo).
    • mAP@0.5:0.95 — promedio sobre umbrales de 0.5 a 0.95 (mucho más exigente con la precisión de la caja). Es el número “serio” con el que se comparan modelos.
  • Latencia / FPS: cuántos frames por segundo procesa. El trade-off de siempre: los modelos con más mAP suelen tener menos FPS. Elegir tamaño (n/s/m/l/x) es elegir un punto en esa curva.

8.5. ByteTrack en detalle

El tracker mantiene un conjunto de tracks, cada uno con un estado estimado por un filtro de Kalman (posición y velocidad de la caja). Por cada frame:

  1. Predice el nuevo estado de cada track (dónde debería estar).
  2. Asocia en dos rondas (la idea central de ByteTrack):
    • Primero empareja los tracks con las detecciones de alta confianza (costo = 1 − IoU, resuelto como asignación óptima con el algoritmo húngaro / lap).
    • Después, con los tracks que quedaron sin pareja, intenta emparejarlos con las detecciones de baja confianza. Esto “rescata” a alguien momentáneamente ocluido o mal detectado, que otros trackers descartarían → menos cambios de ID.
  3. Ciclo de vida: las detecciones nuevas no emparejadas crean tracks tentativos; un track que no se ve por N frames se da de baja.

Que el #ID sea estable es crítico para el conteo: si a una persona se le cambia el ID en mitad del cruce, se puede contar de más o de menos.

8.6. El video por dentro (por qué a veces “cuesta”)

  • El stream viene comprimido en H.264/H.265. No todos los frames son completos: hay keyframes (I-frames) completos y, entre ellos, frames que solo guardan lo que cambió. Por eso, al conectarse, a veces el primer frame llega “roto” hasta el siguiente keyframe (por eso descartamos los primeros frames al abrir).
  • UDP vs TCP: UDP no reenvía lo que se pierde → artefactos y bloques verdes en WiFi con interferencia. TCP garantiza el orden y la integridad a costa de algo de latencia. Elegimos TCP.
  • Buffer chico: preferimos el frame más nuevo antes que acumular una cola que agregue retardo — para conteo importa el “ahora”, no reproducir todo.

8.7. Optimización y despliegue

Para exprimir más rendimiento, sobre todo en hardware modesto:

  • Half precision (FP16): usar números de 16 bits en vez de 32 acelera la inferencia en GPU con mínima pérdida de precisión.
  • Exportar el modelo a formatos optimizados según la plataforma: ONNX (genérico), TensorRT (NVIDIA), CoreML (Apple), OpenVINO (Intel). Cada runtime aprovecha mejor su hardware.
  • Cuantización (INT8): reducir a enteros de 8 bits para correr más rápido y liviano (útil en dispositivos edge), con una pequeña calibración para no perder exactitud.
  • Procesar 1 de cada N frames y usar el sub-stream: la optimización más barata y la que más rinde en un caso como este.

9. De lo simple a lo serio (dónde entra All4Data)

Lo de arriba es la versión sencilla y gratuita: contar entradas y salidas. A partir de la misma base de detección + tracking se abre todo un abanico de analítica de verdad, que ya requiere ingeniería y criterio de datos:

  • Mapas de calor (heatmaps): qué zonas del local se transitan y se frenan más.
  • Tasa de captación: cuánta gente pasa por afuera vs. cuánta entra (efectividad de vidriera / puerta).
  • Excluir empleados del conteo (por zonas, horarios o re-identificación).
  • Tiempos de permanencia, filas, horas pico, comparativas entre locales.
  • Integración con dashboards, alertas y las herramientas del negocio.

Ahí es donde una consultora de datos convierte un contador simple en información que mueve decisiones. Eso es All4Data.

Alejandro Chain

Alejandro Chain

Analista

"Hay dos formas de hacer las cosas: bien o para el ..."

Compartir

¿Querés aplicar esto en tu empresa?

Contanos tu desafío y lo resolvemos juntos.

Contactanos →