Post de minha autoria originalmente publicado no Embarcados.

Durante o 1° IoT RoadShow 2015 da Intel em São Paulo, participei com a equipe do Embarcados na realização do projeto MonitorAKI, que fez uso primordialmente de Visão Computacional por meio da biblioteca OpenCV. Além, é claro, de enviar mensagens via WhatsApp, conforme demonstrado em outro artigo meu.

Uma das questões que mais me pediram foi acerca de como configurar a Intel Edison para operar com OpenCV, e ainda mais… Como trabalhar com Visão Computacional com uma placa que nem sequer possui saída de vídeo? Isso é realmente uma limitação…? Não! Se não tem saída de vídeo, que tal usar Rede? Ainda mais…Wi-Fi!

Visão Computacional com OpenCV na Intel Edison

Figura 1 – Intel Edison – Não possui saída de vídeo!

Quando se trabalha com Visão Computacional é muito comum a necessidade de realizar ajustes em algoritmos e parâmetros utilizados, sem contar a quantidade de erros que ocorrem até você acertar o ponto no seu programa. Sendo assim, é crucial verificar o resultado do processo, que normalmente se dá na forma de imagem, ou vídeo.

Em uma placa que não possui saída de vídeo ou ambiente desktop, normalmente chamada na literatura de headless, a técnica mais comum era programar o algoritmo para salvar a imagem ou vídeo no sistema de arquivos da placa, e depois remotamente fazer o download dos arquivos para verificar o resultado. Nem preciso dizer que esse processo era demorado, né?

Não somente em se tratando de placas que não possuem saída de vídeo fica o ponto do meu trabalho. Ao se encerrar a interface gráfica e eliminar alguns processos correlacionados, o sistema como um todo fica com mais recursos de memória e processador disponíveis para a execução de algoritmos de Visão Computacional, o que pode levar a um melhor desempenho da placa como um todo.

E se você quiser fazer um robô com câmera? E quiser ver o que o robô… vê? Pela rede?

Pensando nesses detalhes apresentados, escrevi em coautoria com o Thiago Lima e o Prof. Dr. Evandro Luis Linhari Rodrigues o artigo A low cost embedded system with computer vision and video streaming (Um sistema embarcado de baixo custo com visão computacional e transmissão de vídeo), cujo pôster foi apresentado no Workshop de Visão Computacional 2015 (WVC2015) em São Carlos – SP. E agora, demonstro aqui a implementação prática do trabalho, fazendo uso da linguagem Python.

Um pouco de Visão Computacional

Visão Computacional compreende todo um conjunto de técnicas capazes de fazer um computador interpretar imagens de uma maneira tão próxima quanto um ser humano é capaz. Dessa forma, com a aplicação de tais técnicas é possível então fazer um computador reconhecer suas mãos, reconhecer seus gestos, reconhecer seu rosto, realizar sua identificação por impressão digital, etc.

Visão Computacional com OpenCV na Intel Edison: image recognition

Figura 2 – Reconhecimento de Objetos em Imagem. Fonte: thevoice.ottawachamber.ca

Já usou uma câmera digital? Viu que ela normalmente identifica os rostos presentes na imagem? Com certeza ela implementa o algoritmo de Viola-Jones, que detecta padrões numa imagem correspondentes ao rosto humano. Como exemplo, veja a imagem abaixo, demonstrando um exemplo de detecção de faces.

Visão Computacional com OpenCV na Intel Edison: Detecção de Faces

Figura 3 – Detecção de Faces. Fonte: technologyreview.com

Viola-Jones é um dos muitos algoritmos existentes, e a cada dia surgem mais, frutos de intensa pesquisa na área.

Não somente em câmeras digitais estão presentes tais algoritmos. Celulares SmartPhones usam câmeras frontais para acompanhar os olhos do usuário e controlar eventos para leitura e exibição de vídeo, televisores SmartTVs já reconhecem gestos do usuário e temos inclusive o famoso Kinect, usado nos consoles Xbox para controle por gestos e movimentos.

Visão Computacional com OpenCV na Intel Edison: kinect

Figura 4 – Tela de depuração do Kinect em Xbox – Fonte: gamerhub.tv

Você também pode escrever programas que façam uso de visão computacional. Para isso, uma das principais bibliotecas disponíveis é a OpenCV, originalmente criada pela Intel em 1999, e agora mantida por toda uma comunidade de desenvolvedores, com suporte a linguagens tais como C, C++, Python, Java, dentre outras.

Basicamente, toda imagem é uma matriz, cujas linhas e colunas endereçam os pixels da referida imagem. Por sua vez, como estes pixels serão referenciados irá depender se a imagem está em escala de cinza, colorida, etc.

Podemos unicamente realizar algum processo sobre a imagem capturada, e não necessariamente algo de maior inteligência. Dessa forma, estamos na área de Processamento Digital de Imagens. É nesta área que entram técnicas para remover ruídos de imagens, alterar propriedades de brilho, contraste, etc. Ou seja, você aperfeiçoa a imagem ou alguma propriedade importante nela. Se você usa o Instagram e fica brincando com filtros de imagem, sem saber, está usando de técnicas de Processamento Digital de Imagens.

OpenCV pode ser facilmente instalado e configurado em SBCs tais como a Intel Edison, e juntamente com uma Webcam, por exemplo, torna-se possível criar programas capazes de controlar um robô seguidor de linha por imagem, ou um sistema que reconhece gestos e movimentos, ou até mesmo um sistema de segurança que detecta movimento na imagem, tira foto e envia por e-mail, por exemplo. As possibilidades… são infinitas. Mãos à obra?

Configuração da Intel Edison

Antes de tudo, tomarei por base uma placa Intel Edison previamente configurada com Poky Linux da Intel. Caso você queira reconfigurar a sua, pode ver este guia do Diego Sueiro ou o Guia da Intel (inglês).

Agora, certifique-se de duas coisas:

  1. Sua Intel Edison possui acesso à rede local e à Internet;
  2. Sua Intel Edison possui acesso remoto via SSH.

Para o devido funcionamento do sistema, iremos precisar da biblioteca OpenCV devidamente instalada, e da biblioteca NumPy, específica para Python. Em se tratando da Intel Edison, é possível instalar a biblioteca OpenCV para Python somente. Caso queira usar com alguma linguagem tal como C ou C++, será necessário compilar dos fontes.

Para instalar as bibliotecas necessárias, realize os seguintes comandos em um terminal de console (com acesso local ou remoto):

# opkg install python-opencv
# opkg install python-numpy

Feito o processo, vamos conferir se as bibliotecas foram devidamente instaladas. Para isso, inicie o console Python por meio do comando:

# python

E agora verifique se as bibliotecas foram devidamente instaladas digitando:

>> import cv2
>> import numpy

E como saber se está tudo OK?! Simples: Se não aparecer nenhuma mensagem de erro, então tá OK!

Para sair, digite quit() no console Python. Veja o resultado na imagem adiante.

Visão Computacional com OpenCV na Intel Edison: Teste de Imports em Python - Intel Edison

Figura 5 – Teste de Imports em Python – Intel Edison

No meu caso, estou usando uma Câmera USB. Certifique-se que sua Intel Edison esteja reconhecendo devidamente a sua câmera USB. Para verificar isso, digite o seguinte comando no console Linux:

# ls /dev/video*

Se aparecer “/dev/video0”, então está tudo OK. A princípio… Veja como ficou a minha tela:

Visão Computacional com OpenCV na Intel Edison: Resposta ao comando "ls /dev/video0" na Intel Edison.

Figura 6 – Resposta ao comando “ls /dev/video0” na Intel Edison.

Caso  a sua câmera esteja conectada na USB da placa-base da Intel Edison, e mesmo assim não esteja aparecendo, certifique-se que a USB da Intel Edison esteja configurada para Host.

Não tem a Intel Edison? Todos os passos aqui mostrados se aplicam também na Intel Galileo, tanto Gen1 quanto Gen2, como demais SBCs com Linux Embarcado, tal como a Raspberry Pi. Bastando, é claro, ter Python 2.7 instalado, com OpenCV e Numpy.

Arquitetura do Sistema

Como a Intel Edison não possui saída de vídeo, e muito menos um ambiente gráfico em execução, para visualizar em “tempo real” a execução de algoritmos de Visão Computacional iremos então bolar um sistema com as seguintes propriedades:

  1. Linguagem de programação utilizada: Python;
  2. Forma de comunicação: Socket TCP via Rede Ethernet ou Wi-Fi;
  3. Abordagem Cliente-Servidor:
    • Intel Edison: Servidor;
    • Aplicação Desktop: Cliente;
  4. Dispositivo de captura: Câmera USB – WebCam.

Então, a título de exemplo, irei demonstrar uma aplicação escrita em Python executando na Intel Edison, a qual fará a leitura de quadros de uma Webcam conectada em sua porta USB, irá processar (ou não…) estes quadros e os transmitirá pela rede para a aplicação cliente, tal como mostrado na figura a seguir.

Visão Computacional com OpenCV na Intel Edison: Arquitetura do Sistema Proposto

Figura 7 – Arquitetura do Sistema Proposto

Dessa forma, teremos um stream de quadros sendo transmitido, possibilitando ver o resultado do processo realizado na Intel Edison, por exemplo.

Codificação da Aplicação Servidora

Para entender fundamentalmente a aplicação, além de OpenCV também é importante ter noções básicas de Sockets de comunicação. Em termos de Python, alguns conceitos muito breves são apresentados aqui.

A comunicação via rede utilizando sockets precisa de dados “serializados”, ou seja, dados transformados em uma sequência de informações. O que acontece é que uma imagem é uma matriz. Como transformar uma matriz em uma sequência? Basta usarmos o método .array() da biblioteca NumPy e o método .tostring(), que, em sequência, irão serializar um objeto a ser transferido via rede usando Socket.

Na nossa sequência de código para a aplicação servidora, teremos a seguinte lógica:

  1. Criação de objeto de Socket;
  2. Vínculo com IP e Porta de comunicação;
  3. Habilitação de escuta de conexões;
  4. Criação de objeto de captura de imagem;
  5. Parametrização da codificação da imagem;
  6. Aguarda conexão de cliente;
  7. Loop infinito:
    1. Codificação da imagem;
    2. Serialização da imagem;
    3. Transmissão da imagem;
    4. Captura de nova imagem;
  8. Encerramento de objetos de captura e socket.

Adiante, segue o código-fonte desenvolvido para este artigo. Como de costume, está muito bem comentado, apresentando detalhes e informações acerca de cada trecho e rotina. Leia com atenção.

Como base, crie um arquivo chamado openCV-Server.py em sua Intel Edison, e cole o seguinte trecho de código mostrado abaixo. Salve o arquivo.

#!/usr/bin/python
import socket
import cv2
import numpy

# Variaveis para armazenar IP e porta de comunicacao
TCP_IP = '' # campo vario - vincula a todos os ips que a maquina possui na rede
TCP_PORT = 5052

# Criacao do socket de comunicacao para servidor
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Vincula o socket de servidor com o IP e Porta. IP = '' - rede
serverSocket.bind((TCP_IP,TCP_PORT))
# Habilita que socket de servidor ira escutar requisicoes
serverSocket.listen(True)

# Cria objeto de captura vinculado a device 0 - webcam
capture = cv2.VideoCapture(0)
# Captura um quadro para verificar conexao
ret, frame = capture.read()

# Parametrizacao da codificacao de imagem a ser transmitirda
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY),90]

print 'Aguardando conexoes...'
# Aguarda conexao com cliente e cria objeto "conn" - socket
conn, add = serverSocket.accept()
while ret:
    # codifica o quadro de imagem em formato jpg e grava em imgencode
    result, imgencode = cv2.imencode('.jpg', frame, encode_param)
    # tranforma imgencode em vetor - serializacao
    data = numpy.array(imgencode)
    # converte o vetor em string
    stringData = data.tostring()
    # Envia comprimento do quadro de imagem, com 16 caracteres justificado a esquerda
    conn.send(str(len(stringData)).ljust(16));
     # Envia quadro de imagem serializado em string
    conn.send(stringData)
    # Realiza leitura de quadro da webcam, grava em frame
    ret,frame = capture.read()
# Encerra conexao com camera usb - webcam
capture.release()
# Encerra o socket de comunicacao
serverSocket.close()

Após ter salvado o arquivo, é preciso dar ao mesmo permissão de execução, o que é possível por meio do seguinte comando:

# chmod +x openCV-Server.py

Agora, para executar o programa basta digitar:

# ./openCV-Server.py

Feito isso, a aplicação será iniciada, e ficará aguardando uma conexão da aplicação Cliente. Agora vamos à codificação da aplicação cliente.

Codificação da Aplicação Cliente

O objetivo da aplicação cliente é conectar na aplicação servidora pela rede, receber os quadros de imagem via socket e exibir esse stream para o usuário em uma janela.

A aplicação cliente pode ser executada tanto em ambiente Windows, quanto em ambiente Linux. Bastando que Python esteja instalado, juntamente com as bibliotecas OpenCV e Numpy também! Dessa forma, o presente exemplo foi executado em ambiente Windows 10 por meio do IDLE – Python’s Integrated Development and Learning Environment. O IDLE possui tanto o acesso ao console Python, como também pode criar arquivos Python. Basta ir na opção File -> New, que aparecerá uma janela onde você poderá tranquilamente digitar seu código Python com destaque para palavras da sintaxe.

Em se tratando de ambiente Windows, veja como instalar o Python, com suporte a OpenCV para Python aqui. Neste mesmo link também é informado onde baixar o Numpy. E sobre como instalar e configurar o Python com OpenCV para ambiente Linux, tendo como base o Ubuntu, veja aqui.

Na nossa sequência de código para a aplicação cliente, teremos a seguinte lógica:

  1. Criação de objeto de Socket;
  2. Conexão com máquina servidora;
  3. Loop infinito:
    1. Recebe tamanho da imagem;
    2. Recebe imagem completa;
    3. Reconstrói array de dados de string;
    4. Decodifica a imagem do array de dados;
    5. Exibe a imagem em janela para o usuário;
    6. Se digitar ‘q’, encerra loop;
  4. Encerramento de objetos de captura e socket.

Um método criado à parte para usar com a aplicação cliente, que receberá os quadros de imagem, é o recvall, método que irá receber como parâmetros um socket e uma quantidade de dados, quantidade que será usada como base de “tamanho” para retornar então a informação esperada. Tive uma base de inspiração para o modelo cliente-servidor utilizado no artigo neste tópico do StackOverflow.

Vamos então à codificação? Crie um arquivo na sua Máquina Desktop (Windows ou Linux – devidamente configurados com Python + OpenCV + Numpy, chamado  openCV-Client.py, e cole o conteúdo de código apresentado adiante. Veja, novamente, que o código está muito bem comentado e apresenta detalhes sobre comandos e trechos de código.

import socket
import cv2
import numpy

# Rotina recvall - trata de receber informacao
def recvall(sock, count):
    buf = b''
    while count:
        newbuf = sock.recv(count)
        if not newbuf: return None
        buf += newbuf
        count -= len(newbuf)
    return buf

# Atribui IP da estacao servidora - Intel Edison
TCP_IP = '192.168.1.13'
# Porta de comunicacao
TCP_PORT = 5052

# Cria objeto socket para comunicacao
conn = socket.socket()

# Faz conexao com estacao servidora
conn.connect((TCP_IP,TCP_PORT))

# Loop infinito: Recebe imagem, exibe. Se digitar q - sai.
while True:
    # Recebe tamanho da imagem
    length = recvall(conn,16)
    # Recebe imagem propriamente
    stringData = recvall(conn, int(length))
    # Recupera a imagem serializada em forma de string
    data = numpy.fromstring(stringData, dtype='uint8')
    # Decodifica a imagem
    decimg=cv2.imdecode(data,1)
    # Exibe a imagem
    cv2.imshow('EdisonCAM',decimg)
    # Se digitar 'q', encerra.
    if(cv2.waitKey(1) & 0xFF == ord('q')):
        break

# Fecha as janelas do OpenCV
cv2.destroyAllWindows()
# Encerra o socket    
conn.close()

Em se tratando do IDLE, em ambiente Windows, basta ir na opção “Run -> Run Module” para executar o código Python escrito. De outra forma, basta apertar F5 para iniciar a execução.

Em ambiente Linux, será preciso chamar o código em linha de comando, tal como:

$ python openCV-Client.py

Se tudo correr certo, a aplicação irá conectar na Intel Edison, e logo aparecerá uma janela mostrando os quadros de imagem. Caso haja um certo delay, um atraso entre o cenário real e o exibido na janela, é normal. Temos um overhead de processamento ao usarmos Python, serialização de objeto, etc…

Caso não apareça sua janela, veja o erro ocorrido. Certifique-se de usar o IP correto da Intel Edison, de que a porta de comunicação está disponível, dentre outras coisas.

Execução

Veja na Figura 8 o console de execução na Intel Edison. A aplicação servidora foi iniciada e aguarda conexões.

Visão Computacional com OpenCV na Intel Edison: conexão com Server

Figura 8 – Tela de console Linux da Intel Edison – Servidor Iniciado.

Na Figura 9, é mostrado o IDLE em execução, com a janela de Shell, janela de código, e a janela do stream de quados mostrando o resultado do processo.

Visão Computacional com OpenCV na Intel Edison: Execucao do PythonClientEdison

Figura 9 – Execução da aplicação Cliente – Exibição da janela de stream de imagens

E na Figura 10 é mostrada uma foto da montagem da Intel Edison correspondente.

Visão Computacional com OpenCV na Intel Edison: montagem da Intel Edison com Câmera USB

Figura 10 – Cenário real da montagem da Intel Edison com Câmera USB.

Aplicação Servidora – Aprimorada

Agora, vamos pensar no seguinte cenário: E se a aplicação servidora pudesse ser parametrizada? Ou seja, e se durante a execução do sistema, fosse possível mudar o algoritmo em execução, alterar parâmetros deste algoritmo, etc…?

Para isso, basta tratar na aplicação cliente e na aplicação servidora uma comunicação bidirecional. Ou seja, a aplicação servidora agora passará a receber parâmetros de comando da aplicação cliente, e esta, por sua vez, passará a enviar parâmetros de comando, conforme digitado pelo usuário. Agora, o usuário poderá ter o poder de mudar a forma como que os quadros serão processados na máquina servidora.

No exemplo em questão, irei trabalhar de forma que a aplicação trabalhe com 4 estados distintos, além de poder ser encerrada pela aplicação cliente, tendo por base os seguintes comandos recebidos via Socket:

  • normal – Operação normal, não altera o quadro capturado;
  • canny – Aplica o Filtro de Canny na imagem capturada;
  • gray – Aplica a conversão de espaço de cores de colorida à escala de cinza na imagem capturada;
  • blur – Aplica um filtro causando efeito de atenuação na imagem – efeito de “Blur”;
  • sair – Encerra a aplicação.

Dessa forma, a aplicação servidora passa a ter a seguinte sequência de lógica de funcionamento:

  1. Criação de objeto de Socket;
  2. Vínculo com IP e Porta de comunicação;
  3. Habilitação de escuta de conexões;
  4. Criação de objeto de captura de imagem;
  5. Parametrização da codificação da imagem;
  6. Aguarda conexão de cliente;
  7. Loop infinito:
    1. Leitura de comando da aplicação cliente;
    2. Codificação da imagem;
    3. Serialização da imagem;
    4. Transmissão da imagem;
    5. Captura de nova imagem;
    6. Processo de imagem conforme comando;
  8. Encerramento de objetos de captura e socket.

De modo a diferenciar o código simplificado do código aprimorado, crie um novo arquivo para o código da aplicação servidora na Intel Edison, chamado openCV-Server-Tunado.py, e coloque neste arquivo o código de programa mostrado adiante. Veja os comentários e os trechos que tratam de avaliar o recebimento de comandos da aplicação cliente, e o processo de quadros com base nestes comandos.

#!/usr/bin/python
import socket
import cv2
import numpy

# IP de vinculo - '' geral na maquina
TCP_IP = ''
# Porta de conexao
TCP_PORT = 5052

#Variavel para estado de funcionamento - comando recebido do cliente
comando = 'normal'
#Variavel para kernel de blur
kernel = numpy.ones((5,5), numpy.float32)/25
#Tamanho de buffer de comunicacao
BUFFER_SIZE = 20

# Criacao do socket de comunicacao para servidor
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Vincula o socket de servidor com o IP e Porta. IP = '' - rede
serverSocket.bind((TCP_IP,TCP_PORT))
# Habilita que socket de servidor ira escutar requisicoes
serverSocket.listen(True)

# Cria objeto de captura vinculado a device 0 - webcam
capture = cv2.VideoCapture(0)
# Captura um quadro para verificar conexao
ret, frame = capture.read()

# Parametrizacao da codificacao de imagem a ser transmitirda
encode_param = [int(cv2.IMWRITE_JPEG_QUALITY),90]

print 'Aguardando conexoes...'
# Aguarda conexao com cliente e cria objeto "conn" - socket
conn, add = serverSocket.accept()

# Enquanto houver retorno de quadro na webcam
while ret:
    # Espera envio de comando da maquina cliente.
    estado = conn.recv(BUFFER_SIZE)
    # codifica o quadro de imagem em formato jpg e grava em imgencode
    result, imgencode = cv2.imencode('.jpg', frame, encode_param)
    # tranforma imgencode em vetor - serializacao
    data = numpy.array(imgencode)
    # converte o vetor em string
    stringData = data.tostring()
    # Envia comprimento do quadro de imagem, com 16 caracteres justificado a esquerda
    conn.send(str(len(stringData)).ljust(16));
    # Envia quadro de imagem serializado em string
    conn.send(stringData)
    # Realiza leitura de quadro da webcam, grava em frame
    ret,frame = capture.read()
    # processo do quadro conforme parametro enviado pela maquina cliente
    if comando == 'normal':
 	# Se for normal, nao faz nada.
        frame = frame 
    elif comando == 'canny':
	# Se for canny, aplica o detector de bordas.
        frame = cv2.Canny(frame,100,200)
    elif comando == 'gray':
	# Se for blackwhite - aplica transformacao de cor
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    elif comando == 'blur':
	# Se for blur, aplica filtro parametrizado
        frame = cv2.filter2D(frame, -1, kernel)
    elif comando == 'sair':
	# Se for sair, encerra.
        break

# Encerra conexao com camera usb - webcam
capture.release()
# Encerra o socket de comunicacao
serverSocket.close()

Para executar o programa, digite o seguinte comando no console Linux da Intel Edison:

# ./openCV-Server-Tunado.py

A aplicação será iniciada e aguardará a conexão da aplicação cliente.

Aplicação Cliente – Aprimorada

Não obstante, a aplicação cliente agora também deve implementar uma comunicação bidirecional, ou seja, deve ser capaz de também enviar mensagens, comandos para a aplicação servidora. E como a “coisa” está arquitetada, constantemente a aplicação servidora precisa receber o parâmetro indicando como deve processar o quadro de imagem capturado pela câmera USB. Dessa forma, constantemente também a aplicação cliente deverá enviar o comando que determina isso.

Assim sendo, a aplicação cliente terá uma variável chamada estado, que irá variar conforme as seguintes teclas digitadas pelo usuário:

  • n – Ao digitar n, o estado atual é ‘normal’, e não é feita nenhuma modificação na imagem capturada pela Edison;
  • w – Ao digitar w, o estado atual será ‘gray’, e a aplicação servidora irá tornar os quadros de imagem capturados de colorido para escala de cinza;
  • c – Ao digitar c, o estado atual passa para ‘canny’, em que a aplicação servidora irá então aplicar o Filtro de Canny nos quadros de imagem subsequentes;
  • b – Ao digitar b, o estado será ‘blur’, e a aplicação servidora irá passar a aplicar o respectivo filtro em cada imagem capturada;
  • q – Ao digitar q, a aplicação será encerrada, enviando também comando para encerrar a aplicação servidora.

Com o estado definido, a cada execução do loop infinito while true é então enviado o estado de operação para a aplicação servidora, que o tomará por base para a execução do correspondente algoritmo ou ação sobre a imagem capturada, e podendo eventualmente até mesmo encerrar a própria aplicação servidora.

Dito isso, veja abaixo o código da aplicação cliente devidamente comentado, indicando campos, trechos e rotinas de código com suas correspondentes funcionalidades. Para reproduzir o feito, salve o código em um arquivo com nome openCV-Client-Tunado.py para logo ser executado.

import socket
import cv2
import numpy
def recvall(sock, count):
    buf = b''
    while count:
        newbuf = sock.recv(count)
        if not newbuf: return None
        buf += newbuf
        count -= len(newbuf)
    return buf

# Atribui IP da estacao servidora - Intel Edison
TCP_IP = '192.168.1.13'
# Porta de comunicacao
TCP_PORT = 5052

# Cria variavel para referencia de estado de operacao - comeca normal
estado = 'normal'
# Cria objeto socket para comunicacao
conn = socket.socket()

# Faz conexao com estacao servidora
conn.connect((TCP_IP,TCP_PORT))
# Envia estado de operacao via socket
conn.send(estado)

# Loop infinito - recebe quadro de imagem, exibe, verifica tecla digitada
# pelo usuario. 
while True:
    length = recvall(conn,16)
    stringData = recvall(conn, int(length))
    data = numpy.fromstring(stringData, dtype='uint8')
    decimg=cv2.imdecode(data,1)
    cv2.imshow('EdisonCAM',decimg)
    if(cv2.waitKey(1) & 0xFF == ord('c')):
        estado = 'canny'
        print 'Estado de operacao: Canny'
    elif(cv2.waitKey(1) & 0xFF == ord('w')):
        estado = 'gray'
        print 'Estado de operacao: Escala de Cinza'
    elif(cv2.waitKey(1) & 0xFF == ord('b')):
        estado = 'blur'
        print 'Estado de operacao: Blur'
    elif(cv2.waitKey(1) & 0xFF == ord('n')):
        estado = 'normal'
        print 'Estado de operacao: Normal'
    elif(cv2.waitKey(1) & 0xFF == ord('q')):
        estado = 'sair'
        print 'Encerrando aplicacao...'
        break
    conn.send(estado)

# Fecha as janelas do OpenCV
cv2.destroyAllWindows()
# Encerra socket de conexao
conn.close()

Salvado o arquivo, é possível executá-lo no IDLE pressionando a tecla F5, ou em ambiente Linux por meio do comando em console:

$ ./openCV-Client-Tunado.py

Se tudo correr bem, irá aparecer uma janela com o stream de imagem, colorida, normal. Para mudar o estado de operação e verificar a “imediata” mudança no processo, mantenha pressionada a tecla correspondente até que a aplicação cliente faça a leitura. Pode demorar “um pouquinho”. Assim que a aplicação cliente lê o comando do usuário, o mesmo é transmitido para a aplicação servidora, que passa a mudar seu processo. Veja o resultado em execução!

Execução da solução aprimorada

Para execução da solução cliente-servidor aprimorada, agora dispondo de comunicação bidirecional e mudança de estado de operação, é preciso inicialmente começar a execução da aplicação servidora na Intel Edison. Veja na Figura 11 a aplicação servidora sendo iniciada.

Visão Computacional com OpenCV na Intel Edison: Iniciando Servidor Tunado na Intel Edison

Figura 11 – Iniciando Servidor Tunado na Intel Edison

E na máquina cliente, é então iniciada a aplicação. Com isso, surge a janela com o stream de imagens, agora podendo ser alterado pelas teclas configuradas na aplicação. Ao pressionar ‘c’, por exemplo, é informado que o estado de operação passa a ser ‘Canny’, devendo então a aplicação servidora realizar o correspondente algoritmo nos quadros capturados a partir de então. Veja na Figura 12 como ficou o resultado deste exemplo:

Visão Computacional com OpenCV na Intel Edison: Edison + Cliente Tunado

Figura 12 – Exemplo de execução da Aplicação Cliente “Tunada”

E adiante seguem as janelas de exibição para cada estado/modo de exibição. Na Figura 13 é mostrada a janela de captura para Estado Normal, na Figura 14 é mostrada a janela de captura para Estado Escala de Cinza, na Figura 15 é mostrada a janela de captura para Estado Blur, e na Figura 16 é mostrada a janela de captura para Estado Canny. Veja em cada imagem o resultado do processo.

Visão Computacional com OpenCV na Intel Edison: Edison Normal

Figura 13 – Execução Normal.

Visão Computacional com OpenCV na Intel Edison: Edison em Grayscale

Figura 14 – Execução em Escala de Cinza.

Visão Computacional com OpenCV na Intel Edison: Edison com Blur

Figura 15 – Execução em modo Blur.

Visão Computacional com OpenCV na Intel Edison: Edison com Canny

Figura 16 – Execução em Modo Canny.

Adiante segue também o vídeo que preparei, justamente quando acabei de escrever este artigo:

Gostou? Ficou interessado em Python e OpenCV?

Caso afirmativo, você pode fazer o curso de Python no CodeAcademy, e se quiser ver mais detalhes acerca de Python com OpenCV, o site PyImageSearch é uma opção, além do Python OpenCV Tutorials, sem esquecer, é claro, da documentação com exemplos oficiais.

Sinta-se à vontade para basear projetos nos códigos apresentados. As possibilidades são infinitas. Agora você pode controlar um robô com câmera, visualizando a câmera do robô e demais processos realizados sobre a imagem que ele captura. Ou melhor, você pode fazer um sistema de segurança com reconhecimento facial ou detecção de objetos, tais como faces humanas!

O que você vai fazer?

Facebooktwittergoogle_plusredditpinterestlinkedinmailby feather