Immaginate di avere un sistema di videosorveglianza che non si limiti a registrare ore di video inutili ogni volta che un gatto attraversa il giardino o un ramo si muove al vento.
L’applicazione che abbiamo sviluppato nasce proprio per risolvere questo problema, unendo la velocità della Motion Detection tradizionale alla precisione chirurgica dell’Intelligenza Artificiale.
Questo software è in grado di monitorare un flusso video in tempo reale, attivando la registrazione solo quando rileva un movimento significativo e, soprattutto, utilizzando modelli di Deep Learning per identificare esattamente cosa sta accadendo davanti all’obiettivo.
Il vero punto di forza di questa app risiede nella sua logica ottimizzata: invece di analizzare freneticamente ogni singolo fotogramma (operazione che richiederebbe risorse computazionali enormi), il sistema attende il momento perfetto.
Grazie a un ritardo programmato di un secondo dal primo rilevamento, l’algoritmo di Image Recognition interviene quando l’oggetto è ormai pienamente visibile e centrato nell’inquadratura.
Il risultato? Notifiche precise, file video già rinominati con il nome dell’oggetto rilevato (come “person”, “dog” o “car”) e un’efficienza energetica che permette al sistema di girare anche su hardware non dedicato.
Scelte Tecnologiche: Moduliarità e Performance
Il cuore del progetto è scritto in Python, scelto per la sua straordinaria capacità di far dialogare librerie eterogenee.
Per la gestione del flusso video abbiamo puntato su GStreamer, uno standard industriale che garantisce latenza minima e supporto ai protocolli di rete come UDP e RTSP.
La rilevazione del movimento è affidata a OpenCV e al suo algoritmo Background Subtractor MOG2, estremamente reattivo nel separare gli oggetti in movimento dallo sfondo.
Infine, per il riconoscimento degli oggetti, abbiamo integrato YOLO (You Only Look Once) nella sua versione più recente e leggera, che rappresenta oggi il miglior compromesso al mondo tra velocità di esecuzione e accuratezza analitica.
Requisiti di Sistema
Per eseguire correttamente l’applicazione, è necessario un ambiente con Python 3.8+ e le librerie opencv-python, ultralytics(per YOLO) e i binding di GStreamer (PyGObject).
Dal punto di vista hardware, sebbene il software sia ottimizzato per CPU standard, l’aggiunta di una GPU compatibile con CUDA o di un acceleratore come i chip M di Apple permetterà un’analisi ancora più fluida.
Infine, è fondamentale una sorgente video che trasmetta in streaming (come una IP Camera o un server VLC) verso la porta UDP configurata nel sistema.
Un Raspberry Pi come Streamer UDP
Per trasformare un Raspberry Pi in una sorgente video remota, utilizzeremo la potenza di GStreamer direttamente da riga di comando.
Una volta collegata una webcam USB, il comando gst-launch-1.0 permette di catturare il flusso video, codificarlo in formato H.264 (per ridurre drasticamente l’occupazione di banda) e impacchettarlo in pacchetti RTP inviati via UDP verso l’indirizzo IP del computer che esegue l’app.
Questa configurazione è ideale perché riduce al minimo la latenza, permettendo al Raspberry Pi di fare solo il lavoro “sporco” di compressione video, lasciando tutta la potenza di calcolo della CPU libera per la gestione del sistema operativo.
gst-launch-1.0 v4l2src device=/dev/video0 ! \
video/x-raw,width=640,height=360,framerate=20/1 ! \
videoconvert ! x264enc tune=zerolatency bitrate=500 speed-preset=superfast ! \
rtph264pay config-interval=1 ! \
udpsink host=INDIRIZZO_IP_PC port=5000

Analisi del codice sorgente
1. Inizializzazione e Configurazione (CONFIG)
Prima ancora di avviare il motore, il programma legge il dizionario CONFIG.
Qui definiamo le “regole del gioco”: a che porta ascoltare, quanto deve essere sensibile il movimento e quanto tempo deve aspettare YOLO prima di analizzare l’immagine.
È il cervello statico del software.
2. Creazione delle Istanze (__init__)
Quando eseguiamo app = MotionMonitorApp(CONFIG), Python entra nel metodo __init__.
Vengono create le tre componenti principali: VisionEngine (carica il modello YOLO in memoria), VideoRecorder(prepara la cartella dei video) e il Sottrattore di Sfondo (che imparerà com’è fatta la stanza vuota).
Viene costruita la stringa GStreamer: è una “tubatura” digitale che prende i pacchetti UDP dalla rete, li decodifica e li trasforma in matrici di pixel (BGR) manipolabili da OpenCV.
3. Avvio della Pipeline e Callback (_on_sample)
Chiamando app.run(), la pipeline GStreamer inizia a scorrere.
Ogni volta che arriva un nuovo fotogramma dalla telecamera, scatta la funzione _on_sample.
Questa funzione “cattura” il fotogramma e lo salva in self.current_frame. È un processo continuo che avviene in background mentre il resto del codice elabora il frame precedente.
4. Il Ciclo Principale (while True)
Qui avviene il lavoro pesante, diviso in quattro fasi cicliche:
A. Analisi del Movimento (Motion Logic)
Il fotogramma attuale viene confrontato con il “modello della stanza” creato dal sottrattore di sfondo.
Il risultato è una maschera in bianco e nero dove il bianco rappresenta ciò che si è mosso.
Il codice cerca i contorni (contours) di queste macchie bianche.
Se un contorno è più grande di min_area, il sistema dichiara lo stato: valid_cnts = True.
B. Gestione della Registrazione (State Machine)
Inizio: Se c’è movimento e non stavamo già registrando, VideoRecorder.start() crea un nuovo file .mp4 temporaneo e segna l’ora esatta del primo movimento (first_motion_time).
Mantenimento: Finché c’è movimento, aggiorniamo last_motion_time.
Chiusura: Se non c’è più movimento per un tempo superiore al cooldown (es. 2 secondi), il registratore chiude il file e lo rinomina includendo il nome dell’oggetto riconosciuto.
C. Riconoscimento Ritardato (Delayed Recognition)
È qui che abbiamo inserito il tuo miglioramento.
Il sistema controlla: “Sto registrando? È passato almeno 1 secondo dal primo movimento? Ho già usato YOLO per questo evento?”
Se tutte le risposte sono SI, VisionEngine.detect prende il frame, ritaglia l’area dove c’è il movimento (con un po’ di margine/padding) e interroga YOLO.
Se YOLO trova qualcosa (es. “person”), l’etichetta viene salvata e il sistema si mette in standby per non sprecare CPU inutilmente.
D. Interfaccia Utente (_show_ui)
Infine, il codice prende il fotogramma originale, disegna sopra i rettangoli verdi del movimento, aggiunge il rettangolo nero della dashboard e scrive i testi (Soglia, Stato, REC). Tutto questo viene mostrato a video con cv2.imshow.
5. Pulizia Finale (finally)
Quando premi ‘q’, il ciclo si rompe. Il blocco finally assicura che:
La registrazione video in corso venga chiusa correttamente (per evitare file corrotti), la pipeline GStreamer venga spenta e le finestre di OpenCV vengano distrutte.