Realizzare un sistema di sorveglianza con Raspberry Pi e OpenCV

Realizziamo con Raspberry Pi un sistema in grado di rilevare il movimento di persone e oggetti tramite una videocamera e di inviare e-mail di allarme.

La cosiddetta Computer Vision o visione artificiale, รจ un settore di ricerca che si occupa di come i computer possano interpretare la realtร  visiva esattamente come un essere umano; essa si avvale di algoritmi complessi in grado di elaborare immagini fisse o in movimento, al fine di fornire indicazioni e informazioni su persone e oggetti, proprio come farebbe il nostro sistema percettivo.

Dal punto di vista pratico, la visione artificiale elaborata da un computer cerca di automatizzare quelle attivitร  che il sistema visivo umano svolge naturalmente. I campi applicativi della Computer Vision vanno dalla digitalizzazione ambientale, la ricostruzione virtuale di luoghi e scenari, fino al riconoscimento e il monitoraggio visivo degli oggetti e delle persone.

Lโ€™acquisizione delle immagini e lโ€™elaborazione delle informazioni visive in tempo reale necessitano solitamente di dispositivi ottici ad alta risoluzione, di potenti computer e software ad hoc.
In questo articolo esporremo unโ€™applicazione di OpenCV 4, ossia la release piรน recente della diffusa libreria libera, rilasciata sotto una licenza BSD (Berkeley Software Distribution), che permette di sviluppare applicazioni di visione artificiale anche molto complesse.

La libreria OpenCV 4

Dal sito ufficiale di OpenCV vediamo innanzitutto le caratteristiche salienti.
โ€ข OpenCV รจ ora una libreria C++ 11 e richiede un compilatore conforme a C++ 11. La versione CMake minima richiesta รจ stata portata a 3.5.1.
โ€ข Molte API C di OpenCV 1.x sono state rimosse.
โ€ข La persistenza (la memorizzazione e il caricamento dei dati strutturati da/a XML, YAML o JSON) nel modulo principale รจ stata completamente reimplementata in C++ 11 e ha perso anche le API in C.
โ€ข รˆ stato aggiunto il nuovo modulo G-API, che funge da motore per pipeline di elaborazione molto efficiente per immagini basate su grafici.
โ€ข Il modulo dnn รจ stato aggiornato con Deep Learning Deployment Toolkit dal toolkit OpenVINO ™ R4. Consultare la guida su come costruire e utilizzare OpenCV con il supporto DLDT.
โ€ข Il modulo dnn ora include il backend Vulkan sperimentale e supporta le reti in formato ONNX.
โ€ข Il famoso algoritmo Kinect Fusion รจ stato implementato e ottimizzato per CPU e GPU (OpenCL).
โ€ข Un rilevatore e decodificatore di codice QR sono stati aggiunti al modulo objdetect
โ€ข Lโ€™algoritmo di flusso ottico denso DIS ad alta efficienza รจ stato spostato da opencv_contrib al modulo video.
โ€ข Maggiori dettagli possono essere trovati negli annunci delle versioni precedenti: 4.0-alpha, 4.0-beta, 4.0-rc e nel changelog.

Ricordiamo che OpenCV รจ disponibile per interfacce C++, Python e Java e supporta le piattaforme Windows, Linux, Mac OS, iOS e Android. Per il nostro progetto verrร  utilizzata la versione Linux/Ubuntu ottimizzata per Raspberry Pi 3B+ e interfaccia Python 3.

La scelta di sviluppare un progetto di home automation con OpenCV e la scheda Raspberry Pi si basa su due semplici motivi: il primo รจ legato alla compattezza del microcomputer, che puรฒ essere tranquillamente alloggiato in un piccolo contenitore, magari stampato in casa con la stampante 3D, il secondo รจ legato alla presenza della porta GPIO di Raspberry Pi a cui possiamo collegare facilmente dispositivi di controllo e di allarme.

Aggiungiamo infine la facilitร  di sviluppare in ambiente Python, che รจ giร  integrato nel suo sistema operativo.

 

VNC Viewer

Anche se si puรฒ operare direttamente con un mouse, una tastiera e un monitor HDMI, collegati alla scheda Raspberry Pi, di solito si preferisce creare un collegamento al desktop di Raspbian attraverso una connessione SSH o VNC.

In questo modo, dopo aver configurato la rete Wi-Fi o Ethernet di Raspberry Pi, si puรฒ accedere al desktop remoto utilizzando uno dei tanti terminali SSH oppure tramite il comodo VNC Viewer, scaricabile gratuitamente dal sito ufficiale e disponibile per tutte le piattaforme. Per la cronaca, abbiamo usato la versione per PC Windows, ma lโ€™utilizzo รจ identico anche per tutti gli altri OS.

Configurazione delle interfacce di Raspberry Pi

Prima di configurare la connessione VNC รจ necessario attivare lโ€™interfaccia VNC dal menu Preferenze > Raspberry Pi Configuration di Raspbian, come illustrato in Fig. 1.

Per fare questo, una volta aperta la finestra Raspberry Pi Configuration, basta fare clic sulla voce VNC. Nella stessa finestra si possono attivare anche tutte le altre interfacce, compresa lโ€™interfaccia Camera, come illustrato in Fig. 2.

Le altre interfacce, anche se non servono per questo progetto, potranno venire utili in futuro.

Fig. 1 Il menu Preferenze > Raspberry Pi Configuration di Raspbian

 

 

Fig. 2 La finestra Raspberry Pi Configuration con le interfacce tutte attivate

 

Per usare la connessione VNC bisogna conoscere lโ€™indirizzo IP che รจ stato assegnato automaticamente alla scheda al momento della prima configurazione WLAN o LAN. Se si vuole sfruttare la rete Wi-Fi della scheda รจ sufficiente aprire la finestra Network Preferences (Fig. 3) in cui รจ visibile lโ€™indirizzo assegnato dalla connessione WLAN.

Fig. 3 La finestra Network Preferences

Connessione VNC

Per creare una nuova connessione con VNC Viewer, basta inserire nella finestra Properties lโ€™indirizzo IP della scheda Raspberry Pi, come illustrato in Fig. 4.

Una volta avviata la connessione VNC verrร  chiesto il nome utente e la password di autenticazione che, per default, sono rispettivamente โ€œpiโ€ e โ€œraspberryโ€ (Fig. 5).

Fig. 4 La finestra Properties di VNC Viewer

 

 

 

Fig. 5 La finestra Authentication di VNC Viewer

 

Una volta effettuata la connessione, il desktop di Raspbian sarร  visibile a tutto schermo sul monitor del PC. Da questo momento in poi, si potranno scollegare il mouse, la tastiera e il monitor dalla scheda Raspberry Pi e avere il controllo totale da remoto. Puรฒ capitare che lโ€™indirizzo IP assegnato dal DHCP cambi, quindi รจ consigliabile configurare un IP statico nella scheda Raspberry Pi.

Configurare un IP statico su Raspberry Pi

Per configurare un IP statico รจ sufficiente aprire una finestra del terminale (Fig. 6) e digitare il seguente comando:

Fig. 6 La finestra dellโ€™editor nano in cui modificare il file dhcpcd.conf

 

sudo nano /etc/dhcpcd.conf

Questo aprirร  il file dhcpcd.conf nella finestra dellโ€™editor nano.
Nellโ€™esempio riportato nel file dhcpcd.conf , basta quindi decommentare le seguenti righe e modificare i dati in base alla propria rete e allโ€™indirizzo IP che si vuole usare per la connessione remota:

interface wlan0

#oppure eth0 se si usa una rete LAN

static ip_address=192.168.1.100/24

#un qualsiasi indirizzo nel segmento di rete del proprio router

static routers=192.168.1.1

#indirizzo IP del router

static domain_name_servers=192.168.1.1 8.8.8.8

#indirizzi statici dei server

Una volta salvato il file e riavviato il sistema, lโ€™IP statico cosรฌ impostato permetterร  di effettuare la connessione VNC utilizzando sempre lo stesso indirizzo.

Raspberry Pi 3B+ e Camera Module v2

Per questo progetto abbiamo optato per la scheda Raspberry Pi modello 3B+ e per Raspberry Pi Camera Module v2. La versione 2 della videocamera offre una risoluzione di ben 8 Megapixel e 3.820 x 2.464 pixel di risoluzione del sensore.

La Camera Module v2 va collegata come illustrato in Fig. 7, usando il flat cable in dotazione e facendo attenzione al verso di inserimento alla porta CSI di Raspberry Pi 3 B+.

Fig. 7 Collegamento del modulo Camera Module v2 a Raspberry Pi 3 B+

Test della videocamera

Per vedere se la videocamera funziona correttamente con Python, si consiglia di effettuare questo semplice test. In una nuova finestra dellโ€™editor di Python scrivere queste poche righe di codice:

from picamera import PiCamera
from time import sleep
camera = PiCamera()
camera.start_preview()
sleep(10)
camera.stop_preview()

Allโ€™avvio dello script dovrebbe aprirsi una finestra di preview e chiudersi dopo 10 secondi.
Se questo non accade, controllare che il flat cable sia ben inserito nel verso giusto nello slot. Se tutto funziona a dovere, si puรฒ proseguire tranquillamente allโ€™installazione di OpenCV 4.

Installazione di OpenCV 4 su Raspbian Stretch

Come per le precedenti versioni, anche OpenCV 4 necessita di una particolare installazione. Per cui, se non si dispone del giร  citato sistema operativo Raspbian Stretch, รจ necessario aggiornare il sistema operativo per sfruttare le nuove funzionalitร .
Attenzione! OpenCV 4 non รจ stato testato su versioni di Raspbian precedenti a Stretch.
Data la giovane etร  di OpenCV 4, non abbiamo trovato molte guide on-line, per cui ci siamo affidati allโ€™esperienza di Adrian Rosebrock che gestisce il suo blog sul Deep Learning allโ€™indirizzo https://www.pyimagesearch.com e di Satya Mallick che gestisce il sito https://www.learnopencv.com dedicato alla Computer Vision a al Machine Learning. Entrambi riportano pressappoco la stessa procedura di installazione.
Notate che per molti comandi da terminale si deve usare il carattere tilde (~). Se non รจ presente sulla tastiera, usare i tasti SHIFT+CTRL+u e inserire il codice esadecimale 7e + INVIO.

Installare le dipendenze di OpenCV 4

Prima di avviare qualsiasi installazione su Raspbian รจ sempre consigliabile aggiornare i repository con il comando apt-get, aprendo una finestra del terminale:

sudo apt-get update && sudo apt-get upgrade

Quindi, sempre con apt-get, si devono installare tutti gli strumenti di sviluppo, inclusa lโ€™ultima versione di CMake:

sudo apt-get install build-essential cmake unzip pkg-config

Successivamente, installiamo una selezione di librerie per il trattamento delle immagini e del video:

sudo apt-get install libjpeg-dev libpng-dev libtiff-dev
sudo apt-get install libavcodec-dev libavformat-dev libswscale-dev libv4l-dev
sudo apt-get install libxvidcore-dev libx264-dev

Quindi, installiamo i toolkit GTK per lโ€™interfaccia grafica:

sudo apt-get install libgtk-3-dev
sudo apt-get install libcanberra-gtk*

(lโ€™asterisco acquisirร  la specifica GTK ARM)

A questo punto servono due pacchetti che contengono ottimizzazioni numeriche per OpenCV:

sudo apt-get install libatlas-base-dev gfortran

Infine, installiamo gli strumenti di sviluppo per Python 3:

sudo apt-get install python3-dev

Dopo aver installato tutti i prerequisiti, รจ possibile eseguire il download di OpenCV 4.

Download di OpenCV 4

รˆ preferibile scaricare gli archivi di OpenCV4 nella cartella Home. Tutte le librerie di OpenCV 4 sono disponibili in due repository github chiamati opencv e opencv_contrib. Il repository contrib contiene moduli aggiuntivi creati dagli utenti.
Ecco i comandi da digitare per tornare alla cartella Home e scaricare i due repository.

cd ~
wget -O opencv.zip https://github.com/opencv/opencv/archive/4.0.0.zip
wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.0.0.zip

Una volta scaricati gli archivi zip, vanno decompressi, sempre nella cartella Home:

unzip opencv.zip
unzip opencv_contrib.zip

Verranno cosรฌ create le directory opencv-4.0.0 e opencv_contrib-4.0.0. Per motivi pratici si consiglia di rinominare le cartelle come opencv e opencv_contrib:

mv opencv-4.0.0 opencv
mv opencv_contrib-4.0.0 opencv_contrib

A questo punto, prima della compilazione vera e propria della libreria OpenCV 4, รจ necessario predisporre lโ€™ambiente virtuale di Python 3.

Configurare lโ€™ambiente virtuale di Python 3

Se non si ha familiaritร  con gli ambienti virtuali di Python e per sapere perchรฉ รจ consigliabile lavorare su un ambiente virtuale si veda il box dedicato.
Per prima cosa, bisogna installare pip:

wget https://bootstrap.pypa.io/get-pip.py
sudo python3 get-pip.py

Quindi installiamo virtualenv e virtualenvwrapper che consentono di creare ambienti virtuali di Python 3:

sudo pip install virtualenv virtualenvwrapper
sudo rm -rf ~/get-pip.py ~/.cache/pip

Per completare lโ€™installazione di questi strumenti, รจ necessario aggiornare il file ~/.profile, usando questi semplici comandi echo:

echo โ€œexport WORKON_HOME=$HOME/.virtualenvsโ€ >> ~/.profile
echo โ€œexport VIRTUALENVWRAPPER_PYTHON=/usr/bin/python3โ€ >> ~/.profile
echo โ€œsource /usr/local/bin/virtualenvwrapper.shโ€ >> ~/.profile

Le aggiunte al profilo indicano il percorso della cartella di lavoro virtualenvs, creata dallo strumento virtualenv nella Home e il percorso dello script virtualwrapper che si trova nella cartella /usr/bin. Una volta aggiornato il profilo, basta attivarlo con il comando seguente:

source ~/.profile

Creare un ambiente virtuale per contenere OpenCV 4 e i pacchetti aggiuntivi

A questo punto si puรฒ creare un ambiente virtuale OpenCV 4 per Python 3 e lavorare cosรฌ in maniera indipendente da altri ambienti.
Questa linea di comando crea semplicemente un ambiente virtuale Python 3 chiamato โ€œcvโ€.

mkvirtualenv cv -p python3

Si puรฒ dare un nome qualsiasi allโ€™ambiente virtuale, ma si consiglia, per praticitร , di tenere un nome corto. Se il profilo รจ attivato correttamente e viene creato lโ€™ambiente virtuale โ€œcvโ€, si puรฒ verificare che siamo nellโ€™ambiente โ€œcvโ€ usando il comando workon, come indicato dalla freccia di Fig. 8:

Fig. 8 Attivazione del profilo e dellโ€™ambiente virtuale cv

 

workon cv

Installazione di NumPy

Il pacchetto Python richiesto da OpenCV 4 รจ NumPy. Per installarlo basta digitare il comando seguente:

pip install numpy

CMake e compilazione di OpenCV 4

Per compilare OpenCV 4, si userร  CMake, seguito da make. Questo รจ il passo piรน dispendioso in termini di tempo. Innanzitutto, bisogna torna alla cartella opencv nella Home e creare al suo interno una sottodirectory build:

cd ~/opencv
mkdir build
cd build

A questo punto eseguite CMake per la creazione della build di tipo release.

ย cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \
-D ENABLE_NEON=ON \
-D ENABLE_VFPV3=ON \
-D BUILD_TESTS=OFF \
-D OPENCV_ENABLE_NONFREE=ON \
-D INSTALL_PYTHON_EXAMPLES=OFF \
-D BUILD_EXAMPLES=OFF ..

Notate che il carattere backslash serve a continuare il comando con un a capo. Notare anche la presenza del percorso per la compilazione dei moduli aggiuntivi opencv_contrib.

Aumentare lo SWAP sul Raspberry Pi

Prima di iniziare la compilazione vera e propria si consiglia di aumentare lo spazio di swap. Questo per evitare che la compilazione si interrompa a causa dellโ€™esaurimento della memoria. Per fare ciรฒ basta modificare temporaneamente il file di swap che si trova in questo percorso /etc/dphys-swapfile:

sudo nano /etc/dphys-swapfile

… e quindi modificare la variabile CONF_SWAPSIZE portandola da 100 a 2.048 MB. Con il carattere # si commenta la riga:

# CONF_SWAPSIZE=100
CONF_SWAPSIZE=2048

Se non si esegue questo passaggio รจ molto probabile che la scheda si blocchi durante la compilazione. Una volta modificato il file di swap, bisogna fermare e riavviare il servizio di swap:

sudo /etc/init.d/dphys-swapfile stop
sudo /etc/init.d/dphys-swapfile start

Compilazione di OpenCV 4

Ora tutto รจ pronto per compilare OpenCV 4. Digitare semplicemente il comando seguente:

make -j4

Si noti che lโ€™opzione – j4 specifica lโ€™uso di 4 core per la compilazione. Se si verificano errori di compilazione o la scheda si blocca, si puรฒ provare senza lโ€™opzione -j4. Normalmente, il processo di compilazione di OpenCV 4 รจ abbastanza lungo e dispendioso di risorse, per cui si consiglia di prendersi una bella pausa e lasciare che la scheda lavori senza interventi esterni di nessun tipo, ovvero senza toccare mouse o tastiera. Al termine della compilazione, se tutto รจ andato bene si potrร  vedere la percentuale di compilazione al 100% (Fig. 9).

Fig. 9 Compilazione terminata con successo

 

Ora non ci resta che installare OpenCV 4 con due tipici comandi:

sudo make install
sudo ldconfig

Non dimenticare di ripristinare lo swapfile, riportandolo a 100 MB, e riavviandolo:

sudo nano /etc/dphys-swapfile
CONF_SWAPSIZE=2048
sudo /etc/init.d/dphys-swapfile stop
sudo /etc/init.d/dphys-swapfile start

Collegamento simbolico di OpenCV

Un’ultima cosa molto importante รจ il collegamento simbolico di OpenCV 4 con la directory dei pacchetti del nostro ambiente virtuale. Bisogna entrare nella directory dei site-packages dellโ€™ambiente virtuale e linkare la libreria cv2.so. Ecco i comandi:

cd ~/.virtualenvs/cv/lib/python3.5/site-packages/
ln -s /usr/local/python/cv2/python-3.5/cv2.cpython-35m-arm-linux-gnueabihf.so cv2.so
cd ~

Notate lโ€™opzione โ€“s di ln che sta per symbolic.

Se non si esegue questo passaggio, OpenCV 4 non riconoscerร  i pacchetti dellโ€™ambiente virtuale di Python 3. A questo proposito controllare che nella directory ~/.virtualenvs/cv/lib/python3.5/site-packages sia presenti il link alla libreria cv2.so.

Virtual Environment in Python 3

Virtual Environment sta per ambiente virtuale. Si tratta di una pratica che permette di creare degli spazi indipendenti dal resto del sistema in cui รจ possibile testare e lavorare con Python e pip.

In altre parole, gli ambienti virtuali consentono di lavorare e sperimentare con piรน progetti contemporaneamente, nonostante questi utilizzino una versione diversa degli stessi moduli.

Inoltre, permettono di installare moduli con pip senza i privilegi di root, con tutti i vantaggi che questo comporta in termini di sicurezza.

In pratica, viene creata una cartella che conterrร  i file necessari al funzionamento dellโ€™ambiente e una copia dei binary di Python. Dentro questa cartella potremo poi installare tutti i moduli con la versione che vogliamo in base al progetto su cui si sta lavorando.

Una volta creato un ambiente virtuale, basta attivarlo e iniziare a lavorare al suo interno.

Se non รจ giร  stato fatto in precedenza, bisogna installare il pacchetto virtualenv con pip:

pip install virtualenv

Prima di tutto, si consiglia di creare una cartella di lavoro:

mkdir progetto
cd progetto

Con il comando che segue si puรฒ creare lโ€™ambiente virtuale nella
cartella progetto, scegliendo un nome qualsiasi:

virtualenv env_name

Questo comando installerร  tutti gli strumenti necessari allโ€™interno dellโ€™ambiente virtuale env_name.

Infine, ci si sposta nella cartella bin dellโ€™ambiente virtuale env_name
e lo si attiva con il comando activate:

cd env_name/bin
source activate

Per disattivare lโ€™ambiente virtuale e tornare al prompt normale, basta digitare il comando deactivate.

Schermata caratteristica del Virtual Environment

Verifica dellโ€™installazione di OpenCV 4

Per vedere se OpenCV 4 รจ stato installato correttamente, rimanendo allโ€™interno dellโ€™ambiente virtuale cv, eseguire quanto segue dal terminale:

python
>>> import cv2
>>> cv2.__version__
โ€˜4.0.0โ€™
>>> exit()

Come illustrato in Fig. 10, il primo comando apre lโ€™interprete Python 3 associato allโ€™ambiente cv.

Fig. 10 Verifica dellโ€™installazione di OpenCV 4

 

Il comando import cv2 importa la lib reria e il comando cv2.__version__ fa vedere la versione 4.0.0 della libreria. Con il comando exit() si esce dallโ€™interprete e si torna al terminale.

Ricordate che al riavvio del sistema bisogna riattivare ogni volta lโ€™ambiente virtuale (nel nostro caso โ€œcvโ€) e quindi iniziare a lavorare, con il comando workon cv:

source ~/. Profile
workon cv

Per usare lโ€™interfaccia IDLE di Python 3 allโ€™interno dellโ€™ambiente virtuale รจ necessario digitare il seguente comando:

python -m idlelib.idle

Con lโ€™interfaccia IDLE aperta, si possono creare nuovi script o aprire quelli giร  fatti in precedenza.

Se si tenta di aprire al di fuori dellโ€™ambiente virtuale uno script che importa la libreria cv2, apparirร  il Traceback con lโ€™avviso di errore:
ImportError: No module named โ€˜cv2โ€™.

Videosorveglianza con OpenCV 4 e Raspberry Pi

Abbiamo pensato a questo progetto come a una valida alternativa ai sistemi dโ€™allarme basati su sensori PIR, a ultrasuoni, a contatto e cosรฌ via. Una volta rilevato un movimento, lo script fotografa lโ€™intruso e manda la foto a un indirizzo di posta elettronica per identificare la persona.

Qualunque sia lo scopo, abbiamo creato lo script basato su OpenCV 4 per la cattura del movimento per lโ€™invio di email a un indirizzo di posta. Contemporaneamente, il movimento rilevato attiva una porta GPIO alla quale collegare eventualmente un relรจ e un sistema di allarme. Raspbian include le librerie per la gestione della posta e della porta GPIO, per cui non serve installare altro.

Di seguito commentiamo le parti salienti dello script (il codice completo potete scaricarlo dal nostro sito www.elettronicain.it). Le librerie importate allโ€™inizio dello script servono solo alla gestione SMTP, ovvero allโ€™invio di e-mail tramite un server di posta noto. Per questo utilizzo, รจ necessario connettere Raspberry Pi alla rete WiFi o Ethernet.

from smtplib import SMTP_SSL as SMTP 
from email.mime.text import MIMEText
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email import Encoders

Nella sezione che segue vanno cambiati i parametri per il server SMTP. Si consiglia di impiegare il server SMTP normalmente usato per lโ€™invio di posta dal computer di casa.

Le variabili sender e destination contengono gli indirizzi del mittente e del destinatario, ovvero lโ€™indirizzo con il quale si mandano normalmente le email e lโ€™indirizzo a cui si vuol inviare il messaggio.

Le variabili username e password sono il nome utente e la password usati per lโ€™invio al server SMTP. Il tipo di messaggio รจ di testo plain e la variabile content indica il contenuto del messaggio mentre la variabile subject riporta lโ€™oggetto del messaggio. Lโ€™istanza msg eredita i metodi della libreria MIMEMultipart.

SMTPserver = โ€˜smtps.server.xxxโ€™ 
sender = โ€˜[email protected]โ€™
destination = โ€˜[email protected]โ€™
username = โ€˜[email protected]โ€™
password = โ€˜myPasswordโ€™
text_subtype = โ€˜plainโ€™
content=โ€™Messaggioโ€™
subject=โ€™Allarmeโ€™
msg = MIMEMultipart()

La funzione email_send() รจ designata allโ€™invio di unโ€™email con un allegato, che nel nostro caso รจ unโ€™immagine jpg dellโ€™intruso o dellโ€™oggetto che si รจ mosso nella stanza. Come vedremo piรน avanti, la funzione di invio e-mail รจ opzionale e puรฒ essere chiamata o meno nello script. Se lโ€™invio avviene correttamente, sul terminale verrร  stampato โ€œInvio eseguitoโ€ altrimenti apparirร  โ€œInvio fallitoโ€.

def email_send():
try:

msg[โ€˜Subjectโ€™]= subject
msg[โ€˜Fromโ€™] = sender
msg[โ€˜Toโ€™] = destination 
msg.attach(MIMEText(content, โ€˜plainโ€™))
msg.attach(part)
conn = SMTP(SMTPserver)
conn.set_debuglevel(False)
conn.login(USERNAME, PASSWORD)
try:
conn.sendmail(sender, destination, msg.as_string())
print(โ€œInvio eseguitoโ€)
finally:
conn.quit()
except Exception: print(โ€œInvio fallitoโ€)

Quelle che seguono sono le librerie che devono essere importate per la gestione della videocamera, della data, dellโ€™orario, degli effetti video, dei file json, di cv2 (OpenCV 4) e della porta GPIO.

import cv2
import time
import datetime
import imutils
import json
import RPi.GPIO as GPIO
from picamera.array import PiRGBArray
from picamera import PiCamera

Le istruzioni seguenti impostano lโ€™uscita GPIO26 (potete, da qui, sceglierne unโ€™altra):

GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(26,GPIO.OUT)

Lo script prevede lโ€™importazione di alcuni parametri attraverso un file di configurazione, che abbiamo chiamato appunto โ€œconfigurazione.jsonโ€. Grazie alla libreria json si puรฒ quindi fare il parsing dei valori assegnati ai parametri di configurazione e assegnarli alle variabili o alle funzioni. Lโ€™istruzione che segue permette il caricamento del file json che viene spiegato nel prossimo paragrafo.

conf = json.load(open(โ€˜configurazione.jsonโ€™))

Il file configurazione.json

Di solito un file JSON (JavaScript Object Notation) viene usato nellโ€™ambiente di programmazione Javascript. Grazie alla sua versatilitร , viene usato spessissimo come file di configurazione in altri ambienti.

Si tratta di uno script che supporta il linguaggio Javascript e quindi accetta la sintassi tipica del linguaggio.

Aprendo il file โ€œconfigurazione.jsonโ€ con un semplice editor di testo si possono vedere i parametri da assegnare a variabili e funzioni:

{
โ€œuse_imgโ€: true,
โ€œuse_emailโ€: true,
โ€œvideo_previewโ€: true,
โ€œmin_timeโ€: 3.0,
โ€œmin_motionโ€: 8,
โ€œthresholdโ€: 5,
โ€œresolutionโ€: [640, 480],
โ€œfpsโ€: 25,
โ€œmin_areaโ€: 5000
}

Come vedete, alcuni parametri sono posti a true o false e altri contengono valori numerici e array.

Leggendo questi parametri con la suddetta istruzione conf = json.load(open(โ€˜configurazione.jsonโ€™)), si possono impostare le funzionalitร  dello script di videosorveglianza, senza dover toccare ogni volta il codice.

Per esempio, se non si vogliono salvare i file delle immagini catturate e usare la videosorveglianza solo per accendere il relรจ di allarme, basta scrivere nel file json la seguente istruzione:

โ€œuse_imgโ€: false

Allo stesso modo, se non si desidera lโ€™invio di email:

โ€œuse_emailโ€: false

Se non volete visualizzare la finestra di anteprima:

โ€œvideo_previewโ€: false

 

Gli altri parametri permettono di impostare:
โ€ข min_time: valore predefinito 3 secondi; รจ il tempo minimo per rilevare il movimento;
โ€ข min_motion: valore predefinito 8 frame; รจ il numero minimo di frame prima di attivare lโ€™accensione del LED, il salvataggio dei file e/o lโ€™invio dellโ€™email. Si puรฒ aumentare o diminuire il valore per rendere piรน o meno sensibile il rilevamento ;
โ€ข threshold: valore predefinito 5; definisce la soglia di sensibilitร  per il rilevamento del movimento. Si puรฒ aumentare o diminuire questo valore a seconda che si voglia rendere il contrasto piรน o meno sensibile;
โ€ข resolution: (predefinito 640×480 pixel) รจ la risoluzione video, ovvero la dimensione del riquadro (frame) di preview; si consiglia di lasciare inalterata la risoluzione per evitare rallentamenti nel flusso video o nellโ€™invio delle e-mail;
โ€ข fps: imposta i frame al secondo; si consiglia di lasciare il valore predefinito (25) per evitare rallentamenti nel flusso video;
โ€ข min_area: predefinito 5000. รˆ il valore minimo dellโ€™area del riquadro verde che viene creata attorno al soggetto rilevato. Di solito non serve modificarla.

Proseguiamo con lโ€™analisi del codice: lโ€™oggetto camera eredita i metodi della libreria picamera. I parametri della videocamera vengono impostati in base alla lettura dei parametri resolution e fps del file json. Notate lโ€™uso del tipo tuple che in Python permette di creare una lista di valori separati da virgole:

camera = PiCamera()
camera.resolution = tuple(conf[โ€œresolutionโ€])
camera.framerate = conf[โ€œfpsโ€]
rawCapture = PiRGBArray(camera, size=tuple(conf[โ€œresolutionโ€]))

Vengono quindi definite alcune variabili che verranno utilizzate nello script per stabilire il tempo di inizio e di fine della cattura dei frame.

count = 0
avg = None
motionCounter = 0
lastUploaded = datetime.datetime.now()

Allโ€™avvio dello script, si potrร  vedere sul terminale la scritta โ€œAvvioโ€ฆโ€ poi il sistema attende 2 secondi e inizia la cattura video. Si fa notare che nella finestra di preview viene sovraimposto nella parte alta il testo โ€œStato attuale: Nessun movimentoโ€ e, in basso, la data e lโ€™orario (Fig. 11).

 

A questo scopo, viene usata la libreria imutils per ridimensionare il frame e la libreria datetime per lโ€™orario da Internet, per cui lโ€™orario e la data dovrebbe essere precisi.

Con la libreria cv2 si imposta la maschera per rilevare un oggetto in movimento. Si fa notare che il parametro tresh legge il valore di soglia, ovvero il parametro threshold dal file json di configurazione. La variabile motionFlag viene posta a False.

print โ€œAvvio...โ€
time.sleep(2)

Tutta la iterazione for serve a contare i frame e rilevare le differenze della maschera di grigio che viene sovraimposta allโ€™immagine catturata, come illustrato in Fig. 12. Il valore di treshold imposta la soglia di intervento per rilevare il movimento.

Fig. 12 Maschera di contrasto

 

for f in camera.capture_continuous(rawCapture, format=โ€bgrโ€, use_video_port=True):
frame = f.array
timestamp = datetime.datetime.now()
text = โ€œNessun movimentoโ€
motionFlag = False
frame = imutils.resize(frame, width=500)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
if avg is None:

avg = gray.copy().astype(โ€œfloatโ€)
rawCapture.truncate(0)
continue

cv2.accumulateWeighted(gray, avg, 0.5)
frameDelta = cv2.absdiff(gray, cv2.convertScaleAbs(avg))

thresh = cv2.threshold(frameDelta, conf[โ€œthresholdโ€], 255, cv2.THRESH_BINARY)[1]
thresh = cv2.dilate(thresh, None, iterations=2)
(cnts, _) = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
โ€ฆ
โ€ฆ

Rilevato un movimento, il soggetto viene evidenziato con riquadri verdi attorno ai bordi. Quando il valore di soglia viene superato, apparirร  il testo โ€œStato attuale: Movimento rilevatoโ€ e la variabile motionFlag viene posta a True.

text = โ€œMovimento rilevatoโ€
motionFlag = True
ts = timestamp.strftime(โ€œ%A %d %B %Y %I:%M:%S%pโ€)

A questo punto, se la variabile motionFlag รจ True, inizia il confronto fra il tempo corrente (currentTime) e il tempo impostato per il rilevamento (lastTime) impostato dal parametro min_time nel file json e inizia il conteggio dei movimenti rilevati con la variabile motionCounter.

if text == โ€œMovimento rilevatoโ€: 
if (currentTime - lastTime).seconds >= conf[โ€œmin_timeโ€]:
motionCounter += 1

Se il numero dei movimenti rilevati supera quella impostato dal parametro min_motion nel file json, si puรฒ decidere se salvare il file jpg del soggetto. Questa opzione viene impostata dal parametro use_img del file json. Notate che il nome del file img = โ€˜foto_โ€™ + str(count) + โ€˜.jpgโ€™ segue una numerazione progressiva.
I nomi dei file vengono salvati localmente con lโ€™istruzione cv2.imwrite(img, frame) come foto_1.jpg, foto_2.jpg e cosรฌ via.

if motionCounter >= conf[โ€œmin_motionโ€]:
if conf[โ€œuse_imgโ€]:
count += 1
img = โ€˜foto_โ€™ + str(count) + โ€˜.jpgโ€™
cv2.imwrite(img, frame)

Nel frattempo, il LED/relรฉ sul pin GPIO26 viene attivato o disattivato, mentre viene stampato โ€œLED ONโ€ sul terminale, a seconda se viene rilevato o meno il movimento:

GPIO.output(26, GPIO.HIGH)
print โ€œLED ONโ€.

oppure:

print (โ€œLED OFFโ€)
GPIO.output(26,GPIO.LOW)

Se รจ stato impostato lโ€™invio dellโ€™email con il parametro use_email, viene creato lโ€™oggetto part che imposta il formato MIME (Multipurpose Internet Mail Extensions) per comporre il messaggio di posta. Il messaggio viene automaticamente codificato in formato base64 e quindi spedito tramite la funzione email_send(),vista in precedenza.
Il messaggio di posta invierร  in allegato il file โ€œfoto_1.jpgโ€ e successivamente il file โ€œfoto_2.jpgโ€ e cosรฌ via, in base alle volte che la videocamera rileva un nuovo movimento.
La Fig. 13 illustra un esempio di ricezione di unโ€™e-mail di allarme.

 

if conf[โ€œuse_emailโ€]:
part = MIMEBase(โ€˜applicationโ€™, โ€œoctet-streamโ€)
part.set_payload(open(t, โ€œrbโ€).read())
Encoders.encode_base64(part)
part.add_header(โ€˜Content-Dispositionโ€™, โ€˜attachment; filename=โ€™+ img)
email_send()

 

Conclusioni

Per ora รจ tutto. Per fare un poโ€™ di esperienza potete provare a modificare il listato per aggiungere funzionalitร  o modificare i parametri del file json per vedere cosa succede.
Se volete approfondire l’utilizzo di Open CV4 Futura Academy mette a disposizione un corso specifico.

Lascia un commento

Il tuo indirizzo email non sarร  pubblicato.

Menu