Manufaturação industrial
Internet das coisas industrial | Materiais industriais | Manutenção e reparo de equipamentos | Programação industrial |
home  MfgRobots >> Manufaturação industrial >  >> Industrial programming >> VHDL

Lendo Imagens BMP Bitmap em Testbenches VHDL com TEXTIO

Ao trabalhar com testbenches VHDL, a maneira mais simples de importar uma imagem é usar o formato de gráficos raster BMP. Arquivos BMP são nativamente suportados pelo Windows e expõem dados de pixel brutos sem compressão, tornando-os ideais para simulação.

Este artigo explica como ler um arquivo BMP binário, armazenar seus dados de pixel em memória dinâmica, alimentá-lo a um DUT VHDL e gravar a imagem processada de volta em um novo arquivo BMP. O DUT de exemplo realiza conversão para escala de cinza, mas a técnica se aplica a qualquer módulo de processamento pixel a pixel.

Parte de uma série TEXTIO:

Por que BMP é o Formato Ideal para VHDL

JPEG e PNG são ubíquos na web, mas ambos empregam compressão. JPEG é lossy, PNG é lossless; ambos adicionam uma camada de complexidade quando um testbench deve acessar dados de pixel diretamente. BMP, por outro lado, armazena dados de imagem como gráficos raster não comprimidos, então cada pixel é representado por bytes RGB brutos. Isso elimina a necessidade de código de descompressão em VHDL e garante tempo de simulação determinístico.

Editores de imagem comuns como Photoshop ou GIMP carregam imagens na memória como dados raster internamente. Para VHDL, converter a imagem fonte para BMP manualmente (ou via script) é a abordagem mais direta.

Preparando o Arquivo BMP

Use o Windows Paint para garantir um layout de arquivo consistente:

  1. Abra a imagem.
  2. Selecione File > Save As.
  3. Escolha 24-bit Bitmap (*.bmp; *.dib) e salve.

Com este método, o cabeçalho do arquivo será sempre a variante de 54 bytes BITMAPINFOHEADER com formato de pixel RGB24. A tabela a seguir lista os campos do cabeçalho que lemos.

Offset (Dec)Size (B)Expected (Hex)Description
0242 4DID field
10454 (36 00 00 00)Pixel array offset
14440 (28 00 00 00)Header size
184Read valueImage width in pixels
224Read valueImage height in pixels
26101Number of color planes
28118Number of bits per pixel

Apenas os campos sombreados em verde são essenciais; o resto serve como verificação de sanidade.

O Caso de Teste

Abaixo está um DUT mínimo de escala de cinza que aceita entrada RGB de 24 bits e outputs o valor de luminância correspondente codificado de volta em RGB. O módulo é puramente combinacional, então nenhum clock é necessário.

entity grayscale is port ( r_in : in std_logic_vector(7 downto 0); g_in : in std_logic_vector(7 downto 0); b_in : in std_logic_vector(7 downto 0); r_out : out std_logic_vector(7 downto 0); g_out : out std_logic_vector(7 downto 0); b_out : out std_logic_vector(7 downto 0) ); end grayscale; 

Para completude, o código fonte completo do projeto (incluindo um BMP Boeing 747 de 1000x1000 pixels) está disponível para download fornecendo um endereço de e-mail no formulário linkado.

Importando TEXTIO

No topo do seu arquivo VHDL adicione:

use std.textio.all; use std.env.finish;

Estas declarações requerem VHDL-2008 ou mais recente.

Tipos Personalizados para Armazenamento de Imagem

Defina os seguintes tipos na região declarativa do seu testbench:

type header_type is array (0 to 53) of character; type pixel_type is record red : std_logic_vector(7 downto 0); green : std_logic_vector(7 downto 0); blue : std_logic_vector(7 downto 0); end record; type row_type is array (integer range <>) of pixel_type; type row_pointer is access row_type; type image_type is array (integer range <>) of row_pointer; type image_pointer is access image_type;

Estas estruturas de dados dinâmicas permitem que o testbench acomode imagens de qualquer tamanho sem limites de array estático.

Instanciando o DUT

signal r_in, g_in, b_in : std_logic_vector(7 downto 0); signal r_out, g_out, b_out : std_logic_vector(7 downto 0); begin DUT : entity work.grayscale port map ( r_in => r_in, g_in => g_in, b_in => b_in, r_out => r_out, g_out => g_out, b_out => b_out ); 

Lendo o Cabeçalho BMP

O processo começa carregando o cabeçalho de 54 bytes em uma variável header e validando campos-chave com declarações assert. Esta guarda previne uso acidental de formato de arquivo não suportado.

for i in header_type'range loop read(bmp_file, header(i)); end loop; -- Basic sanity checks assert header(0) = 'B' and header(1) = 'M' report "First two bytes are not ""BM"". This is not a BMP file" severity failure; assert character'pos(header(10)) = 54 and character'pos(header(11)) = 0 and character'pos(header(12)) = 0 and character'pos(header(13)) = 0 report "Pixel array offset is not 54 bytes" severity failure; assert character'pos(header(14)) = 40 and character'pos(header(15)) = 0 and character'pos(header(16)) = 0 and character'pos(header(17)) = 0 report "DIB header size is not 40 bytes, is this a Windows BMP?" severity failure; assert character'pos(header(26)) = 1 and character'pos(header(27)) = 0 report "Color planes is not 1" severity failure; assert character'pos(header(28)) = 24 and character'pos(header(29)) = 0 report "Bits per pixel is not 24" severity failure;

Após validação, a largura e altura da imagem são extraídas:

image_width := character'pos(header(18)) + character'pos(header(19)) * 2**8 + character'pos(header(20)) * 2**16 + character'pos(header(21)) * 2**24; image_height := character'pos(header(22)) + character'pos(header(23)) * 2**8 + character'pos(header(24)) * 2**16 + character'pos(header(25)) * 2**24; report "image_width: " & integer'image(image_width) & ", image_height: " & integer'image(image_height);

Lendo Dados de Pixel

Cada linha BMP é preenchida para múltiplo de quatro bytes. Calcule o padding por linha e aloque armazenamento dinâmico para a imagem.

padding := (4 - image_width*3 mod 4) mod 4; image := new image_type(0 to image_height - 1); for row_i in 0 to image_height - 1 loop row := new row_type(0 to image_width - 1); for col_i in 0 to image_width - 1 loop read(bmp_file, char); row(col_i).blue := std_logic_vector(to_unsigned(character'pos(char), 8)); read(bmp_file, char); row(col_i).green := std_logic_vector(to_unsigned(character'pos(char), 8)); read(bmp_file, char); row(col_i).red := std_logic_vector(to_unsigned(character'pos(char), 8)); end loop; for i in 1 to padding loop read(bmp_file, char); end loop; -- discard padding image(row_i) := row; end loop;

Testando o DUT

Alimente cada pixel no DUT, espere um pequeno ciclo delta, e capture a saída em escala de cinza.

for row_i in 0 to image_height - 1 loop row := image(row_i); for col_i in 0 to image_width - 1 loop r_in <= row(col_i).red; g_in <= row(col_i).green; b_in <= row(col_i).blue; wait for 10 ns; row(col_i).red := r_out; row(col_i).green := g_out; row(col_i).blue := b_out; end loop; end loop;

Gravando o BMP de Saída

Primeiro, grave o cabeçalho preservado. Depois, serializa os dados de pixel linha por linha, adicionando padding onde necessário. Finalmente, limpe memória dinâmica e feche os arquivos.

for i in header_type'range loop write(out_file, header(i)); end loop; for row_i in 0 to image_height - 1 loop row := image(row_i); for col_i in 0 to image_width - 1 loop write(out_file, character'val(to_integer(unsigned(row(col_i).blue)))); write(out_file, character'val(to_integer(unsigned(row(col_i).green)))); write(out_file, character'val(to_integer(unsigned(row(col_i).red)))); end loop; deallocate(row); for i in 1 to padding loop write(out_file, character'val(0)); end loop; end loop; deallocate(image); file_close(bmp_file); file_close(out_file); report "Simulation done. Check ""out.bmp"" image."; finish; end process;

Imagem Resultante

O arquivo out.bmp gerado mostra a versão em escala de cinza da imagem original do Boeing 747. Uma prévia JPEG é exibida no artigo; o arquivo BMP completo está disponível via formulário de download.

Considerações Adicionais

VHDL

  1. Holografia Desmistificada: Da Invenção Nobel de Gabor ao Armazenamento de Dados do Futuro
  2. Dominando Declarações Using em C#: Imports, Aliases e Diretivas Estáticas
  3. Manipulação de Arquivos em C: Dominando I/O com fopen, fprintf, fread e fseek
  4. Dominando Operações de Arquivo em Java com java.io – Criação, Leitura, Escrita e Exclusão
  5. Inicializando Block RAM de FPGA a partir de Arquivos de Texto Usando a Biblioteca TEXTIO do VHDL
  6. Lendo Arquivos em Java com BufferedReader – Guia Prático com Exemplos
  7. Python JSON: Codificação, Decodificação e Manipulação de Arquivos – Guia Prático
  8. Dominando I/O de Arquivos em Verilog: Abrir, Ler, Escrever e Fechar
  9. Entendendo Arquivos de Cabeçalho em C: Tipos, Uso e Boas Práticas
  10. Centro de Pesquisa Langley da NASA Revela Câmera Plenóptica Avançada para Imagem 3D Colorida