Búsqueda de personas con un Lepton
Este es un tutorial para implementar un algoritmo básico de búsqueda de personas con una cámara FLIR Lepton utilizando la biblioteca de visión artificial de código abierto OpenCV.
El objetivo
Las cámaras térmicas son excelentes para encontrar mamíferos en casi cualquier condición de iluminación. Como ejercicio para explorar lo que pueden hacer, intentemos encontrar gente en el campo de visión de Lepton y pongamos un esquema a su alrededor con OpenCV.
Las herramientas
El hardware que necesitará:
- Un Lepton
- Una placa PureThermal
- Un entorno de Python 2.7 con enlaces OpenCV instalados. Esto se puede configurar para Windows, OSX o Linux.
- PIL si desea poder guardar imágenes.
La configuración
Siga un tutorial para su plataforma específica para configurar el entorno de Python y OpenCV instalado. Cuando haya terminado, compruebe que todo funciona viendo una secuencia de cámara web.
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
Esto debería mostrarle una secuencia. Si tiene una cámara web conectada o integrada en su ordenador, es posible que tenga que cambiar el ID de la cámara a un valor distinto de 0. En mi máquina de desarrollo, el ID de la placa PureThermal es 1.
El enfoque
El código de captura de la cámara web OpenCV no es capaz de capturar datos térmicos radiométricos, lo que sería un formato ideal para el recuento de personas, pero sí permite capturar la alimentación coloreada de una placa PureThermal, lo que será lo suficientemente bueno para dibujar contornos con un poco de procesamiento previo.
Concretamente, las personas tienden a mostrarse muy brillantes en la paleta de colores por defecto, por lo que convertir las imágenes RGB a HSV y mirar el canal V proporciona una imagen bastante clara de dónde están los objetos de temperatura corporal en la escena.
Pruébelo intercambiando cv2.imshow("preview", frame) con lo siguiente:
frame_hsv = cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)
frame_v = frame_hsv[:,:,2]
cv2.imshow("preview", frame_v)
Ahora es bastante obvio dónde están las personas y tenemos algo con lo que podemos hacer visión artificial.
Introducir OpenCV
OpenCV es una biblioteca de visión artificial muy popular para C++ con enlaces a Python. Ofrece una amplia variedad de operaciones de visión artificial comunes, que utilizaremos para dibujar nuestros esquemas.
La detección de bordes de Canny es donde empezaremos. Es una técnica robusta para encontrar bordes en una imagen.
Puede ver los bordes que OpenCV detecta con este código:
thresh = 50
edges = cv2.Canny(frame_v,thresh,thresh*2, L2gradient=True)
cv2.imshow("preview", edges)
Pero esto no tiene muy buen aspecto. La detección de bordes está captando demasiado ruido de alta frecuencia y confundiéndolo con los bordes. Un pequeño suavizado de imagen debería poder solucionarlo. Utilizaremos un método de suavizado de imagen con conservación de bordes llamado filtro bilateral. Es como un difuminado gausiano, pero tiene menos impacto en los bordes que buscamos en primer lugar.
blurredBrightness = cv2.bilateralFilter(frame_v,9,150,150)
thresh = 70
edges = cv2.Canny(blurredBrightness,thresh,thresh*2, L2gradient=True)
cv2.imshow("preview", edges)
Esto tiene un aspecto mucho mejor, pero todavía hay margen de mejora. Vamos a intentar reducir cosas como las luces que se delinean como personas. Esto es complicado, pero OpenCV proporciona una forma de hacerlo. En primer lugar, crearemos una imagen binaria estableciendo el umbral de la imagen original y poniendo un 1 donde el píxel esté caliente, y un 0 donde no lo está. A continuación, utilizaremos OpenCV para erosionar en los blobs de 1 creados por esa operación. Después de eso, volveremos a expandir esos blobs para que tengan aproximadamente el mismo tamaño que antes.
_,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)))
Después de la erosión y la dilatación, la imagen binaria se deja básicamente igual, pero con todas las formas pequeñas eliminadas. Eso es exactamente lo que queremos. Ahora podemos usarlo para ocultar todos los bordes que pertenecían a formas pequeñas.
Veamos cómo se ve esto cuando se aplica a los bordes detectados.
¡No está mal! Además, también parece bastante bien superpuesta en la imagen de origen.
El código final tiene un aspecto similar al siguiente. Es posible que necesite ajustar las constantes a su gusto, y OpenCV proporciona una amplia variedad de herramientas que podría utilizar para mejorar los resultados para sus necesidades específicas.
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