02-ago: [proyecto] vigilancia - presencia por persona (YOLO) + zonas autorizadas/no autorizadas por camara en el aviso de Telegram
This commit is contained in:
@@ -26,3 +26,7 @@ ALEXA_NOTIFY_SCRIPT=C:\Users\juanm\Documents\GitHub\biblioteca_negocio_prolongo\
|
|||||||
|
|
||||||
# Directorio de snapshots
|
# Directorio de snapshots
|
||||||
SNAPSHOT_DIR=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=
|
||||||
|
|||||||
@@ -32,3 +32,6 @@ VOICEMONKEY_DEVICE = os.getenv("VOICEMONKEY_DEVICE", "").strip()
|
|||||||
ALEXA_NODE = os.getenv("ALEXA_NODE", "node")
|
ALEXA_NODE = os.getenv("ALEXA_NODE", "node")
|
||||||
ALEXA_NOTIFY_SCRIPT = os.getenv("ALEXA_NOTIFY_SCRIPT", "").strip()
|
ALEXA_NOTIFY_SCRIPT = os.getenv("ALEXA_NOTIFY_SCRIPT", "").strip()
|
||||||
SNAPSHOT_DIR = os.getenv("SNAPSHOT_DIR", "snapshots")
|
SNAPSHOT_DIR = os.getenv("SNAPSHOT_DIR", "snapshots")
|
||||||
|
ZONAS_AUTORIZADAS = {
|
||||||
|
n.strip() for n in os.getenv("ZONAS_AUTORIZADAS", "").split(",") if n.strip()
|
||||||
|
}
|
||||||
|
|||||||
@@ -53,9 +53,15 @@ def main():
|
|||||||
for nombre in nombres:
|
for nombre in nombres:
|
||||||
carpeta = os.path.join(CONOCIDOS, nombre)
|
carpeta = os.path.join(CONOCIDOS, nombre)
|
||||||
os.makedirs(carpeta, exist_ok=True)
|
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:
|
while True:
|
||||||
ok, frame = cap.read()
|
ok, frame = cap.read()
|
||||||
if not ok:
|
if not ok:
|
||||||
|
|||||||
@@ -36,18 +36,31 @@ def cargar_identificador():
|
|||||||
def componer_alerta(resultados, cam_nombre, ts):
|
def componer_alerta(resultados, cam_nombre, ts):
|
||||||
conocidas = sorted({r["nombre"] for r in resultados if "nombre" in r})
|
conocidas = sorted({r["nombre"] for r in resultados if "nombre" in r})
|
||||||
desconocidas = sum(1 for r in resultados if r.get("desconocido"))
|
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:
|
if conocidas and desconocidas:
|
||||||
return (f"👧 {', '.join(conocidas)} | "
|
return (f"👧 {', '.join(conocidas)} | "
|
||||||
f"⚠️ {desconocidas} persona(s) desconocida(s) "
|
f"⚠️ {desconocidas} persona(s) desconocida(s) "
|
||||||
f"en {cam_nombre} - {ts}")
|
f"en {cam_nombre}{sufijo} - {ts}")
|
||||||
if conocidas:
|
if conocidas:
|
||||||
return (f"👧 {', '.join(conocidas)} detectada(s) "
|
return (f"👧 {', '.join(conocidas)} detectada(s) "
|
||||||
f"en {cam_nombre} - {ts}")
|
f"en {cam_nombre}{sufijo} - {ts}")
|
||||||
if desconocidas:
|
if desconocidas:
|
||||||
return (f"⚠️ {desconocidas} persona(s) desconocida(s) "
|
return (f"🚨 {desconocidas} persona(s) en {cam_nombre}"
|
||||||
f"en {cam_nombre} - {ts}")
|
f"{sufijo} - {ts}")
|
||||||
return f"🚨 Movimiento en {cam_nombre} - {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:
|
def dentro_de_franja_horaria(hora_actual=None) -> bool:
|
||||||
@@ -77,6 +90,14 @@ def main():
|
|||||||
|
|
||||||
ident = cargar_identificador()
|
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: "
|
print("Sistema de vigilancia iniciado. Franja activa: "
|
||||||
f"{config.HORA_INICIO}:00 - {config.HORA_FIN}:00")
|
f"{config.HORA_INICIO}:00 - {config.HORA_FIN}:00")
|
||||||
|
|
||||||
@@ -91,36 +112,46 @@ def main():
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
detector = detectores[i]
|
detector = detectores[i]
|
||||||
detectado = detector.hay_movimiento(frame)
|
movido = detector.hay_movimiento(frame)
|
||||||
|
|
||||||
ahora = time.time()
|
ahora = time.time()
|
||||||
if detectado and (ahora - ultima_alerta[i] > config.COOLDOWN):
|
if not movido:
|
||||||
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
continue
|
||||||
ruta = os.path.join(
|
if (ahora - ultima_alerta[i]) <= config.COOLDOWN:
|
||||||
config.SNAPSHOT_DIR, f"snapshot_{cam.nombre}_{ts}.jpg"
|
continue
|
||||||
)
|
|
||||||
|
|
||||||
texto = f"🚨 Movimiento en {cam.nombre} - {ts}"
|
if not detectar_presencia(modelo_presencia, frame):
|
||||||
if ident is not None:
|
continue
|
||||||
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}")
|
|
||||||
|
|
||||||
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:
|
try:
|
||||||
cv2.imwrite(ruta, frame)
|
resultados = ident.analizar_frame(frame)
|
||||||
|
if resultados:
|
||||||
|
texto = componer_alerta(resultados, cam.nombre, ts)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
cv2_ok = False
|
print(f"[{cam.nombre}] Error identificando: {e}")
|
||||||
print(f"[{cam.nombre}] Error guardando snapshot: {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:
|
cv2_ok = True
|
||||||
enviar_telegram(ruta, texto)
|
try:
|
||||||
disparar_webhook_alexa(texto)
|
cv2.imwrite(ruta, frame)
|
||||||
ultima_alerta[i] = ahora
|
except Exception as e:
|
||||||
print(texto)
|
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)
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user