【FPGA图像处理实战】- FPGA图像处理仿真测试工程(读写BMP图片)

news/2024/7/21 4:51:29 标签: fpga开发, 图像处理, 人工智能, fpga, vivado, verilog, xilinx

FPGA开发过程中“行为功能仿真”是非常必要的一个过程,如果仿真都没通过,则上板测试必定失败。

FPGA图像处理需要读写大量的图像数据,单看这些图像数据实际是没有规则的,如果直接上板测试,调试起来非常困难,数量量大,ILA只能抓一段时间的数据,不易确定问题原因。

所以FPGA图像处理开发中,创建一个正确的仿真测试激励非常关键,基本上只要满足时序要求,上板就大概率就能过,如果上板遇到问题,还可以拿到这张图片数据,仿真测试一下看看能否复现,如果能复现问题,再通过仿真调试解决这个问题就容易很多了。

今天,我们就来搭建一个图像处理仿真测试工程,实现读写bmp文件的功能。

一、SystemVerilog/Verilog读写文件函数

仿真测试激励(Testbench)中经常需要读写文件,这里介绍一下SystemVerilog/Verilog常用的操作文件的函数,写测试激励推荐使用SystemVerilog。

1、打开文件函数

函数定义:integer fd = $fopen(file_name,type)

函数返回值: fd不等于0,表示文件打开成功;fd等于0,表示文件打开失败。

函数参数:

(1)file_name是一个字符串。

(2)type有如下类型:

“r” or “rb”:只读 或 按二进制文件读取

“w” or “wb”:只写 或 按二进制文件写入

“a” or “ab”:打开文件追加从文件末尾(EOF)写或创建文件写

“r+” or “rb+”:打开文件,可读可写

“w+” or "wb+": 打开或创建文件写

"a+" "a+b" or "ab+" :追加,在文件末尾打开

示例:

integer fd;
fd = $fopen("./1280_720.bmp","rb");

2、关闭文件函数

养成一个良好的习惯,打开文件处理完后,记得关闭文件。

函数定义:$fclose(fd)

函数说明:fd就是调用$fopen返回的值。

3、读写文件函数

(1)writemem[b|h]/readmem[b|h]

writemem 表示写,readmem表示读。b 表示读写二进制文件,h表示读写十六进制文件。

所以对应的全名有:writememb/writememh/readmemb/readmemh。

读写文件函数调用形式如下:

(1)$readmemb("<数据文件名>",<存储器名>);

(2)$readmemb("<数据文件名>",<存储器名>,<起始地址>);

(3)$readmemb("<数据文件名>",<存储器名>,<起始地址>,<终止地址>);

其中存储器名就是数组型变量,起始地址和终止地址就是数组型变量的起始范围。

示例:

   reg [31:0]   mem[63:0] ;
   initial begin
      //读文件数据
      $readmemb("./data.hex", mem);
      $display("Read memory1: %h", mem[0]) ;
      //写文件数据
      $writememb("./data_bak.hex", mem);
   end

注意:

readmem[b|h]是将数据放在存储器数组中,所以存储器数组应该定义为reg型,而不是wire。

readmem[b|h]是不能操作二维数组,只能操作一维数组。

(2)$fscanf 和 $fwrite

$fscanf 按照指定格式从文件中读取数据。

函数定义:integer flag=$fscanf(fd,format,args);

函数参数:fd表示文件句柄;format表示数据格式,%d表示十进制整数,%c表示一字节8bit字符,%x表示十六进制整数;args表示存储器数组。

$fwrite 按照指定格式从文件中读取数据。

函数定义:integer flag=$fwrite(fd,format,args);

函数参数定义:与$fscanf一样。

示例:

parameter LEN = 1920;
integer i;
reg [7:0] data[LEN-1:0];
integer fd;

initial begin
    //读文件
    fd = $fopen("./in.txt","rb");
    for( i=0; i<LEN; i=i+1 ) begin
        $fscanf(fd, "%c", data[i]);
        $display("Read data is: %c", data[i]);
    end 
    $fcolse(fd);
    
    //写文件
    fd = $fopen("./out.txt","rb");
    for( i=0; i<LEN; i=i+1 ) begin
        $fwrite(fd, "%c", data[i]);
    end 
    $fcolse(fd);    
end

4、文件定位函数

(1)获取文件位置函数 $ftell

integer pos = $ftell( fd ) ; 返回文件当前位置距离文件首部的偏移量,初始地址为 0,偏移量按照字节为一单位(8bits),配合 $fseek 使用。

(2)重定位函数$fseek

integer code = $fseek(fd, offset, type) ; 设置文件下一个输入或输出的位置

函数参数 :offset 为设置的偏移量,type 为偏移量的参考位置,具体如下:

--- 0: 以文件起始位置为基准

--- 1: 以文件当前位置为基准

--- 2: 以文件末尾为基准

二、BMP文件介绍

BMP(Bitmap)文件格式是一种图像文件格式,与常见的图像格式如 JPEG、PNG 等不同,它属于典型的位图格式。BMP 采用位映射存储格式,除了图像深度可选以外,不使用其他任何压缩。

1、BMP文件头

BMP文件头长度可变,但一般都是 54 字节,其中包括 14 字节的 Bitmap 文件头以及 40 字节的 DIB (Device Independent Bitmap) 数据头,或称位图信息数据头(BItmap Information Header)。



2、视频数据 Raw Bitmap Data

常见的数据格式是24bitRGB,具体到每一个像素是24bit数据,分别是B、G、R的形式排列。

三、图像处理仿真测试工程

1、图像处理仿真测试工程结构

2、参数定义

设定图像文件位置、图像大小、横向消影区、纵向消影区大小。

//`define pix_1920_1080
`define pix_1280_720

`ifdef pix_1920_1080  
    `define INPUT_FILE "../../../../test_img/in/1920_1080.bmp"  //input image
	`define IMG_WIDTH 1920   //Image width
	`define IMG_HEIGHT  1080  //Image height
	`define H_BLANK 720   //横向消影区,仿真可自由设定
    `define V_BLANK 45 	//纵向消影区,仿真可自由设定
`endif

`ifdef pix_1280_720  
    `define INPUT_FILE "../../../../test_img/in/1280_720.bmp"  //input image
	`define IMG_WIDTH 1280   //Image width
	`define IMG_HEIGHT  720  //Image height
	`define H_BLANK 480   //横向消影区,仿真可自由设定
    `define V_BLANK 30 	//纵向消影区,仿真可自由设定
`endif

`define OUTPUT_FILE "../../../../test_img/out/result.bmp" //result image

`define SEEK_SET 0
`define SEEK_CUR 1
`define SEEK_END 2

3、读图像文件

读取BMP文件数据,先读取BMP文件头,BMP的数据时按倒序存储,即从下到上,从左到右,读取出来存储时,需要存储到对应的位置。

    fdI = $fopen(`INPUT_FILE,"rb");
	if (fdI == `NULL) begin 
		$display("> OPEN FAIL: The file not exist !!!");
	end else begin  
		$display("> OPEN file SUCCESS !");
		//读取bmp文件头		
		ret = $fread(bmp_head_r, fdI, 0, `LEN_HEADER);
	    //读取图像RGB分量值
        //BMP倒序存储数据时,从下到上,从左到右
	    for(i=`IMG_HEIGHT - 1;i >= 0;i=i-1) 
            for(j=0;j <`IMG_WIDTH;j=j+1) begin
                idx = i*`IMG_WIDTH + j;
				imgB_r[idx] = $fgetc(fdI);//b
				imgG_r[idx] = $fgetc(fdI);//g
				imgR_r[idx] = $fgetc(fdI);//r                
		end
        $display("> Read b,g,r Successful !");
    end

4、写图像文件

写图像文件,先写入文件头信息,再按照倒序存储BGR数据,需要移动文件内的偏移量。


    //写入文件头  
    for(i=0;i < `LEN_HEADER;i=i+1)   begin
        $fwrite(fdO, "%c", bmp_head_r[i]);
    end

    //移动到图片数据最后一行起始位置
    file_end_offset = `IMG_ALL + `LEN_HEADER - `IMG_WIDTH*3;
    $fseek(fdO, file_end_offset, `SEEK_SET);


    assign {R_o_w, G_o_w, B_o_w} = img_data_o;

    always @(posedge clk or posedge reset) begin
        if (reset) begin
            out_data_cnt_r <= 'b0;
            valid_o_r <= 'b0;
        end else begin
            valid_o_r <= valid_o;
            if(valid_o) begin
                $fwrite(fdO, "%c", B_o_w);
                $fwrite(fdO, "%c", G_o_w);
                $fwrite(fdO, "%c", R_o_w);
                out_data_cnt_r <= out_data_cnt_r + 1'b1;
            end else if(valid_o_r) begin//行结束
                file_end_offset = file_end_offset - `IMG_WIDTH*3;
                $fseek(fdO, file_end_offset, `SEEK_SET);
            end
        end
    end

注意:

BMP位图的每一行像素所占字节数必须被4整除。若不能倍4整除,则每一行的末尾需要“补”1至3个字节的“00”。

整个文件大小也需要是4字节的整数倍,不足需要补零,当然不补零也不影响正常显示。

四、仿真测试结果

仿真图:

效果图:

五、源码下载

https://pan.quark.cn/s/f0e7a72caa26


http://www.niftyadmin.cn/n/5243629.html

相关文章

kyuubi整合flink yarn session mode

目录 概述配置flink 配置kyuubi 配置kyuubi-defaults.confkyuubi-env.shhive 验证启动kyuubibeeline 连接使用hive catlogsql测试 结束 概述 flink 版本 1.17.1、kyuubi 1.8.0、hive 3.1.3、paimon 0.5 整合过程中&#xff0c;需要注意对应的版本。 注意以上版本 配置 ky…

SpringBoot 与Maven ProFile的使用

SpringBoot 与Maven ProFile的使用 目录结构 dev 开发环境 sit 测试环境 prd 正式环境 maven 配置 <build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId>&l…

【PyTorch】权重衰减

文章目录 1. 理论介绍2. 实例解析2.1. 实例描述2.2. 代码实现 1. 理论介绍 通过对模型过拟合的思考&#xff0c;人们希望能通过某种工具调整模型复杂度&#xff0c;使其达到一个合适的平衡位置。权重衰减&#xff08;又称 L 2 L_2 L2​正则化&#xff09;通过为损失函数添加惩…

机器学习之蛙跳算法(Jumping Frog Optimization,JFO)

概念 蛙跳算法(Jumping Frog Optimization,JFO)是一种基于仿生学和自然界觅食行为的启发式优化算法。该算法模拟了青蛙在寻找食物时的跳跃行为。青蛙通过一系列跳跃来寻找最优位置,而这些跳跃的长度和方向是通过计算当前位置的适应度值来确定的。 蛙跳算法的基本步骤: …

AUTOSAR汽车电子嵌入式编程精讲300篇-基于加密算法的车载CAN总线安全通信

目录 前言 研究现状 系统架构研究 异常检测研究 认证与加密研究 相关技术 2.1车联网 2.2车载网络及总线 2.2.1 CAN总线基础 2.2.2 CAN总线网络安全漏洞 2.2.3 CAN总线信息安全需求 2.3密码算法 2.3.1 AES算法 2.3.2 XTEA算法 CAN网络建模与仿真 3.1 CAN网络建模…

51单片机程序

利用动态扫描和定时器1在数码管上显示出从765432开始以1/10秒的速度往下递减直至765398并保持显示此数&#xff0c;与此同时利用定时器O以500MS速度进行流水灯从土至下移动,当数码管上数减到停止时&#xff0c;实验板上流水灯也停止然后全部开始闪烁&#xff0c;3秒后&#xff…

linux 安装并配置rabbitmq

注&#xff1a;将需要安装的 erlang 和 rabbimq 包放在/usr/src 目录下。erlang 的下载需要注意.centos7 下载的是 el7 版本。生产者和消费者同时打开生产和消费都很快&#xff0c;如果只开生产者&#xff0c;每 5s 才生产一条消息&#xff0c;还没找到办法解决 安装 安装 er…

unity 2d 入门 飞翔小鸟 下坠功能且碰到地面要停止 刚体 胶囊碰撞器 (四)

1、实现对象要受重力 在对应的图层添加刚体 改成持续 2、设置胶囊碰撞器并设置水平方向 3、地面添加盒状碰撞器 运行则能看到小鸟下坠并落到地面上