Détecter la présence de personnes avec un Lepton

Ceci est un didacticiel permettant de mettre en œuvre un algorithme de recherche de personnes de base avec une caméra FLIR Lepton utilisant la bibliothèque open source de vision par ordinateur OpenCV.

L’objectif

Les caméras thermiques sont idéales pour détecter des mammifères dans presque toutes les conditions d’éclairage. Pour explorer ce qu’ils peuvent faire, essayons de trouver des personnes dans le champ de vision de Lepton et de les entourer d’un contour avec OpenCV.

Les outils

Matériel requis :

  1. Un Lepton
  2. Une carte PureThermal
  3. Un environnement Python 2.7 avec des liaisons OpenCV installées. Il peut s’agir d’une configuration Windows, OSX ou Linux.
  4. PIL si vous souhaitez pouvoir enregistrer des images.

La configuration

Suivez un didacticiel pour votre plateforme spécifique afin de configurer l’environnement Python et d’installer OpenCV. Une fois que vous avez terminé, vérifiez que tout fonctionne en visualisant un flux de webcam.

import 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

Vous devriez pouvoir voir un flux. Si une webcam est connectée ou intégrée à votre ordinateur, vous devrez peut-être remplacer la valeur de cameraID par une valeur autre que 0. Sur ma machine de développement, l’ID de la carte PureThermal est 1.

L’approche

Le code de capture de webcam OpenCV n’est pas capable de capturer des données thermiques radiométriques, qui constitueraient un format idéal pour compter les personnes, mais il vous permet de capturer l’alimentation colorisée d’une carte PureThermal, ce qui sera suffisant pour dessiner des contours avec un peu de prétraitement.

Plus précisément, les humains ont tendance à apparaître comme très lumineux dans la palette de couleurs par défaut ; la conversion des images RVB en HSV et la consultation du canal V donnent une image assez claire de l’emplacement des objets à température corporelle dans la scène.

Essayez en remplaçant cv2.imshow("preview", frame) par ce qui suit :

frame_hsv = cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)
frame_v = frame_hsv[:,:,2]
cv2.imshow("preview", frame_v)

La présence des humains est maintenant évidente, et nous avons une base pour réaliser la vision par ordinateur.

Allez à OpenCV

OpenCV est une bibliothèque de vision par ordinateur très populaire pour C++ avec des liaisons à Python. Elle offre une grande variété d’opérations courantes de vision par ordinateur, que nous allons utiliser pour dessiner nos contours.

La détection des contours par algorithme de Canny est un bon point de départ. Il s’agit d’une technique robuste pour trouver des contours dans une image.

Vous pouvez afficher les contours détectés par OpenCV avec le code suivant :

thresh = 50
edges = cv2.Canny(frame_v,thresh,thresh*2, L2gradient=True)
cv2.imshow("preview", edges)

Mais cela n’est pas encore assez clair. La détection de contour détecte trop de bruit à haute fréquence qu’elle confond avec des contours. Un peu de lissage d’image devrait pouvoir résoudre ce problème. Nous utilisons une méthode de lissage d’image avec conservation des contours appelée filtre bilatéral. Elle est similaire à un flou gaussien, mais a moins d’impact sur les contours que nous cherchons à détecter en premier lieu.

blurredBrightness = cv2.bilateralFilter(frame_v,9,150,150)
thresh = 70
edges = cv2.Canny(blurredBrightness,thresh,thresh*2, L2gradient=True)
cv2.imshow("preview", edges)

Cela se présente mieux, mais il y a encore une marge d’amélioration. Essayons de réduire les éléments tels que les lumières mises en évidence comme étant des personnes. C’est un peu compliqué, mais OpenCV propose une solution pour y parvenir. Commençons par créer une image binaire en délimitant l’image d’origine et en plaçant un 1 là où le pixel est chaud, et un 0 là où il ne l’est pas. Nous utiliserons ensuite OpenCV pour éroder les groupes de 1 créés par cette opération. Nous élargirons ensuite à nouveau ces groupes pour qu’ils retrouvent à peu près la même taille qu’auparavant.

_,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)))

Après l’érosion et la dilatation, l’image binaire reste essentiellement la même, mais toutes les petites formes ont été supprimées. C’est exactement le résultat recherché. Nous pouvons maintenant l’utiliser pour masquer tous les bords qui appartenaient à de petites formes.

Voyons comment cela se présente une fois appliqué aux bords détectés.

Pas mal ! Et cela se présente bien une fois superposé sur l’image source.

Le code final ressemble à ceci. Vous devrez peut-être régler les constantes à votre convenance, et OpenCV fournit une large gamme d’outils que vous pouvez utiliser pour améliorer les résultats en fonction de vos besoins spécifiques.

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

Articles connexes