Files
biblioteca_conocimiento_lab…/vigilancia/main.py

196 lines
6.4 KiB
Python

import os
import time
from datetime import datetime
import cv2
import config
from camara import CamaraRTSP
from detector_movimiento import DetectorMovimiento
from notificador import (disparar_webhook_alexa, enviar_telegram,
enviar_texto_telegram)
USAR_YOLO = True
identificador = None
def notificar_personales(resultados, cam_nombre):
"""Mensaje personalizado por Telegram a cada destinatario segun la persona."""
conocidas = {r["nombre"] for r in resultados if "nombre" in r}
if not conocidas or not config.RECIPIENTES:
return
nombres = ", ".join(sorted(conocidas))
ts = datetime.now().strftime("%H:%M:%S")
for chat in config.RECIPIENTES:
for nombre in sorted(conocidas):
texto = (f"📢 <b>{nombre}</b>, ¿qué estás haciendo? "
f"(vista en {cam_nombre} a las {ts})")
enviar_texto_telegram(texto, chat_id=chat)
def notificar_discord(resultados, cam_nombre):
try:
from discord_notif import notificar_discord_personales
notificar_discord_personales(resultados, cam_nombre)
except Exception as e:
print(f"[Discord] Error: {e}")
def cargar_identificador():
global identificador
if identificador is None:
try:
from reconocedor import CONOCIDOS, Reconocedor, os as _os
if _os.path.isdir(CONOCIDOS) and any(
_os.path.isdir(_os.path.join(CONOCIDOS, n))
for n in _os.listdir(CONOCIDOS)
):
identificador = Reconocedor()
print(f"Identificacion activa. Conocidos: "
f"{list(identificador.conocidos.keys())}")
else:
print("Sin conocidos registrados (ejecuta enroll.py). "
"Modo deteccion simple.")
except Exception as e:
print(f"No se pudo cargar identificador: {e}")
return 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}{sufijo} - {ts}")
if conocidas:
return (f"👧 {', '.join(conocidas)} detectada(s) "
f"en {cam_nombre}{sufijo} - {ts}")
if desconocidas:
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:
if hora_actual is None:
hora_actual = datetime.now().hour
inicio = config.HORA_INICIO
fin = config.HORA_FIN
if inicio < fin:
return inicio <= hora_actual < fin
return hora_actual >= inicio or hora_actual < fin
def main():
if not config.CAMARAS:
print("No hay cámaras configuradas en .env")
return
os.makedirs(config.SNAPSHOT_DIR, exist_ok=True)
camaras = [CamaraRTSP(c["rtsp"], c["nombre"]) for c in config.CAMARAS]
detectores = []
ultima_alerta = {}
for i, c in enumerate(config.CAMARAS):
detectores.append(DetectorMovimiento())
ultima_alerta[i] = 0
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")
while True:
if not dentro_de_franja_horaria():
time.sleep(30)
continue
for i, cam in enumerate(camaras):
frame = cam.leer_frame()
if frame is None:
continue
detector = detectores[i]
movido = detector.hay_movimiento(frame)
ahora = time.time()
if not movido:
continue
if (ahora - ultima_alerta[i]) <= config.COOLDOWN:
continue
if not detectar_presencia(modelo_presencia, frame):
continue
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}"
resultados = []
if ident is not None:
try:
for _ in range(3):
f2 = cam.leer_frame()
if f2 is None:
continue
resultados += ident.analizar_frame(f2)
time.sleep(0.1)
if resultados:
texto = componer_alerta(resultados, cam.nombre, ts)
except Exception as 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}"
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)
if resultados:
try:
notificar_personales(resultados, cam.nombre)
notificar_discord(resultados, cam.nombre)
except Exception as e:
print(f"[{cam.nombre}] Error notificando personales: {e}")
disparar_webhook_alexa(texto)
ultima_alerta[i] = ahora
print(texto)
time.sleep(0.5)
if __name__ == "__main__":
main()