Como encontrar pessoas com um Lepton

Este é um tutorial para implementar um algoritmo básico de localização de pessoas com uma câmera FLIR Lepton usando a biblioteca de visão computacional de código aberto OpenCV.

A meta

As câmeras termográficas são ótimas para encontrar mamíferos em praticamente qualquer condição de iluminação. Como um exercício para explorar o que eles podem fazer, vamos tentar encontrar pessoas no campo de visão do Lepton e colocar um esboço em torno delas com o OpenCV.

As ferramentas

Hardware de que você precisará:

  1. Um Lepton
  2. Uma placa PureThermal
  3. Um ambiente Python 2.7 com vinculações OpenCV instaladas. Isso pode ser configurado para Windows, OSX ou Linux.
  4. PIL se quiser salvar imagens.

A configuração

Siga um tutorial para sua plataforma específica para configurar o ambiente Python e instalar o OpenCV. Quando terminar, verifique se tudo funciona visualizando um fluxo de webcam.

importar cv2
cv2.namedWindow("visualização")
CameraID = 0
vc = cv2.VideoCapture(cameraID)

se vc.isOpened(): # tente obter o primeiro quadro
rval, frame = vc.read()
mais:
rval = Falso

enquanto rval:
cv2.imshow("visualização", quadro)
rval, frame = vc.read()
tecla = cv2.waitKey(20)
se chave == 27: # sair em ESC
pausa

Isso deve mostrar um fluxo. Se você tiver uma webcam conectada ou integrada ao seu computador, pode ser necessário alterar o CameraID para um valor diferente de 0. Na minha máquina de desenvolvimento, a ID da placa PureThermal é 1.

A abordagem

O código de captura da webcam da OpenCV não é capaz de capturar dados térmicos radiométricos, o que seria um formato ideal para contagem de pessoas, mas permite capturar o feed colorido de uma placa PureThermal, que será bom o suficiente para desenhar contornos com um pouco de pré-processamento.

Especificamente, os humanos tendem a aparecer como muito brilhantes na paleta de cores padrão, portanto, converter as imagens RGB em HSV e olhar para o canal V fornece uma imagem bastante clara de onde os objetos de temperatura corporal estão na cena.

Experimente-o trocando cv2.imshow("preview", frame) pelo seguinte:

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

Agora é muito óbvio onde estão os humanos, e temos algo com que podemos fazer visão computacional.

Insira OpenCV

O OpenCV é uma biblioteca de visão computacional muito popular para C++ com vinculações ao Python. Ela oferece uma ampla variedade de operações comuns de visão computacional, que usaremos para desenhar nossos contornos.

A detecção de borda é onde começaremos. É uma técnica robusta para encontrar bordas em uma imagem.

Você pode visualizar as bordas que o OpenCV detecta com este código:

lima = 50
arestas = cv2.Canny(frame_v,thresh,thresh*2, L2gradient=Verdadeiro)
cv2.imshow("preview", arestas)

No entanto, isso não parece muito bom. A detecção de borda está captando muito ruído de alta frequência e confundindo-a com bordas. Um pouco de suavização de imagem deve ser capaz de resolver isso. Usaremos um método de suavização de imagem que preserva a borda chamado filtro bilateral. Isso é como um desfoque gaussiano, mas tem menos impacto nas bordas que estamos procurando encontrar em primeiro lugar.

blurredBrilho = cv2.bilateralFilter(frame_v,9,150,150)
lima = 70
arestas = cv2.Canny(brilhanteBrilho,limiar,limiar*2, L2gradient=Verdadeiro)
cv2.imshow("preview", arestas)

Isso parece muito melhor, mas ainda há espaço para melhorias. Vamos tentar reduzir coisas como luzes sendo delineadas como pessoas. Isso é complicado, mas o OpenCV oferece uma maneira de fazê-lo. Primeiro, criaremos uma imagem binária ao definir o limite da imagem original e colocar um 1 onde quer que o pixel esteja quente e um 0 onde não esteja. Em seguida, usaremos o OpenCV para erodir as bolhas de 1 criadas por essa operação. Depois disso, expandiremos esses blobs novamente para ter aproximadamente o mesmo tamanho de antes.

_,máscara = cv2.threshold(blurredBrightness,200,1,cv2.THRESH_BINARY)
erodeSize = 5
dilateSize = 7
importar adormecido como np
erodido = cv2.erode(máscara, np.ones((erodeSize, erodeSize)))
máscara = cv2.dilate(erodido, np.ones((dilateSize, dilateSize)))

Após a erosão e a dilatação, a imagem binária é essencialmente a mesma, mas com todas as pequenas formas removidas. É exatamente isso que queremos. Agora podemos usá-lo para mascarar todas as bordas que pertenciam a formas pequenas.

Vamos ver como isso se parece quando aplicado às arestas detectadas.

Nada mal! E ela também parece muito boa sobreposta à imagem de origem.

O código final é algo assim. Você pode precisar ajustar as constantes ao seu gosto, e o OpenCV fornece uma vasta variedade de ferramentas que você pode usar para melhorar os resultados para suas necessidades específicas.

importar cv2
importar adormecido como np
cv2.namedWindow("visualização")
CameraID = 0
vc = cv2.VideoCapture(ID da câmera)

se vc.isOpened(): # tente obter o primeiro quadro
rval, frame = vc.read()
mais:
rval = Falso

enquanto rval:
frame_v = cv2.cvtColor(frame, cv2.COLOR_RGB2HSV)[:,:,2]

blurredBrilho = cv2.bilateralFilter(frame_v,9,150,150)
lima = 50
arestas = cv2.Canny(brilhanteBrilho,limiar,limiar*2, L2gradient=Verdadeiro)

_,máscara = cv2.threshold(blurredBrightness,200,1,cv2.THRESH_BINARY)
erodeSize = 5
dilateSize = 7
erodido = cv2.erode(máscara, np.ones((erodeSize, erodeSize)))
máscara = cv2.dilate(erodido, np.ones((dilateSize, dilateSize)))

cv2.imshow("preview", cv2.resize(cv2.cvtColor(mask*edges, cv2.COLOR_GRAY2RGB) | frame, (640, 480), interpolação = cv2.INTER_CUBIC))

rval, frame = vc.read()
tecla = cv2.waitKey(20)
se chave == 27: # sair em ESC
intervalo