1. Introdução
Nosso projeto implementa um sistema de detecção de borda em tempo real, com base na captura de quadros de imagem de uma câmera OV7670 e no seu streaming para um monitor VGA após a aplicação de um filtro em escala de cinza e do operador Sobel. Nosso design é construído em uma placa FPGA Cyclone IV, que nos permite otimizar o desempenho usando os poderosos recursos do hardware de baixo nível e cálculos paralelos, o que é importante para atender aos requisitos do sistema em tempo real.
Usamos a placa de desenvolvimento ZEOWAA FPGA, baseada no ciclone IV (EP4CE6E22C8N). Além disso, usamos o Quartus Prime Lite Edition como ambiente de desenvolvimento e o Verilog HDL como linguagem de programação. Além disso, usamos a interface VGA integrada para acionar o monitor VGA e o GPIO (pinos gerais para entrada e saída) para conectar o hardware externo à nossa placa.

Arquitetura
Nosso design é dividido em 3 partes principais:
- Lendo os pixels de dados da câmera.
- Implementando nosso algoritmo de detecção de borda (conversor de escala de cinza e operador Sobel).
- Exibindo a imagem final através da interface com um monitor VGA.
Além disso, existe um armazenamento de memória intermediário entre a leitura / gravação dos dados e a operação nesses dados. Para esse fim, implementamos dois buffers que funcionam como espaço temporário para pixels antes de serem usados.

Observe que, depois de tirarmos o pixel da câmera, não o armazenamos diretamente no buffer de memória intermediário. Em vez disso, a convertemos para a escala de cinza e a armazenamos no buffer. Isso ocorre porque o armazenamento de pixels em escala de cinza de 8 bits requer menos memória do que o armazenamento dos pixels coloridos de 16 bits. Além disso, temos outro buffer que armazena os dados após a aplicação do operador Sobel para prepará-los para serem exibidos no monitor.
Aqui estão os detalhes sobre a implementação de nossa arquitetura:
Camera
Usamos a câmera OV7670, que é um dos módulos de câmera mais baratos que encontramos. Além disso, esta câmera pode funcionar em 3.3V e não precisa de protocolos de comunicação difíceis, como I2c ou SPI, para extrair os dados da imagem. Requer apenas interface SCCB, que é semelhante à interface I2c, para definir a configuração da câmera em termos de formato de cor (RGB565, RGB555, YUV, YCbCr 4: 2: 2), resolução (VGA, QVGA, QQVGA, CQ, QCIF) e muitas outras configurações.

O vídeo consiste em quadros que estão sendo alterados a uma taxa específica. Um quadro é uma imagem que consiste em linhas e colunas de pixels, onde cada pixel é representado por valores de cores. Neste projeto, usamos a configuração padrão da câmera em que o tamanho do quadro é a resolução VGA 640 x 480 (0,3 megapixels) e o formato de cor do pixel é RGB565 (5 bits para vermelho, 6 bits para azul, 5 bits para verde) ) e a taxa de alteração dos quadros é de 30 fps.
Abaixo, as conexões da câmera ao FPGA usando o GPIO existente na placa de desenvolvimento:
Pin na câmera | pino no FPGA | Descrição do produto | Pin na câmera | pino no FPGA | Descrição do produto |
---|
3.3V | 3.3V | Fonte de Alimentação (+) | GND | GND | Nível de fornecimento terrestre (-) |
Sdioc | GND | Relógio SCCB | SDIOD | GND | Dados SCCB |
VSYNC | P31 | Sincronização vertical | Href | P55 | Sincronização horizontal |
PCLK | P23 | Relógio de pixel | Xclk | P54 | Relógio do sistema de entrada (25 MHz) |
D7 | P46 | 8º bit de dados | D6 | P44 | Sétimo bit de dados |
D5 | P43 | 6º bit de dados | D4 | P42 | Quinto bit de dados |
D3 | P39 | 4º bit de dados | D2 | P38 | Terceiro bit de dados |
D1 | P34 | Segundo bit de dados | D0 | P33 | 1º bit de dados |
RESET (ativo baixo) | 3.3V | Redefinir pino | PWDN | GND | Pino de desligamento |
Observe que não usamos a interface SCCB para configuração. Então, colocamos seus fios correspondentes no chão para evitar qualquer sinal flutuante que possa afetar os dados.
Para fornecer o relógio de 25MHz para a câmera, usamos PLL (Phase-Locked Loop), que é um sistema de controle de frequência em loop fechado para fornecer o relógio necessário a partir dos 50MHz fornecidos pela placa. Para implementar o PLL, usamos a ferramenta de catálogo IP interno no software Quartus.
Esta câmera usa o sinal de sincronização vertical (VSYNC) para controlar o processo de envio do quadro e o sinal de sincronização horizontal (HREF) para controlar o envio de cada linha do quadro. Esta câmera usa apenas 8 linhas de dados (D0-D7) para transferir os bits que representam os valores de cor do pixel, pois ela divide o valor do pixel RGB de 16 bits em 2 partes (8 bits) e envia cada uma separadamente.
As figuras abaixo da folha de dados do módulo da câmera OV7670 ilustram os sinais da sincronização vertical e horizontal.



Conversor de escala de cinza
Para produzir uma imagem em escala de cinza a partir de sua imagem colorida original, muitos fatores devem ser levados em consideração, pois a imagem pode perder contraste, nitidez, sombra e estrutura. Além disso, a imagem deve preservar a luminância relativa do espaço de cores. Várias técnicas lineares e não lineares são usadas para converter a imagem colorida em escala de cinza. Dessa forma, para atingir nosso objetivo, usamos a conversão colorimétrica (preservação da luminosidade perceptiva) em escala de cinza representada na seguinte equação:

Para aprimorar o desempenho em termos de cálculos, é mais rápido usar o operador shift. Portanto, a equação acima pode ser reduzida para o seguinte:

Como resultado, após capturar um valor de pixel (565 RGB) da câmera, ele pode ser convertido imediatamente em um valor de pixel em escala de cinza de 8 bits, aplicando a fórmula da conversão. A imagem em escala de cinza é mais fácil de armazenar na memória e rápida o suficiente para atender à funcionalidade do nosso sistema em tempo real, pois sua complexidade é aproximadamente logarítmica e o FPGA pode torná-lo ainda mais rápido acessando a memória em paralelo. Depois disso, a imagem armazenada está pronta para implementar o algoritmo de detecção de borda.
Temos dois buffers, o primeiro é usado para armazenar os pixels após convertê-los em escala de cinza e seu tamanho (8 bits x 150 x 150) e o segundo é usado para armazenar os pixels após a aplicação do operador Sobel e o limite para o valor de saída e seu tamanho (1 bit x 150 x 150). Infelizmente, os buffers de 150 x 150 não armazenam a imagem inteira da câmera, mas armazenam apenas parte dela.
Escolhemos o tamanho de nossos buffers como 150 x 150 por causa da limitação da memória do ciclone IV, pois ele possui apenas 276,480 Kbit, enquanto nossos dois buffers recebem 202,500 Kbit (150 x 150 x 9), o que equivale a 73,24% da memória original do o ciclone IV e o restante da memória são usados para armazenar o algoritmo e a arquitetura. Além disso, tentamos (170 x 170) como um tamanho para nossos buffers, que retiram 94,07% da memória, o que não deixa espaço suficiente na implementação do algoritmo.
Nossos buffers são a verdadeira RAM de porta dupla, que pode ler e gravar em diferentes ciclos de clock simultaneamente. Aqui, criamos nossa implementação em vez de usar a ferramenta de catálogo IP no software Quartus para ter mais flexibilidade na implementação. Além disso, integramos os dois buffers em apenas um módulo em vez de ter módulos diferentes.
Operador Sobel
Utilizamos um primeiro operador de detecção de borda derivada, que é um operador de gradiente de área da matriz que determina a mudança de luminância entre diferentes pixels. Para ser mais preciso, por ser um método direto e eficiente em termos de uso de memória e complexidade de tempo, usamos o operador de gradiente Sobel que usa o núcleo 3x3 centralizado em um pixel escolhido para representar a força da borda. O operador Sobel é a magnitude do gradiente calculado por:

Onde Gx e Gy podem ser representados usando máscaras de convolução:

Observe que os pixels mais próximos do centro da máscara recebem mais peso. Além disso, G x e G y podem ser calculados da seguinte forma:

Onde pi é o pixel correspondente na seguinte matriz e o valor de pi é um valor em escala de cinza de 8 bits:

É uma prática comum aproximar a magnitude do gradiente do operador Sobel por valores absolutos:

Essa aproximação é mais fácil de implementar e mais rápida de calcular, o que novamente serve à nossa funcionalidade em termos de tempo e memória.
Aqui está o diagrama de blocos do operador Sobel, que recebe 9 (8 bits) pixels como entrada e produz um valor de pixel (8 bits):

E aqui está o diagrama de blocos detalhado da implementação do operador Sobel.

Monitor VGA
Nossa placa de desenvolvimento possui uma interface VGA incorporada, capaz de exibir apenas 8 cores no monitor VGA, pois possui apenas 3 bits para controlar as cores através de um bit para vermelho, um para verde e um para azul. Isso tornou nossa depuração mais difícil, pois nos impede de exibir a imagem da câmera diretamente no monitor. Portanto, usamos um limite para converter os pixels em valor de 1 bit, para que seja possível exibir a imagem.
A interface VGA funciona como a câmera, pois opera pixel por pixel do canto superior esquerdo ao canto inferior direito. Usando a sincronização vertical e horizontal, podemos sincronizar os sinais que controlam o fluxo de pixels.
O sinal de sincronização vertical é usado para representar o índice da linha, enquanto o sinal de sincronização horizontal é usado para representar o índice da coluna. Além disso, ambos os sinais usam a varanda frontal, o pulso de sincronização e a varanda traseira como sinais de sincronização para separar a linha antiga da nova linha no sinal de sincronização horizontal e o quadro antigo do novo quadro no sinal de sincronização vertical.

Usamos a interface de sinal VGA padrão (640 x 480 a 60 MHz). Todas as especificações padrão do sinal são descritas aqui .
Teste
Antes de juntar tudo e testar o sistema em tempo real. Primeiro tivemos que testar cada parte separadamente. Inicialmente, verificamos os valores e sinais que vêm da câmera exibindo certos valores de pixel. Então, com a ajuda do OpenCV usando a linguagem de programação Python, pudemos aplicar o filtro Sobel em várias imagens para comparar os resultados com nosso algoritmo e verificar a exatidão de nossa lógica. Além disso, testamos nossos buffers e driver VGA exibindo várias imagens estáticas no monitor VGA após aplicar o operador Sobel e o limiar. Além disso, alterando o valor do limite, a precisão da imagem é afetada.
O código python que usamos:
Resultados
Como resultado de nossa implementação, obtivemos um sistema de detecção de borda em tempo real que produz uma imagem de 150x150 após a aplicação do filtro em escala de cinza e do operador Sobel. O sistema implementado fornece 30 fps. A câmera funciona com um relógio de 25 MHz e o sistema, em geral, cumpre os prazos em tempo real sem atraso perceptível. Além disso, o valor limite pode afetar a quantidade de detalhes e o ruído na imagem final.
Aqui está uma comparação entre o operador Sobel no FPGA e o operador sobel OpenCV:

Abaixo está um vídeo ilustrativo dos resultados:

Aqui está o link do repositório no Github, que possui todos os códigos-fonte.
Melhorias futuras
Como estamos usando o FPGA Cyclone IV, estamos limitados à sua capacidade de memória e ao número de portas lógicas. Portanto, como uma melhoria futura, podemos usar uma fonte de memória externa ou implementar nosso trabalho em outra placa para exibir todos os pixels da imagem recebida da câmera.
Além disso, embora o operador Sobel seja rápido e simples de implementar, é notavelmente sensível ao ruído. Para eliminar o ruído produzido, podemos usar um filtro de ruído como o filtro mediano não linear que funciona perfeitamente bem com o nosso sistema se tivermos memória suficiente para implementar um terceiro buffer. Isso produzirá uma imagem mais suave com os recursos nítidos removidos.
Dessa forma, usamos a interface VGA integrada do FPGA, que só pode produzir uma imagem de 3 bits. Portanto, não foi possível exibir a imagem em escala de cinza, pois ela precisa de 8 bits para ser exibida. Como resultado, implementar outra interface ou usar uma placa mais poderosa aumentará a flexibilidade de exibir a imagem.
Conclusão
Conseguimos usar nosso conhecimento e compreensão de conceitos cruciais em sistemas embarcados como máquinas de estado, paralelismo de computação e interface de hardware e software para criar um aplicativo eficiente de detecção de borda que atenda aos nossos objetivos.
Agradecimentos
Este projeto é construído por uma equipe composta por dois estudantes: Hussein Youness e Hany Hamed no primeiro ano de bacharel em Ciência da Computação na Universidade de Innopolis, na Rússia.
Este projeto faz parte do curso de Arquitetura da Computação no outono de 2018 na Universidade de Innopolis .