diff --git a/vigilancia/.env.example b/vigilancia/.env.example index ed0710c..00c36c0 100644 --- a/vigilancia/.env.example +++ b/vigilancia/.env.example @@ -26,3 +26,7 @@ ALEXA_NOTIFY_SCRIPT=C:\Users\juanm\Documents\GitHub\biblioteca_negocio_prolongo\ # Directorio de snapshots SNAPSHOT_DIR=snapshots + +# Zonas autorizadas (nombres de camara separados por coma). +# Si una camara esta aqui, sus presencias se marcan como "zona autorizada". +ZONAS_AUTORIZADAS= diff --git a/vigilancia/config.py b/vigilancia/config.py index 3b04061..d049695 100644 --- a/vigilancia/config.py +++ b/vigilancia/config.py @@ -32,3 +32,6 @@ VOICEMONKEY_DEVICE = os.getenv("VOICEMONKEY_DEVICE", "").strip() ALEXA_NODE = os.getenv("ALEXA_NODE", "node") ALEXA_NOTIFY_SCRIPT = os.getenv("ALEXA_NOTIFY_SCRIPT", "").strip() SNAPSHOT_DIR = os.getenv("SNAPSHOT_DIR", "snapshots") +ZONAS_AUTORIZADAS = { + n.strip() for n in os.getenv("ZONAS_AUTORIZADAS", "").split(",") if n.strip() +} diff --git a/vigilancia/enroll.py b/vigilancia/enroll.py index 90746ed..c3c1f95 100644 --- a/vigilancia/enroll.py +++ b/vigilancia/enroll.py @@ -53,9 +53,15 @@ def main(): for nombre in nombres: carpeta = os.path.join(CONOCIDOS, nombre) os.makedirs(carpeta, exist_ok=True) - print(f"\n>>> Hija: {nombre}") - fase = "cara" + tiene_cara = os.path.exists(os.path.join(carpeta, "face.npy")) + tiene_cuerpo = os.path.exists(os.path.join(carpeta, "body.npy")) + if tiene_cara and tiene_cuerpo: + print(f" {nombre} ya registrado completo, omitido.") + continue + + fase = "cuerpo" if tiene_cara else "cara" + print(f"\n>>> Hija: {nombre} (falta {fase})") while True: ok, frame = cap.read() if not ok: diff --git a/vigilancia/main.py b/vigilancia/main.py index af2bd9a..a8c6cd6 100644 --- a/vigilancia/main.py +++ b/vigilancia/main.py @@ -36,18 +36,31 @@ def cargar_identificador(): def componer_alerta(resultados, cam_nombre, ts): conocidas = sorted({r["nombre"] for r in resultados if "nombre" in r}) desconocidas = sum(1 for r in resultados if r.get("desconocido")) + zona = "autorizada" if cam_nombre in config.ZONAS_AUTORIZADAS else "NO autorizada" + sufijo = f" (zona {zona})" if conocidas and desconocidas: return (f"👧 {', '.join(conocidas)} | " f"⚠️ {desconocidas} persona(s) desconocida(s) " - f"en {cam_nombre} - {ts}") + f"en {cam_nombre}{sufijo} - {ts}") if conocidas: return (f"👧 {', '.join(conocidas)} detectada(s) " - f"en {cam_nombre} - {ts}") + f"en {cam_nombre}{sufijo} - {ts}") if desconocidas: - return (f"⚠️ {desconocidas} persona(s) desconocida(s) " - f"en {cam_nombre} - {ts}") - return f"🚨 Movimiento en {cam_nombre} - {ts}" + return (f"🚨 {desconocidas} persona(s) en {cam_nombre}" + f"{sufijo} - {ts}") + return f"🚨 Presencia en {cam_nombre}{sufijo} - {ts}" + + +def detectar_presencia(modelo, frame): + """True si hay al menos una persona en el frame (YOLO).""" + if modelo is None: + return True + try: + r = modelo.predict(frame, verbose=False, conf=0.4) + return any(int(b.cls) == 0 for b in r[0].boxes) + except Exception: + return True def dentro_de_franja_horaria(hora_actual=None) -> bool: @@ -77,6 +90,14 @@ def main(): ident = cargar_identificador() + modelo_presencia = None + try: + from ultralytics import YOLO + ruta_yolo = os.path.join(os.path.dirname(os.path.abspath(__file__)), "yolov8n.pt") + modelo_presencia = YOLO(ruta_yolo) + except Exception as e: + print(f"No se pudo cargar YOLO para presencia: {e}") + print("Sistema de vigilancia iniciado. Franja activa: " f"{config.HORA_INICIO}:00 - {config.HORA_FIN}:00") @@ -91,36 +112,46 @@ def main(): continue detector = detectores[i] - detectado = detector.hay_movimiento(frame) + movido = detector.hay_movimiento(frame) ahora = time.time() - if detectado and (ahora - ultima_alerta[i] > config.COOLDOWN): - ts = datetime.now().strftime("%Y%m%d_%H%M%S") - ruta = os.path.join( - config.SNAPSHOT_DIR, f"snapshot_{cam.nombre}_{ts}.jpg" - ) + if not movido: + continue + if (ahora - ultima_alerta[i]) <= config.COOLDOWN: + continue - texto = f"🚨 Movimiento en {cam.nombre} - {ts}" - if ident is not None: - try: - resultados = ident.analizar_frame(frame) - if resultados: - texto = componer_alerta(resultados, cam.nombre, ts) - except Exception as e: - print(f"[{cam.nombre}] Error identificando: {e}") + if not detectar_presencia(modelo_presencia, frame): + continue - cv2_ok = True + ts = datetime.now().strftime("%Y%m%d_%H%M%S") + ruta = os.path.join( + config.SNAPSHOT_DIR, f"snapshot_{cam.nombre}_{ts}.jpg" + ) + + texto = f"🚨 Presencia en {cam.nombre} - {ts}" + if ident is not None: try: - cv2.imwrite(ruta, frame) + resultados = ident.analizar_frame(frame) + if resultados: + texto = componer_alerta(resultados, cam.nombre, ts) except Exception as e: - cv2_ok = False - print(f"[{cam.nombre}] Error guardando snapshot: {e}") + print(f"[{cam.nombre}] Error identificando: {e}") + else: + zona = "autorizada" if cam.nombre in config.ZONAS_AUTORIZADAS else "NO autorizada" + texto = f"🚨 Presencia en {cam.nombre} (zona {zona}) - {ts}" - if cv2_ok: - enviar_telegram(ruta, texto) - disparar_webhook_alexa(texto) - ultima_alerta[i] = ahora - print(texto) + cv2_ok = True + try: + cv2.imwrite(ruta, frame) + except Exception as e: + cv2_ok = False + print(f"[{cam.nombre}] Error guardando snapshot: {e}") + + if cv2_ok: + enviar_telegram(ruta, texto) + disparar_webhook_alexa(texto) + ultima_alerta[i] = ahora + print(texto) time.sleep(0.5)