Trovare persone con un Lepton
Questo è un tutorial per l'implementazione di un algoritmo di base di rilevamento delle persone con una fotocamera FLIR Lepton che utilizza la libreria open source di visione artificiale OpenCV.
L’obiettivo
Le termocamere sono ideali per trovare i mammiferi in quasi tutte le condizioni di illuminazione. Come esercizio per esplorare cosa possono fare, proviamo a trovare persone nel campo visivo di Lepton e mettiamo un contorno intorno a loro con OpenCV.
Gli strumenti
Hardware di cui avrai bisogno:
- Una Lepton
- Una scheda PureThermal
- Un ambiente Python 2.7 con associazioni OpenCV installate. È possibile configurare Windows, OSX o Linux.
- PIL se si desidera salvare le immagini.
La configurazione
Segui un tutorial per la tua piattaforma specifica per configurare l'ambiente Python e installare OpenCV. Una volta terminato, verificare che tutto funzioni visualizzando uno stream di webcam.
importa cv2
cv2.namedWindow("preview")
cameraID = 0
vc = cv2.VideoCapture(cameraID)
if vc.isOpened(): # try to get the first frame
rval, frame = vc.read()
else:
rval = False
while rval:
cv2.imshow("preview", frame)
rval, frame = vc.read()
key = cv2.waitKey(20)
if key == 27: # exit on ESC
break
Questo dovrebbe mostrare uno stream. Se nel computer è collegata o integrata una webcam, potrebbe essere necessario modificare l'ID della videocamera in un valore diverso da 0. Sul mio computer di sviluppo, l’ID della scheda PureThermal è 1.
L’approccio
Il codice di acquisizione della webcam di OpenCV è in grado di acquisire dati termici radiometrici, il che sarebbe un formato ideale per il conteggio delle persone, ma consente di acquisire il feed colorato da una scheda PureThermal, che sarà abbastanza buono per disegnare contorni con un po' di pre-elaborazione.
In particolare, gli esseri umani tendono a essere molto luminosi nella tavolozza colori predefinita, quindi convertire le immagini RGB in HSV e guardare il canale V offre un’immagine abbastanza chiara della posizione degli oggetti a temperatura corporea nella scena.
Provare scambiando cv2.imshow("preview", frame) con quanto segue:
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)
frame_v = frame_hsv[:,:,2]
cv2.imshow("preview", frame_v)
Ora è abbastanza ovvio dove si trovano gli esseri umani e abbiamo qualcosa con cui possiamo fare la visione computerizzata.
Entra in OpenCV
OpenCV è una libreria di visione artificiale molto popolare per C++ con associazioni a Python. Offre un’ampia varietà di operazioni comuni di visione computerizzata, che utilizzeremo per disegnare i nostri bordi.
Il rilevamento dei bordi Canny è il punto di partenza. È una tecnica efficace per trovare i bordi in un'immagine.
È possibile visualizzare i bordi rilevati da OpenCV con questo codice:
thresh = 50
edges = cv2.Canny(frame_v,thresh,thresh*2, L2gradient=True)
cv2.imshow("preview", edges)
Questo però non ha un bell’aspetto. Il rilevamento dei bordi sta rilevando troppo rumore ad alta frequenza e lo scambia per dei bordi. Un piccolo livellamento dell'immagine dovrebbe essere in grado di risolvere il problema. Utilizzeremo un metodo di livellamento dell’immagine con conservazione del bordo chiamato filtro bilaterale. È come una sfocatura gaussiana, ma ha un impatto minore sui bordi che cerchiamo di trovare in primo luogo.
blurredBrightness = cv2.bilateralFilter(frame_v,9,150,150)
thresh = 70
edges = cv2.Canny(blurredBrightness,thresh,thresh*2, L2gradient=True)
cv2.imshow("preview", edges)
Sembra molto meglio, ma c’è ancora margine di miglioramento. Proviamo a ridurre le cose come le luci che vengono delineate come persone. È complicato, ma OpenCV offre un modo per farlo. In primo luogo, creeremo un’immagine binaria impostando una soglia all’immagine originale e inserendo un 1 dove il pixel è caldo e uno 0 dove non lo è. Quindi, utilizzeremo OpenCV per erodere i blocchi di 1 creati da tale operazione. Dopodiché, espandiamo di nuovo quelle macchie per avere le stesse dimensioni di prima.
_,mask = cv2.threshold(blurredBrightness,200,1,cv2.THRESH_BINARY)
erodeSize = 5
dilateSize = 7
import numpy as np
eroded = cv2.erode(mask, np.ones((erodeSize, erodeSize)))
mask = cv2.dilate(eroded, np.ones((dilateSize, dilateSize)))
Dopo erosione e dilatazione, l’immagine binaria viene essenzialmente lasciata uguale, ma con tutte le piccole forme rimosse. È esattamente ciò che vogliamo. Ora possiamo usarla per nascondere tutti i bordi che appartenevano a forme piccole.
Vediamo come appare quando viene applicato ai bordi rilevati.
Non male! E non è male anche se lo sovrapponiamo all'immagine sorgente.
Il codice finale è simile a questo. Potrebbe essere necessario regolare le costanti in base alle proprie preferenze; OpenCV fornisce un vasto assortimento di strumenti che è possibile utilizzare per migliorare i risultati in base alle proprie esigenze specifiche.
import cv2
import numpy as np
cv2.namedWindow("preview")
cameraID = 0
vc = cv2.VideoCapture(cameraID)
if vc.isOpened(): # try to get the first frame
rval, frame = vc.read()
else:
rval = False
while rval:
frame_v = cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)[:,:,2]
blurredBrightness = cv2.bilateralFilter(frame_v,9,150,150)
thresh = 50
edges = cv2.Canny(blurredBrightness,thresh,thresh*2, L2gradient=True)
_,mask = cv2.threshold(blurredBrightness,200,1,cv2.THRESH_BINARY)
erodeSize = 5
dilateSize = 7
eroded = cv2.erode(mask, np.ones((erodeSize, erodeSize)))
mask = cv2.dilate(eroded, np.ones((dilateSize, dilateSize)))
cv2.imshow("preview", cv2.resize(cv2.cvtColor(mask*edges, cv2.COLOR_GRAY2RGB) | frame, (640, 480), interpolation = cv2.INTER_CUBIC))
rval, frame = vc.read()
key = cv2.waitKey(20)
if key == 27: # exit on ESC
break