闲庭信步使用SV搭建图像测试平台:第一课——图片的读写
(如需要该系列的工程文件请关注知识星球:成工fpga,https://t.zsxq.com/DMeqH,关注即送200GB学习资料,链接已置顶!)
一个FPGA开发人员,不管是工作需要还是个人爱好,现在要对数字图像进行处理,尴尬的是手头没有FPGA硬件平台,也不会用或者不想用matlab,opencv,python等软件对图像进行处理。总而言之,目前就一个modelsim仿真软件,能不能对图像进行处理呢?
成工可以明确的说,仅仅使用modelsim软件是可以对图像进行处理的,但是不能只使用verilog,而是要使用system verilog语言。说到verilog和system verilog,成工不仅想到了大学学习c和c++语言的时候,大家说的最多的就是c++是面向对象编程的,而system verilog与verilog最大的不同也是一样,system verilog支持面向对象的编程,也就是可以使用class。
本系列是基于system verilog,使用modelsim来搭建图像的测试平台,所以重点不是学习system verilog语言,而是使用system verilog来搭建仿真测试平台,非必要成工不会对system verilog的语法进行专门的讲解,语法相关的东西,用多了自然就会了。
语言和软件确定了,要选用什么格式的图片呢?图像的格式有很多种,比如jpg,png,bmp,tif,gif等等,看似很多,但是等让我们简单上手的只有bmp图片,因为bmp图片包含的图像信息很丰富,几乎不进行压缩,当然占用磁盘空间也比较大。而jpg,png等格式的图片都进行了压缩,处理前还要进行图像恢复的操作,不容易上手。大家可能会问,我要处理的图片不是bmp格式的怎么办呢?成工只能默默的告诉你,先转成bmp的图片再进行处理,而且转的过程中,一定选择24位的位图,否则后续处理起来非常的麻烦。
下面我们来看看bmp图片的格式,分成文件头,信息头,色彩表和数据阵列字节四部分。
其中图像文件头和图像信息头共54字节,需要注意的是,上面成工说的bmp一定要保存24位的位图,就是对应001Ch的Bits Per Pixel,24bit真彩色位图,也就是说图像的每个像素点都是24bit,分别是r,g,b三个分量,此时图片是没有进行任何压缩的,而且色彩表的成员尺寸大小是0,也就是说24bit真彩色位图就是由54字节的头和数据阵列组成。
语言,软件,图片都准备好了,那就开干。由于使用system verilog开发,那应该新建*.sv文件而不是.*v文件,这儿成工新建的是tb_image_sim.sv文件。
首先成工介绍一下每个仿真测试工程的内容,刚开始是包括五个文件见,doc用来存放说明文档,img用来保存要处理和处理后的图片,sim里面是仿真文件列表filelist,自动化脚本run.do和window下可执行文件top_tb.bat,只需要双击top_tb.bat就可以完成整个测试仿真;src用来存放可综合的rtl代码,第一期全是测试仿真,所以src文件夹下全部都是空的,第二期是rtl代码的仿真和测试平台的仿真对比,这时候就会有文件放进去;tb用来存放仿真测试的sv文件,tb_image_sim.sv就在该文件夹下。
下面我们开始讲解tb_image_sim模块。第25到27行定义了图像头、图像宽度和图像的高度的大小,之所以现在800x480图像,是因为成工手头开发板的LCD屏是800x480分辨率的。28行计算了图像的大小,乘3是因为一个像素点有rgb三个分量,54+800*480*3=1152054,我们查看一下图片的大小,确实是1152054。
30行到32行定义了integer变量,用来指示输入图片,输入图片和输出txt文本。第34行到38行定义了几个图像头的变量,用来测试一下从头部读出来的值是否和期望值一致。40行定义了一个reg类型的二维数组,用来存储图像的数据,数组长度是整个图片的大小。41行定义了一个32bit(一个word)的变量,图片的存储必须按照word为单位进行存储。
经典问题,把大象装入冰箱需要几个步骤,答案很简单,三个步骤:打开冰箱门,把大象装入冰箱,关闭冰箱。同理,不管是图片的读写,还是文本的读写,不管使用c,c++还是python,应该都是三个步骤,那就是打开文件,对文件进行读写,关闭文件,system verilog也不能免俗,对图片和文本的读写也是这三个步骤。
43行到75行定义了initial块,完成图像数据的读写。其中图像的读操作是先打开图片(45行$fopen),将图片数据保存到数组(49行$fread),最后关闭图像(50行$fclose)。
将图像数据保存到txt文档中也是差不多,先打开txt文档(47行$fopen),将图片数组中的数据保存到txt文件中(64行$fwrite),最后关闭txt文档(65行$fclose)。
将图像数据再保存到图像,就是图像的写操作,步骤是先打开图片(46行$fopen),将图片数组中的数据保存到图片中(71行$fwrite),最后关闭图像(73行$fclose)。需要注意的是保存到图片的数据必须是word,69到72行实现了该功能。
53行到57行解析了图想head的一下信息,通过$display打印出来。
图像的读写就是这么简单,双击sim文件夹下的top_tb.bat文件,自动打开modelsim完成仿真,打印信息如下,可见期望的数据和获取的数据是一致的。
打开img文件夹,可以看到新生成了图像文件out.bmp和文本文件out.txt。
我们查看一下out.bmp文件的大小,发现是1152056,比原始图像大了2个字节。
网上有人说过这个问题,成工也试过用ps将jpg图片转称bmp文件,也会增加2个字节。我们用UE将两幅图片打开,发现新保存的图片最后多了两个字节的0。其实原因也很简单,原图像大小1152054/4=288013.5,不能被4整除,而我们又是按照word(4字节)进行存储,最后两个字节自动补零,所以图片大小就变成了1152056。