8.6 KiB
Hard-PNG
基于FPGA的流式的png图象解码器
特点
- 支持宽度不大于4000像素的png图片,对图片高度没有限制。
- 支持所有颜色类型: 灰度、灰度透明、RGB、索引RGB、RGBA。
- 仅支持8bit深度,大多数png图片都是8bit深度。
- 完全使用SystemVerilog实现,方便移植和仿真。
图1 : Hard-PNG 原理框图 |
背景知识
png是仅次于jpg的第二常见的图象压缩格式,相比于jpg,png支持透明通道,支持无损压缩。在色彩丰富的数码照片中,无损压缩的png只能获得1~4倍的压缩比,低失真有损压缩的png能获得4~20倍的压缩比。在色彩较少的人工合成图(例如框图、平面设计)中,无损压缩的png就能获得10倍以上的压缩比。因此,png更适合压缩人工合成图,jpg更适合压缩数码照片。
png 图片的文件扩展名为 .png 。以我们提供的文件 test1.png 为例,它包含98字节,称为原始码流。我们可以使用WinHex软件查看它:
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, ...... , 0xAE, 0x42, 0x60, 0x82
该图象文件解压后只有4列2行,共8个像素,16进制表示如下表。其中R, G, B, A分别代表像素的红、绿、蓝、透明通道。
列 1 | 列 2 | 列 3 | 列 4 | |
---|---|---|---|---|
行 1 | R:FF G:F2 B:00 A:FF | R:ED G:1C B:24 A:FF | R:00 G:00 B:00 A:FF | R:3F G:48 B:CC A:FF |
行 2 | R:7F G:7F B:7F A:FF | R:ED G:1C B:24 A:FF | R:FF G:FF B:FF A:FF | R:FF G:AE B:CC A:FF |
Hard-PNG 的使用
Hard-PNG是一个能够输入原始码流,输出解压后的像素的硬件模块,它的代码在 hard_png.sv 中。其中 hard_png 是顶层模块,它的接口如图2所示
图2 : hard_png 接口图 |
它的使用方法很简单,首先需要给 clk 信号提供时钟(频率不限),并将 rst 信号置低,解除模块复位。 然后将原始码流从原始码流输入接口 输入,就可以从图象基本信息输出接口和像素输出接口中得到解压结果。
以test1.png为例,我们应该以图3的时序把原始码流(98个字节)输入hard_png中。 该输入接口类似 AXI-stream ,其中 ivalid=1 时说明外部想发送一个字节给 hard_png。iready=1 时说明 hard_png 已经准备好接收一个字节。只有 ivalid 和 iready 同时 =1 时,ibyte 才被成功的输入 hard_png 中。
图3 : hard_png 输入时序图,以 test1.png 为例 |
在输入的同时,解压结果从模块中输出,如图4。在新的一帧图象输出前,newframe 信号会出现一个时钟周期的高电平脉冲,同时 colortype, width, height 保持有效直到该图象的所有像素输出完为止。其中 width, height 分别为图象的宽度和高度, colortype 的含义如下表。另外, ovalid=1 代表该时钟周期有一个像素输出,该像素的R,G,B,A通道分别出现在 opixelr,opixelg,opixelb,opixela 信号上。
colortype | 2'd0 | 2'd1 | 2'd2 | 2'd3 |
---|---|---|---|---|
颜色类型 | 灰度图 | 灰度+透明 | RGB / 索引RGB | RGBA |
含义 | RGB通道相等, A通道=0xFF | RGB通道相等 | RGB通道不等, A通道=0xFF | RGBA通道均不等 |
图4 : hard_png 输出时序图,以 test1.png 为例 |
当一个图象完全输入结束后,我们可以紧接着输入下一个图象进行解压。如果一个图象输入了一半,我们想打断当前解压进程并输入下一个图象,则需要将 rst 信号拉高至少一个时钟周期进行复位。
仿真
tb_hard_png.sv 是仿真的顶层,它从指定的 .png 文件中读取原始码流输入hard_png中,再接收解压后的像素并写入一个 .txt 文件。
仿真前,请将 tb_hard_png.sv 中的PNG_FILE宏名改为 .png 文件的路径,将OUT_FILE宏名改为 .txt 文件的路径。然后运行仿真。 .png 文件越大,仿真的时间越长。当ivalid信号出现下降沿时,仿真完成。然后你可以从 .txt 文件中查看解压结果。
我们在 images文件夹 下提供了多个 .png 文件,它们尺寸各异,且有不同的颜色类型,你可以用它们进行仿真。以 test3.png 为例,仿真得到的 .txt 文件如下:
frame type:2 width:83 height:74
f4d8c3ff f4d8c3ff f4d8c3ff f4d8c3ff f4d8c3ff f4d9c3ff ......
这代表图片的尺寸是83x74, colortype 是2(RGB),第1行第1列的像素是RGBA=(0xf4, 0xd8, 0xc3, 0xff),第1行第2列的像素是RGBA=(0xf4, 0xd8, 0xc3, 0xff),......
正确性验证
为了验证解压结果是否正确,我们提供了Python程序 validation.py ,它对 .png 文件进行软件解压,并与仿真得到的 .txt 文件进行比较,若比较结果相同则验证通过。为了准备必要的运行环境,请安装Python3以及其配套的 numpy 和 PIL 库。运行环境准备好后,打开 validation.py ,将变量 PNG_FILE 改为要验证的 .png 文件的路径,将 TXT_FILE 改为仿真输出的 .txt 文件的路径,然后用命令运行它:
python validation.py
若验证通过,则打印 "validation successful!!" 。目前我们测试了几十张不同的 .png 图片,均验证通过。
性能测试
- 测试平台: 在 Altera Cyclone IV EP4CE40F23C6 上运行 Hard-PNG 进行png解压,时钟频率= 50MHz (正好时序收敛)。
- 对比平台: 使用MSVC++编译器以O3优化级别编译upng库,在笔记本电脑(Intel Core I7 8750H)上运行png解压。
测试结果如下表,Hard-PNG的性能接近对比平台。由此可以推断,Hard-PNG的性能好于大部分ARM嵌入式处理器。
png文件名 | 颜色类型 | 图象尺寸 | 对比平台耗时 | Hard-PNG 耗时 |
---|---|---|---|---|
test9.png | RGB | 631x742 | 83 ms | 204 ms |
test10.png | 索引RGB | 631x742 | 不支持 | 48 ms |
test11.png | RGBA | 1920x1080 | 402 ms | 993 ms |
test12.png | 索引RGB | 1920x1080 | 不支持 | 204 ms |
test13.png | RGB | 1819x1011 | 321 ms | 655 ms |
test14.png | 黑白 | 1819x1011 | 135 ms | 227 ms |
wave2.png | 索引RGB | 1427x691 | 不支持 | 27 ms |
FPGA 资源消耗
下表是hard_png模块综合后占用的FPGA资源量。
FPGA 型号 | LUT | LUT(%) | FF | FF(%) | Logic | Logic(%) | BRAM | BRAM(%) |
---|---|---|---|---|---|---|---|---|
Xilinx Artix-7 XC7A35T | 2581 | 13% | 2253 | 5% | - | - | 792kbit | 44% |
Altera Cyclone IV EP4CE40F23C6 | - | - | - | - | 4551 | 11% | 427kbit | 37% |
参考链接
感谢以下链接为我们提供参考。
- upng: 一个轻量化的 C 语言 png 解码库
- TinyPNG: 一个利用索引 RGB 对 png 图片进行有损压缩的工具
- PNG Specification: png 标准手册