FAVORITAR
Faça login para como favoritoFechar

Contagem de objetos em movimento com OpenCV e Python usando Raspberry Pi

A visão computacional é fantástica. Com este recurso, um sistema computacional “aprende a enxergar” e, com isso, fazer tarefas cada vez mais complexas e úteis ao dia a dia moderno, tais como: identificar objetos, identificar pessoas e/ou faces, reconhecer objetos e obter características deles, determinar movimento de objetos, mensurar velocidade de objetos, e por aí vai. E o sistema computacional em questão pode ser uma Single-Board Computer comum, como uma Raspberry Pi, por exemplo.

Neste artigo será mostrado um uso da Raspberry Pi em visão computacional: com base no OpenCV e Python, permitir contagem de objetos em movimento utilizando visão computacional.

Material necessário

Para reproduzir este projeto, serão necessários os seguintes materiais:

  • Uma Raspberry Pi 3B (com cartão de tamanho recomendado de 16GB);
  • Uma webcam qualquer*;
  • Fonte de alimentação para Raspberry Pi.

* Pode ser qualquer modelo, desde que seja compatível com o Linux rodando na Raspberry Pi.

Embarcados Experience 2024: Evento Presencial

Participe do Embarcados Experience 2024 em São Paulo. Conhecimento técnico, palestras, workshops e oportunidade de networking com profissionais experientes.

Inscreva-se agora

Montagem

Assumindo que você já tem controle sobre a Raspberry Pi (seja por acesso via VNC, SSH ou por um teclado e mouse nela conectados), a montagem do hardware é muito simples: basta ligar a webcam USB a uma das portas USB da Raspberry Pi.

Preparação: Instalação do OpenCV na Raspberry Pi

Antes de prosseguir com o projeto, é necessário instalar o OpenCV na Raspberry Pi. No caso, isto envolverá compilar o OpenCV na Raspberry (processo um tanto quanto lento, mas que garante máximo desempenho deste na Raspberry Pi). Para isso, recomendo fortemente seguir o tutorial deste link.

Observação: apesar do tutorial recomendar a utilização de um virtual environment (para “isolar” o OpenCV das demais dependências e bibliotecas do Python no Linux), eu não segui este conselho. Escolhi esta opção pois, no meu “quadro geral de bibliotecas”, convém ter disponível a OpenCV para todo o sistema. Ou seja, foi uma opção baseada no meu uso pessoal. Portanto, se você quiser não utilizar um virtual environment (e fazer como eu fiz), sinta-se à vontade.

Overview do projeto

O projeto em questão se trata de um contador de objetos em movimento, com contagens independentes para objetos saindo e entrando na zona monitorada. Veja a figura 1.

OpenCV e Python - Zona monitorada e suas definições
Figura 1 – Zona monitorada e suas definições

Procedimento de contabilização

O incremento da contagem se dá quando o centróide do objeto (será explicado a seguir a definição deste) cruza uma das linhas de referência. Portanto, não importa o tamanho do objeto e tão pouco sua forma, a contabilização será feita sem mais problemas.

A contabilização de objetos é feita com base em duas características:

  • Somente objetos em movimento serão detectados;
  • A contabilização ocorre somente se o objeto cruzar uma das linhas de referência;
  • A direção do movimento importa.

Ambas as características combinadas permitem contabilizar não só o número bruto de objetos que passaram, mas sim quantos objetos entraram e saíram da zona monitorada.

OpenCV e Python - Detecção de direção do movimento de um objeto com base nas linhas de referência
Figura 2 – Detecção de direção do movimento de um objeto com base nas linhas de referência

 A contabilização de objetos em movimento será feita da seguinte forma:

  • Contabilização de objetos que entraram na zona monitorada: tudo que cruza a linha azul, vindo a partir da linha vermelha (ou seja, está entre as linhas de referência, mas cruza a linha azul), será contabilizado como entrada da zona de monitoramento. Esta situação está evidenciada na Figura 2.a.
  • Contabilização de objetos que entraram na zona monitorada: analogamente, qualquer objeto que cruza a linha vermelha, vindo da linha azul (ou seja, está entre as linhas de referência, mas cruza a linha vermelha), será contabilizado como saída da zona de monitoramento. Esta situação está evidenciada na Figura 2.b.

Importante:

A captura de frames do stream da câmera e processamento de imagem de cada frame logo em seguida faz com que a captura de frames não seja em tempo real. Isso significa que alguns quadros podem ser ignorados / perdidos. Isso leva a uma conclusão ruim: há chances de que o exato quadro do centróide do objeto cruzando uma das linhas de referência seja perdido, afetando assim a contagem e funcionamento do projeto como um todo. Para minimizar este problema, foi adotada uma solução de tolerância de cruzamento das linhas de referência.

Tal tolerância consiste em uma faixa de 2 pixels, para cima e para baixo da linha de referência. Se o centróide estiver nessa zona de tolerância, é considerado que este está cruzando a linha de referência em questão. Observe a figura 3.

Zona de tolerância (onde é considerado que o centróide está cruzando uma linha de referência
Figura 3 – Zona de tolerância (onde é considerado que o centróide está cruzando uma linha de referência

Raciocínio do projeto para a detecção de objetos em movimento

Conforme explicado no tópico anterior, tem-se um raciocínio claro de como detectar que um objeto cruzou uma linha de referência e, além disso, saber sua direção. Agora, será visto como detectar um objeto em movimento. As etapas a seguir são executadas no processamento/tratamento de imagens na ordem que são apresentadas.

Realce do objeto em movimento

Na física, para classificar se algo está em movimento ou não, deve-se adotar uma referência. Aqui, o princípio é o mesmo: para saber se há movimento, compara-se um frame capturado recentemente com um frame-referência. Esta comparação consiste em um recurso de visão computacional chamado subtração de background. Este recurso consiste em eliminar o máximo possível de informações irrelevantes da imagem (o fundo dela, por exemplo, daí o “background” do nome) e realçar características desejadas. Cada aplicação tem um método adequado de subtração de background, pois cada aplicação vai querer realçar uma determinada característica da imagem.

No caso deste projeto, a subtração de background é feita da forma mais intuitiva possível: uma imagem em escala de cinza é, basicamente, um grande array bidimensional. Portanto, quaisquer operações matemáticas pixel-a-pixel (ou qualquer outro tipo de operação matricial) podem ser feitas. Considerando isso, dois frames (um capturado recentemente e um frame-referência) são convertidos para escala de cinza, sofrem ação do filtro Gaussian Blur (para suavizar contornos, o que permitirá deixar objetos mais “uniformes” nas etapas subsequentes de tratamento/processamento de imagem) e subtraídos (ponto-a-ponto / pixel-a-pixel), de modo que somente o que variou de um frame para outro seja realçado. Isso acontece pois, como objetos em movimento vão, obrigatoriamente, causar variações em relação ao frame-referência, e portanto estes serão realçados pela subtração de background. Sendo assim, após a subtração do background, idealmente ficará em destaque somente o objeto em movimento. É importante ressaltar aqui que, na prática, devido às características de iluminação e da captura de frames da câmera utilizada, praticamente nunca dois frames terão resultados perfeitos da subtração do background (somente com o objeto em movimento realçado). 

Um frame com o background subtraído e o movimento realçado em cores mais claras pode ser visto na figura 4.

Frame com background subtraído e objeto em movimento realçado por cores mais claras
Figura 4 – Frame com background subtraído e objeto em movimento realçado por cores mais claras

Binarização

Normalmente em visão computacional, após realçar as características desejadas, bizariza-se a imagem. Isso é feito pois, matematicamente, é muito mais simples se trabalhar com imagens binarizadas (de apenas 2 valores possíveis de cor), levando a uma redução drástica de demanda de processamento do hardware que executa o projeto/análise. Aqui, isto não é diferente.

O único ponto de atenção aqui é o threshold (limite do valor de cor do pixel, que vai de 0 a 255 em escala de cinza, para se atribuir valor preto ou branco). Infelizmente, este é fortemente dependente da iluminação do local. Portanto, muito provavelmente este valor deve ser ajustado, de caso para caso. Na figura 5, ve-se o frame após binarização.

Imagem após binarização com threshold adequado
Figura 5 – Imagem após binarização com threshold adequado

Dilatação

Os objetos em movimento até aqui detectados, suavizados e binarizados já estão quase na sua forma ideal para se trabalhar. O “quase” se caracteriza por haver possibilidade de existirem “buracos” no meio de objetos (ou seja, objetos que não são uma “massa” de imagem). Se existirem, estes buracos prejudicarão o posterior processamento/tratamento de imagem, aumentando as chances de erros na identificação de contornos (etapa posterior). Isso ocorre pois, em uma imagem com buracos, podem ser detectados contornos falsos (ou contornos dentro de contornos), afetando assim a contagem final de objetos em movimento.

Para eliminar esta possibilidade, é feito o processo de dilatação. No final deste processo, os objetos serão uma “massa” única de pixels de uma só cor.

Procura por contornos (e seu centróide)

Neste ponto, temos o objeto realçado / bem definido e sem “buracos” / falhas (ou seja, objetos aqui são uma “massa” de pixels de uma só cor). Essa “massa” de pixels, em visão computacional, é chamada de contorno. 

Agora, o que é feito é a detecção dos contornos da imagem (= objetos em movimento) considerando suas áreas (em pixels²). Desta detecção, é feita a obtenção das coordenadas e dimensões de retângulos que “cercam” os objetos. Uma vez em posse destes dados, o centro deste retângulo equivalerá ao centróide do objeto em questão. Portanto, temos aqui uma vantagem: todo o movimento do objeto pode ser analisado pelo movimento de seu centróide.

Outra grande vantagem é que, por considerarmos apenas o centróide do objeto na análise de seu movimento, não importa no algoritmo de contagem nem o tamanho tão pouco a forma do objeto em questão. 

Na figura 6, ve-se em preto o centróide do objeto em movimento e, em verde, o retângulo que envolve o contorno do objeto detectado.

Frame colorido, com destaque para centróide do objeto em movimento (em preto) e do retângulo que envolve o contorno do objeto detectado (em verde)
Figura 6 – Frame colorido, com destaque para centróide do objeto em movimento (em preto) e do retângulo que envolve o contorno do objeto detectado (em verde)

Análise da posição do centróide de cada objeto em relação às linhas e referência

Uma vez analisando a trajetória do objeto através de seu centróide, basta comparar a coordenada Y do mesmo com as coordenadas Y das linhas de referência e, com base nisso, aplicar o algoritmo explicado no tópico “Procedimento de contabilização”. Desta forma, contabiliza-se quem entrou e saiu da zona monitorada.

Com isso, chega-se ao fim do processamento de imagens do projeto.

Código-fonte

Para visualizar o código-fonte do projeto, acesse-o no meu GitHub clicando aqui. Por favor, atente-se aos comentários antes de utilizar o projeto.

Para clonar o repositório e utilizar / rodar o projeto, utilize os comandos abaixo:

Demonstração – GIF Animado

Segue uma demonstração do projeto em ação, no formato de GIF animado:

GIF animado do projeto em ação
GIF animado do projeto em ação

Melhorias

Assim como todo projeto de visão computacional, este projeto pode estar sujeito a erros. Por esse motivo, é importante sempre melhorar o código (processo que chamo aqui de melhoria contínua) e deixá-lo menos sujeito a variações e características irrelevantes das imagens. Portanto, listo aqui alguns pontos de melhoria contínua deste projeto:

  1. O funcionamento do mecanismo de tolerância de cruzamento de linha de referência funciona corretamente se o fluxo de objetos for ininterrupto (ou seja, não haver chance do objeto “parar” sobre a tolerância). Portanto, melhorar este mecanismo seria muito importante, dependendo de seu uso (sugestão: marcar o objeto contado, de forma que não seja contado novamente);
  2. Melhorar o processo de dilatação e Blur, de modo que o sistema dependa menos do valor de threshold de binarização e valor mínimo da área de objeto detectado;
  3. Melhoria de tempo de processamento de imagens para minimizar perda de quadros (sugestão: reduzir o tamanho da imagem antes de trabalhar com a mesma).

Aprenda mais

Aplicação de visão computacional com OpenCV

Visão Computacional com OpenCV na Intel Edison

OpenCV 2.4.9 + QT5 no Ubuntu

Instalando SimpleCV no Ubuntu

Referências

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
32 Comentários
recentes
antigos mais votados
Inline Feedbacks
View all comments
FABIANO DE FREITAS
FABIANO DE FREITAS
07/10/2021 17:26

Alguém aí tem um projeto em que o python identifica quantos elementos estão se movimentando e conte o total deles?

Fernando
Fernando
08/09/2019 10:33

Muito bom mesmo, saberia dizer se há alguma biblioteca, ou algo do tipo que reconheça por exemplo se o objeto é um carro? Estou iniciando na parte de visão computacional e estou com este projeto em mente. Abraços

Joselito Junior
Reply to  Fernando
06/12/2019 11:12

Bom dia Fernando, também estou iniciando em visão computacional, com relação a tua pergunta primeiramente você precisa definir alguns pontos, por exemplo, os carros estarão parados ou em movimento? Você quer apenas reconhecer que existe um carro ou definir um carro específico? Pois pra realizar o reconhecimento podem ser usadas algumas técnicas como, definição por tamanho, por cor, por tipo do contorno, etc.

Fernando
Fernando
Reply to  Joselito Junior
30/03/2020 16:57

Amigo, perdão a demora, mas teria alguma bibliografia que sugeres?

Luis Mendonca
Luis Mendonca
30/01/2019 08:50

Bom dia Pedro, quando rodo seu codigo, recebo o seguinte erro:

$ python ContadorObjetosEmMovimento.py
Traceback (most recent call last):
File “ContadorObjetosEmMovimento.py”, line 50, in
height = np.size(Frame,0)
File “/usr/lib/python2.7/dist-packages/numpy/core/fromnumeric.py”, line 2700, in size
return asarray(a).shape[axis]
IndexError: tuple index out of range

Saberia me dizer o que e? Estou usando Raspbian Strecth mais novo e OpenCv 3.3.0 .

Luis Mendonca
Luis Mendonca
Reply to  Luis Mendonca
04/02/2019 10:02

Consegui resolver meu erro Pedro, ajustando parte do codigo para funcionar tambem com a camera do proprio raspberry ao inves de uma webcam. Se for util para voce, aqui esta o codigo alterado, tomei a liberdade tambem de adicionar algumas novas funcionalidades, como fechar o programa por uma tecla ou por tempo, escrever os resultados em um arquivo e tambem envia-lo por email. Grande abraco! https://pastebin.com/f5Z4eBC7

Matheus Cunha
Matheus Cunha
08/10/2018 16:57

Olá Pedro, li todo o tutorial porem quando compilo o código fonte no meu Raspberry o seguinte erro é printado na tela: ” File “ContadorObjetosEmMovimento.py”, line 20
return 1
^
TabError: inconsistent use of tabs and spaces in indentation

Juan
Juan
Reply to  Matheus Cunha
09/10/2018 11:29

Eu estou tentando testar no meu computador usando Jupyter Notebook e aparece o mesmo.

FABIANO DE FREITAS
FABIANO DE FREITAS
Reply to  Matheus Cunha
07/10/2021 17:24

consegui corrigir esses erros usando a mesma quantidade de espaços na indentação.
exemplo
if (condições): #4 barras de espaços aqui ou 1 tab
instruçoes # 8 espaços aqui ou 2 tabs

o importante para o erro TabError sair é que no bloco if, na indentação seja apenas com espaços ou apenas com tabulações, daí o erro some

Guilherme Chiqueti
Guilherme Chiqueti
16/10/2017 08:49

Você conseguiu fazer um texto de forma que até um iniciante em visão computacional como eu conseguisse entender. Parabéns pelo nível de explicação e formatação do texto.

Julio Calvo
Julio Calvo
03/10/2017 23:07

Hola.
Cómo vocé hizo para no instalar el entorno virtual?
Yo he tratado de instalar OpenCV siguiendo el tutorial del link pero siempre tengo errores.
No estoy seguro si estoy ignorando los comandos correctos.
Ya he intentado 15 veces, con diferentes maneras, pero no logro instalar OpenCV en mi Raspberry Pi.
Gracias.

Igor Felipe Gallon
Igor Felipe Gallon
26/08/2017 17:33

Parabéns pelo projeto! Muito bem explicado, fácil de entender! Porém quando fui testar na minha Raspberry (para testar o openCV), surgiu o seguinte erro: https://uploads.disquscdn.com/images/4a007049e133e5e2d9a1dc222939900666ed4e8df5359d5ccc9d9db188253b8d.png

phfbertoleti
phfbertoleti
Reply to  Igor Felipe Gallon
27/08/2017 16:00

Igor, boa tarde.

Você seguiu o procedimento de instalação do OpenCV por completo, incluindo isntalação do numpy?

Atenciosamente,
Pedro Bertoleti

Igor Felipe Gallon
Igor Felipe Gallon
Reply to  phfbertoleti
28/08/2017 09:55

Sim, segui. Estou utilizando o módulo Python picamera e não uma câmera USB. Seria esse o problema?

phfbertoleti
phfbertoleti
Reply to  Igor Felipe Gallon
28/08/2017 10:01

Olha, não sei dizer, pois nunca usei uma camera diferente de USB. Você teria disponibilidade de testar com uma camera USB?

Igor Felipe Gallon
Igor Felipe Gallon
Reply to  phfbertoleti
28/08/2017 21:02
phfbertoleti
phfbertoleti
Reply to  Igor Felipe Gallon
29/08/2017 10:08

Isso tá com cara que, por alguma razão, a resolução da sua câmera é um número ímpar, seja na altura e/ou largura.
Acabei de atualizar o código no github forçando a resolução da câmera para 640×480, mesma resolução que utilizei no desenvolvimento. Baixe por favor o código-fonte novamente e teste.

Igor Felipe Gallon
Igor Felipe Gallon
Reply to  phfbertoleti
30/08/2017 14:55

Essa configuração não funcionou também. Eu andei procurando e achei que o problema estaria no “cv2.VideoCapture” que não reconhece bem o módulo pi camera. Então fiz um workaround seguindo esse tutorial https://www.pyimagesearch.com/2016/01/04/unifying-picamera-and-cv2-videocapture-into-a-single-class-with-opencv/

Agora está funcionando!

phfbertoleti
phfbertoleti
Reply to  Igor Felipe Gallon
30/08/2017 16:41

Opa, boas noticias! Desculpa não ter conseguido responder sua pergunta, eu nunca trabalhei com este modulo pi camera.

Fico feliz que deu certo!

Igor Felipe Gallon
Igor Felipe Gallon
26/08/2017 17:32

Parabéns pelo projeto, código de fácil entendimento! Tentei rodar na minha Raspberry (para testar o openCV) e apareceu o seguinte erro:

Juraci Nascimento
Juraci Nascimento
23/08/2017 15:32

Parabéns Pedro, muito bom o artigo. Estou tentando utilizar ele como teste no Python p/ windows e estou tendo alguns problemas para rodar. No entanto gostaria de ter o seu contato pois tenho uma aplicação que estou desenvolvendo e acredito que seria interessante contratar sua assessoria. Obrigado

phfbertoleti
phfbertoleti
Reply to  Juraci Nascimento
24/08/2017 12:02

Juraci, muito obrigado pela leitura e elogios!

Vi seu e-mail agora, acabei de responder. Por favor, de uma olhada.

Diego Andrade
Diego Andrade
21/08/2017 22:28

Parabéns cara, muito bem explicado! Já tive a oportunidade de trabalhar em um projeto parecido e acho essa área muito legal.

phfbertoleti
phfbertoleti
Reply to  Diego Andrade
22/08/2017 08:31

Diego, muito obrigado

Home » Hardware » Placas de desenvolvimento » Contagem de objetos em movimento com OpenCV e Python usando Raspberry Pi

EM DESTAQUE

WEBINARS

LEIA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste:


Seminário de
Sistemas Embarcados e IoT 2024
 
Data: 25/06 | Local: Hotel Holiday Inn Anhembi, São Paulo-SP
 
GARANTA SEU INGRESSO

 
close-link