Kanan AI — Arquitectura (iteración 2, orientada a módulos)
Documento vivo. Esta iteración reorganiza la arquitectura alrededor de los seis módulos de seguridad del producto. Principio rector: los seis módulos no son seis pipelines. Comparten una capa de percepción (detección + pose) y cada módulo es, en su mayor parte, una configuración del motor de reglas sobre detecciones comunes. Esto reduce la superficie de mantenimiento, condición crítica para un equipo de CV reducido.
Los seis módulos del producto
- Zonas restringidas (Zone & Access Control) — zonas de exclusión sobre el CCTV; alerta cuando persona o vehículo entra a área prohibida.
- Detección de EPP (PPE Compliance) — casco, chaleco, guantes, calzado; alerta si un operario entra a zona de riesgo sin el equipo correcto.
- Ergonomía (Ergonomic Risk Detection) — análisis de postura; levantamientos incorrectos, sobreesfuerzo, posturas prolongadas.
- Control vehicular (Forklift & Vehicle Safety) — montacargas y vehículos, su interacción con peatones; velocidad, zonas prohibidas, puntos ciegos.
- Conducta segura (Behavioral Safety) — correr en planta, uso de celular en zona operativa, omisión de pasamanos.
- Analytics y reportes (Operational Impact Analysis) — dashboard de incidentes, reportes automáticos, patrones recurrentes y tendencias.
Flujo general
┌─────────────┐ ┌──────────────────────────────────────┐ ┌─────────────────────┐
│ Cámaras │ │ CAPA DE CV (Python) │ │ STACK MERN │
│ (archivo │───▶│ ingesta → PERCEPCIÓN COMPARTIDA → │───▶│ API Node → MongoDB │
│ inicial, │ │ reglas por módulo → eventos limpios │ │ │ │
│ RTSP │ │ │ │ ▼ │
│ posterior) │ │ │ │ Dashboard React │
└─────────────┘ └──────────────────────────────────────┘ │ (Analytics = mód. 6)│
│ └─────────────────────┘
▼ (offline)
┌──────────────────────┐
│ Pipeline de datos │
│ (moat, separado) │
└──────────────────────┘
La capa de CV concluye al producir eventos limpios. El módulo 6 (Analytics) no es un módulo de CV: reside por completo en el stack MERN y consume los eventos que la capa de CV ya entregó.
Capa de percepción compartida
Dos backbones alimentan a casi todos los módulos. La elección de cada uno determina la exposición de licencia de todo el sistema.
| Componente | Tecnología | Licencia | Alternativa permisiva | Alimenta a los módulos |
|---|---|---|---|---|
| Detección de objetos | RF-DETR (Roboflow) — seleccionado | Apache 2.0 ✅ | YOLO26 (AGPL-3.0), mejor tooling/ecosistema | Zonas, EPP, Control vehicular, Conducta (celular, correr) |
| Estimación de pose | YOLO26-pose (Ultralytics) | AGPL-3.0 / Enterprise | MediaPipe (Apache 2.0) · RF-DETR keypoints (Apache 2.0, preview) | Ergonomía, Conducta (correr, pasamanos) |
| Tracking (diferido) | Modo tracking de Ultralytics | AGPL-3.0 / Enterprise | ByteTrack / BoT-SORT (permisivos), desacoplables del detector | Control vehicular, EPP por persona, posturas prolongadas, reincidencia |
Si la prioridad es evitar licencias, la ruta permisiva completa es RF-DETR (detección) + MediaPipe o RF-DETR-keypoints (pose) + ByteTrack (tracking) — todo Apache/MIT, a cambio de fragmentar el pipeline en varias familias. La decisión es legal y de mantenimiento, no puramente técnica, y requiere revisión interna según el modo de despliegue (SaaS vs. on-premise).
Decisión de detección (validada empíricamente en el módulo 1). Se selecciona RF-DETR como backbone de detección. En pruebas sobre footage CCTV de almacén, RF-DETR-Medium detectó más personas que YOLO26-m y que MediaPipe/EfficientDet-Lite2 (9 vs 8 vs 5 en el frame de referencia), con cajas más consistentes en figuras pequeñas/lejanas —donde MediaPipe parpadeaba, produciendo falsos negativos inaceptables para una alerta de seguridad. Rendimiento medido: sobre una RTX 3070 Ti con FP16, ~57 FPS (17 ms/frame) —tiempo real holgado—; en CPU ~4.5 FPS, suficiente para procesamiento por jobs. Al ser Apache 2.0, elimina la exposición AGPL en la capa de detección (ver Pendientes). Nota de implementación: RF-DETR usa la indexación COCO de 91 clases (
person= clase 1). Cifras sujetas a revalidación con footage propio y por módulo.
Mapa módulo → tecnología
| Módulo | Técnica principal | Percepción que usa | ¿Tracking? | ¿Entrenamiento custom? | Tecnología (stack) | Capa | Validado |
|---|---|---|---|---|---|---|---|
| 1. Zonas restringidas | Point-in-polygon sobre detecciones | Detección | No (intrusión simple) | No | RF-DETR + point-in-polygon (OpenCV) | CV | ✅ |
| 2. Detección de EPP | Detección de clases PPE + asociación a persona | Detección | Recomendable (PPE sostenido por persona) | Sí (casco, chaleco, guantes, calzado) | RF-DETR (persona) + modelo de casco YOLOv8 (HF, prototipo) + asociación geométrica · fine-tune EPP propio pendiente | CV | 🟡 casco |
| 3. Ergonomía | Keypoints + cálculo de ángulos + scoring OWAS/RULA/REBA | Pose | Para "posturas prolongadas" (duración) | No para pose; sí para calibrar scoring | Pose † + scoring OWAS/RULA/REBA | CV | — |
| 4. Control vehicular | Detección de vehículos + tracking + estimación de velocidad + reglas espaciales | Detección + tracking | Sí (velocidad, interacción peatón) | Sí (montacargas, vehículos) | RF-DETR (fine-tune vehículos) + tracking † + calibración de cámara | CV | — |
| 5. Conducta segura | Mixto por sub-caso (ver notas) | Detección + pose + tracking | Sí (correr = velocidad) | Sí (celular) | RF-DETR (fine-tune celular) + pose † + tracking † | CV | — |
| 6. Analytics y reportes | Agregación, heatmaps, reportes, tendencias | — (consume eventos) | — | — | React + Node + MongoDB | MERN | — |
Leyenda. ✅ = validado empíricamente en prototipo · 🟡 = prototipo parcial (una sub-capacidad validada) · — = pendiente. † = backbone aún por decidir (pose: MediaPipe / YOLO26-pose / RF-DETR-keypoints · tracking: ByteTrack / BoT-SORT / Ultralytics). La detección ya está fija en RF-DETR para todos los módulos que la usan.
Notas de dificultad y decisiones honestas por módulo
1. Zonas restringidas — el punto de arranque. El más simple y stack-agnóstico: una vez que hay detección de persona/vehículo, la regla es geometría pura (point-in-polygon sobre el punto de "pies" de cada caja — centro-inferior, el punto que pisa el suelo). Funciona por frame, sin tracking. Es el primer módulo a construir; entrega una victoria temprana y valida toda la cadena cámara → detección → regla → evento. Detección: RF-DETR (ver decisión en Capa de percepción compartida). Setup manual de polígonos por cámara (definidos en el frontend; ver Orquestación CV ↔ MERN). Prototipo funcional validado con este backbone.
2. Detección de EPP — el primer módulo que exige dataset propio. Las clases (casco, chaleco, guantes, calzado) requieren entrenamiento custom; aquí empieza de verdad el moat de datos anotados. "Sin EPP en zona de riesgo" combina este módulo con el de zonas. La asociación EPP-a-persona se beneficia de tracking para evitar falsos positivos por frame; sin tracking, la regla es más ruidosa. Guantes y calzado son objetos pequeños y de difícil visibilidad en CCTV picado: esperar degradación, validar con footage.
Prototipo validado (solo casco). Se validó el enfoque de dos modelos + asociación: RF-DETR detecta la persona; un segundo modelo detecta el casco; una regla geométrica los liga. Detalles:
- Modelo de casco (prototipo):
keremberke/yolov8m-hard-hat-detection(Hugging Face), clasesHardhat/NO-Hardhat. Es YOLOv8 → AGPL, aceptable solo para prototipar. La ruta de producción es fine-tune de RF-DETR (Apache) con dataset propio de EPP, cerrando el moat y evitando el AGPL. - Asociación geométrica: por cada persona se calcula su "región de cabeza" (~40% superior de la caja) y se comprueba si el centro de un casco cae ahí. El EPP se razona por persona, no por frame global.
- Tres estados deliberados:
con casco/sin casco/sin dato(no se detectó la cabeza). El tercero es una decisión de diseño de seguridad: "no pude confirmar" ≠ "no trae casco". Evita falsos positivos y falsos negativos silenciosos. - Hallazgo empírico: con footage CCTV lejano, el modelo genérico casi no confirma cabezas descubiertas (
NO-Hardhatdébil) → muchossin dato. Confirma en la práctica que EPP exige dataset propio y footage representativo; un modelo genérico degrada. UnNO-Hardhatno detectado = infracción no reportada, riesgo inaceptable para producción. - Alcance: demo independiente (solo casco). La combinación "sin casco en zona" y el resto de EPP (chaleco, guantes, calzado) quedan para fases posteriores.
3. Ergonomía — pose, no detección. Depende de keypoints y del cálculo de ángulos traducido a scoring ergonómico (OWAS/RULA/REBA). "Posturas prolongadas" introduce el factor tiempo, que requiere seguir a la persona el tiempo suficiente. La confiabilidad de los keypoints bajo ángulos de CCTV es el principal riesgo empírico de este módulo. La API clásica de pose de MediaPipe está deprecada; usar MediaPipe Tasks si se va por esa ruta.
4. Control vehicular — el módulo más complejo, correctamente en Fase 2. Tres dificultades acumuladas: (a) la estimación de velocidad requiere tracking y calibración de cámara (sin calibración, "velocidad" es solo píxeles por frame, no m/s); (b) la interacción montacargas-peatón exige tracking multi-objeto y razonamiento espacial entre dos entidades; (c) "puntos ciegos en cruces" implica modelar geometría de la escena. No es un módulo de MVP; difiérase con su dependencia de tracking explícita.
5. Conducta segura — técnicamente heterogéneo, dividir por sub-caso. No es un módulo único:
- Correr en área operativa → pose + tracking para estimar velocidad de la persona. Viable pero depende de tracking.
- Uso de celular → detección de un objeto pequeño (teléfono) + pose (mano cerca de la cabeza). El teléfono es de los objetos más difíciles de detectar en CCTV; alto riesgo de falsos negativos.
- Omisión de pasamanos → pose + relación espacial mano-barandal en escaleras. Caso de nicho, geometría específica por escena, baja generalización. Candidato a posponer o tratar como prueba de concepto.
Recomendación: este módulo no debe tratarse como una sola entrega. Sus sub-casos tienen dificultad muy dispar y conviene priorizarlos por separado.
6. Analytics y reportes — territorio MERN, con una bifurcación importante. Dashboard, heatmaps, reportes EHS automáticos y tendencias se construyen sobre los eventos en MongoDB, con React y Node; no requieren CV. La excepción es "reincidencia por operario": identificar al mismo operario entre eventos implica re-identificación de personas (re-ID), una capacidad de CV técnicamente difícil y sensible en privacidad. Existe una alternativa no-biométrica (atribución por credencial/badge, por zona o por turno) que evita el re-ID. Esta decisión —re-ID vs. atribución alternativa— debe tomarse de forma consciente y con criterio legal/ético, no resolverse por defecto.
Reparto por fase
- Fase 1 (MVP): Zonas restringidas + Detección de EPP + Ergonomía + Analytics base (dashboard de eventos). Cubre los tres módulos de menor riesgo técnico y la visualización.
- Fase 2: Control vehicular + Conducta segura (sub-casos priorizados) + Analytics avanzado (tendencias, reincidencia, integraciones EHS) + motor de reglas formal. Concentra las dependencias de tracking, calibración y re-ID.
Este reparto coincide con que la Fase 1 evita tracking salvo refinamientos opcionales, mientras que la Fase 2 lo asume como requisito.
Orquestación CV ↔ MERN
El contrato de la sección siguiente define qué datos cruzan de la capa de CV al stack MERN; esta sección define cómo. La capa de CV vive en Python (detección, pose, tracking); el stack de negocio vive en Node. Son dos runtimes distintos: Node no ejecuta modelos; Python no es dueño de la base. El puente entre ambos es el punto de integración crítico.
Dos hechos condicionan el diseño:
- Runtimes separados. Toda la percepción ocurre en Python. Node orquesta, persiste y sirve. La lógica de negocio y el acceso a MongoDB quedan de un solo lado (Node).
- Procesamiento largo. Analizar un video no es una operación de milisegundos (medición interna: ~20 s para un clip de 25 s a 10 análisis/seg en GPU de desarrollo). No cabe en un request HTTP síncrono; obliga a un modelo de trabajos asíncronos (jobs).
Ciclo de vida de un job (ingesta por archivo)
1. Front sube el .mp4 + zona (polígono JSON) → Node guarda archivo y crea Job(status: "processing")
2. Node lanza el worker: spawn python worker.py --id <jobId> --token <secreto>
3. Worker → GET /api/jobs/:id/config → Node responde { zona, rutaVideo, fpsAnalisis }
4. Worker procesa (percepción + reglas del módulo) → produce eventos
5. Worker → POST /api/jobs/:id/result → { eventos[], métricas, artefactos } (con token)
6. Node valida, guarda en Mongo, marca status: "done"
7. Front (polling o WebSocket) ve "done" y renderiza el dashboard
El worker Python solo habla HTTP con Node: recibe su configuración y devuelve su resultado. No necesita credenciales de MongoDB ni conocer el esquema. Esto lo mantiene como componente reemplazable y conserva a Node como único dueño de la base.
Tres garantías operativas mínimas
- Detección de fallo. Como Node hace el
spawn, retiene el handle del proceso y observa su código de salida. Si el worker muere sin hacer el POST final, Node marca el job comoerroren lugar de dejarlo colgado enprocessing. No se depende únicamente del callback del worker. - Autenticación worker → API. El endpoint de resultados no puede estar abierto. Node genera un token por job en el
spawn; el worker lo devuelve en el callback; Node lo valida. Evita inyección de resultados falsos. - Concurrencia acotada. Cada worker carga un modelo en la GPU. Sobre una sola GPU de desarrollo el número de procesos simultáneos es 1–2 antes de agotar VRAM (sujeto a medición). Se requiere un tope explícito y una cola de espera, aunque sea trivial al inicio.
Evolución del mecanismo
El spawn directo es la v1 correcta para bajo volumen. El día que la concurrencia acotada se vuelva el cuello de botella real —no antes— el mecanismo migra a una cola de trabajos (p. ej. BullMQ/Redis con worker Python consumidor), sin cambiar el contrato: el worker sigue hablando HTTP, solo cambia "Node hace spawn" por "Node encola". La transición a RTSP en vivo (fase posterior) sustituye la ingesta por archivo por streams continuos, pero conserva la separación worker/negocio.
Definición de zonas en el frontend
El "setup manual de polígonos por cámara" (módulo 1) ocurre en un canvas de React sobre un frame de referencia, no en la ventana de OpenCV (que es solo herramienta de desarrollo). El frontend captura las coordenadas del polígono y las envía como configuración del job; el worker las consume tal cual en el point-in-polygon. Los eventos de mouse del navegador reemplazan al callback de OpenCV.
Modelo de despliegue
Dónde vive el cómputo de CV es una decisión de arquitectura, no un detalle de operaciones: afecta costo, privacidad del video y exposición de licencia.
| Web / SaaS | Desktop / on-premise | |
|---|---|---|
| Frontend | React servido como estático | React empaquetado (Electron/Tauri) |
| ¿Dónde corre la percepción? | GPU en el servidor | GPU de la máquina del cliente |
| Costo de infraestructura | Alto (GPU 24/7) | Bajo (usa hardware del cliente) |
| Privacidad del video | El footage sale hacia el servidor | El footage no abandona el sitio |
| Exposición AGPL-3.0 | El SaaS distribuye salida sobre red → activa el copyleft de forma más agresiva | On-premise cambia el análisis, no lo elimina |
| Actualización | Centralizada | Re-distribución al cliente |
Para footage de CCTV —sensible por naturaleza, con clientes que suelen tener hardware en sitio— el despliegue on-premise es competitivo: aprovecha la GPU del cliente, mantiene el video local y desacopla el costo del volumen. La ruta SaaS simplifica operación y actualización a cambio de infraestructura GPU y un análisis de licencia más delicado.
Esta decisión interactúa con la de licencias de la capa de percepción: la ruta permisiva (RF-DETR + MediaPipe + ByteTrack) reduce el riesgo en el escenario SaaS, donde la exposición AGPL es mayor.
Contrato con el stack MERN
La capa de CV entrega un evento por incidente detectado. El motor de reglas de cada módulo produce el mismo tipo de objeto, lo que permite que el stack MERN trate todos los módulos de forma uniforme. Borrador a refinar:
{
"camera_id": "string",
"module": "zone | ppe | ergonomics | vehicle | behavior | ...",
"event_type": "zone_intrusion | missing_ppe | bad_lift | overspeed | phone_use | ...",
"timestamp": "ISO-8601",
"severity": "low | medium | high",
"detail": { /* espec ífico por módulo: zona, EPP faltante, ángulo, velocidad, etc. */ },
"actor_ref": "opcional — id de tracking o credencial, según módulo y decisión de re-ID"
}
El campo module permite que Analytics (módulo 6) agrupe, filtre y reporte por módulo sin lógica especial. El campo actor_ref queda abierto a la decisión de reincidencia descrita arriba.
Pendientes y riesgos abiertos
- Licencia AGPL-3.0: la detección ya se resolvió con RF-DETR (Apache 2.0), eliminando esa exposición en la capa de detección. Quedan por decidir pose (YOLO26-pose AGPL vs. MediaPipe / RF-DETR-keypoints permisivos) y tracking (Ultralytics AGPL vs. ByteTrack/BoT-SORT permisivos). Requiere revisión legal según despliegue.
- Entrenamiento custom para EPP, vehículos y celular: es trabajo de datos anotados, no de configuración. Constituye el moat y debe planearse desde el inicio.
- Calibración de cámara para velocidad (módulo 4): sin ella no hay medición real de velocidad, solo movimiento en píxeles.
- Re-identificación de personas (módulo 6, reincidencia): difícil y sensible en privacidad; evaluar la alternativa por credencial antes de comprometer re-ID.
- Objetos pequeños en CCTV (guantes, calzado, celular): degradación esperada respecto a benchmarks; magnitud sujeta a footage propio.
- Pose en ángulos de CCTV (módulo 3): confiabilidad de keypoints es cuestión empírica.
- Cámaras concurrentes sobre el hardware de desarrollo: límite acotado por medición, no asumido. El submuestreo temporal —analizar N frames/seg en vez de todos— es la palanca directa: medición interna muestra ~2.8× menos cómputo al pasar de 30 a 10 análisis/seg, sin pérdida perceptible para intrusión en zona. Desacopla la tasa de inferencia (cara) de la de visualización y multiplica las cámaras atendibles por GPU. El piso de FPS analizables lo fija la detección de eventos rápidos (velocidad, correr).
- Accuracy: sin datos propios, ninguna cifra es defendible. La arquitectura está diseñada para medir y mejorar, no para garantizar a priori.
Elemento invariante
El diferenciador del producto no reside en el modelo, sino en el dataset anotado propio —concentrado en los módulos que exigen entrenamiento custom (EPP, vehículos, conducta)— y en la velocidad del pipeline de datos. Los competidores de referencia emplean los mismos bloques tecnológicos. Por ello el pipeline de datos (offline) figura en la arquitectura desde la primera iteración. Los modelos son reemplazables; el moat no lo es.