亿迅智能制造网
工业4.0先进制造技术信息网站!
首页 | 制造技术 | 制造设备 | 工业物联网 | 工业材料 | 设备保养维修 | 工业编程 |
home  MfgRobots >> 亿迅智能制造网 >  >> Industrial programming >> VHDL

用 TEXTIO 在 VHDL 测试平台读取 BMP 位图图像

VHDL 测试平台导入图像最简单方式是用 BMP 光栅图形格式。BMP 文件被 Windows 原生支持,且以无压缩方式暴露原始像素数据,极适合仿真。

本文讲解如何读取二进制 BMP 文件、将像素数据存入动态内存、送入 VHDL DUT、并将处理后图像写回新 BMP 文件。示例 DUT 执行灰度转换,但技术适用于任何逐像素处理模块。

属于 TEXTIO 系列:

为何 BMP 是 VHDL 最优格式

JPEG 和 PNG 网络普及,但都用压缩。JPEG 有损,PNG 无损;两者都给测试平台直接访问像素数据增加复杂层。BMP 以无压缩光栅图形存储图像数据,每像素用原始 RGB 字节表示。这省去了 VHDL 中解压代码,保证确定性仿真时间。

Photoshop 或 GIMP 等常见图像编辑器内部以光栅数据加载图像。对 VHDL,手动(或脚本)将源图像转 BMP 是最直接途径。

准备 BMP 文件

用 Windows 画图确保一致文件布局:

  1. 打开图像。
  2. 选 文件 > 另存为。
  3. 选 24‑位位图 (*.bmp; *.dib) 并保存。

此法文件头始终为 54 字节 BITMAPINFOHEADER 变体,RGB24 像素格式。下表列出读取的头部字段。

偏移量(十进制)大小(字节)期望值(十六进制)说明
0242 4DID 字段
10454 (36 00 00 00)像素数组偏移
14440 (28 00 00 00)头部大小
184读取值图像宽度(像素)
224读取值图像高度(像素)
26101颜色平面数
28118每像素位数

仅绿底字段必需;其余作完整性检查。

测试用例

下面是最小灰度 DUT,接受 24 位 RGB 输入并输出对应亮度值编码回 RGB。模块纯组合,无需时钟。

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; 

为完整起见,完整工程源码(含 1000×1000 像素波音 747 BMP)可在链接表单提供邮箱下载。

导入 TEXTIO

VHDL 文件顶部添加:

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

这些声明要求 VHDL‑2008 或更新版本。

图像存储自定义类型

在测试平台声明区定义以下类型:

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;

这些动态数据结构让测试平台适应任意尺寸图像,无静态数组限制。

实例化 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 ); 

读取 BMP 头部

进程先将 54 字节头部加载到 header 变量,用 assert 校验关键字段。防止误用不支持文件格式。

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;

校验后提取图像宽高:

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);

读取像素数据

每 BMP 行填充至 4 字节倍数。计算每行填充并为图像分配动态存储。

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;

测试 DUT

将每像素送入 DUT,等待小增量周期,捕获灰度输出。

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;

写入输出 BMP

先写保留的头部。再逐行序列化像素数据,必要处加填充。最后清理动态内存并关闭文件。

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;

结果图像

生成的 out.bmp 文件显示原始波音 747 图像的灰度版。文章显示 JPEG 预览;完整 BMP 文件可通过下载表单获取。

进一步考量

VHDL

  1. 全息摄影揭秘:从加博尔的诺贝尔奖发明到未来数据存储
  2. NASA 兰利研究中心推出先进全光场相机实现 3D 彩色成像
  3. Linux下用数字签名验证二进制文件完整性:ELF签名实战脚本详解
  4. 掌握 C# using 指令:命名空间导入、别名与静态导入全解析
  5. C语言文件处理完全指南:fopen、fprintf、fread 与 fseek
  6. C 语言头文件详解:类型、用法与最佳实践
  7. 精通PSL形式化验证VHDL模块:从理论到实战
  8. 用 VHDL TEXTIO 库从文本文件初始化 FPGA 块 RAM
  9. 掌握 Verilog 文件 I/O:打开、读取、写入和关闭
  10. Python JSON:编码、解码与文件处理实战指南
  11. 掌握 Java 文件操作:java.io 包下的创建、读取、写入与删除
  12. Java BufferedReader 读取文件:实战指南与示例