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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/224588.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Vue】Vue Router 在 Vue2 项目中的简单使用案例

前言 Vue Router 是 Vue.js 官方的路由管理器。它可以帮助我们在 Vue2 项目中实现页面之间的切换和导航。以下是在 Vue2 项目中使用 Vue Router 的简单案例。 步骤 安装 Vue Router 首先&#xff0c;我们需要安装 vue-router 包。你可以使用 npm 或 yarn 安装&#xff0c;打开…

C语言实现植物大战僵尸(完整版)

实现这个游戏需要Easy_X 这个在我前面一篇C之番外篇爱心代码有程序教你怎么下载&#xff0c;大家可自行查看 然后就是需要植物大战僵尸的素材和音乐&#xff0c;需要的可以在评论区 首先是main.cpp //开发日志 //1导入素材 //2实现最开始的游戏场景 //3实现游戏顶部的工具栏…

Elasticsearch 8.9 flush刷新缓存中的数据到磁盘源码

一、相关API的handler1、接收HTTP请求的hander2、每一个数据节点(node)执行分片刷新的action是TransportShardFlushAction 二、对indexShard执行刷新请求1、首先获取读锁&#xff0c;再获取刷新锁&#xff0c;如果获取不到根据参数决定是否直接返回还是等待2、在刷新之后transl…

【Azure 架构师学习笔记】- Azure Databricks (2) -集群

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Databricks】系列。 接上文 【Azure 架构师学习笔记】- Azure Databricks (1) - 环境搭建 前言 在上文中提到了ADB 的其中一个核心就是集群&#xff0c;所以这里专门研究一下ADB 的集群。 ADB 集群 首先了解一下ADB…

智能优化算法应用:基于饥饿游戏算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于饥饿游戏算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于饥饿游戏算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.饥饿游戏算法4.实验参数设定5.算法结果6.参考…

抽象类和接口(超重点!!)

[本节目标] 1.抽象类 2.接口 3.Object类 1.抽象类 1.1 抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果一个类中没有包含足够的信息来描绘一个具体的对象&a…

编程实战:类C语法的编译型脚本解释器(九)编译语句

系列入口&#xff1a;编程实战&#xff1a;类C语法的编译型脚本解释器&#xff08;系列&#xff09;-CSDN博客 前文已经介绍了编译入口&#xff0c;核心就是语句&#xff0c;本文介绍语句的编译。 一、代码概览 代码太长&#xff0c;直接贴&#xff1a; bool GetSentence(CToke…

urllib爬虫 应用实例(三)

目录 一、 ajax的get请求豆瓣电影第一页 二、ajax的get请求豆瓣电影前十页 三、ajax的post请求肯德基官网 一、 ajax的get请求豆瓣电影第一页 目标&#xff1a;获取豆瓣电影第一页的数据&#xff0c;并保存为json文件 设置url&#xff0c;检查 --> 网络 --> 全部 -…

JPA与MySQL锁实战

前言&#xff1a;最近使用jpa和mysql时&#xff0c;遇到了死锁问题。在解决后将一些排查过程中新学到和复习到的知识点再总结整理一下。首先对InnoDB中锁相关的概念进行介绍&#xff0c;然后展示如何利用JPA提供的排他锁来实现想要的功能&#xff0c;最后对死锁问题进行讨论。 …

MOSFET

MOSFET 电子元器件百科 文章目录 MOSFET前言一、MOSFET是什么二、MOSFET类别三、MOSFET应用实例四、MOSFET作用原理总结前言 MOSFET是一种常见的半导体器件,通过栅极电场控制通道区的导通特性,以控制电流流动。它在现代电子电路中发挥着重要的作用,并广泛应用于各种应用领域…

第一百九十一回 自定义TimePicker:一

文章目录 1. 概念介绍2. 思路与方法2.1 整体思路2.2 实现方法3. 示例代码4. 内容总结我们在上一章回中介绍了"如何自定义一个可选择的星期组件"相关的内容,本章回中将介绍" 自定义TimpePicker".闲话休提,让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

弘扬中华文化 感受戏曲魅力——安徽演艺小分队赴和田交流演出

为进一步弘扬中华优秀传统文化&#xff0c;促进皖和两地交往交流交融&#xff0c;12月2日&#xff0c;安徽省演艺小分队走进和田新夜市登台演出&#xff0c;黄梅戏、独唱、民乐演奏、杂技等丰富多样的表演&#xff0c;为观众们送上了一场文化盛宴。 安徽演艺小分队赴和田交流演…

Stable Diffusion AI绘画系列【18】:东方巨龙,威武霸气

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

HarmonyOS(十一)——初识状态管理

前言 在前文的描述中&#xff0c;我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面&#xff0c;就需要引入“状态”的概念。 假设我们要实现如下一个动态的交互界面&#xff1a; 上面的示例中&#xff0c;用户与应用程序的交互触发了文本状态变更&#x…

Linux中的输入输出重定向

目录 1.输出重定向 > 2.追加重定向 >> 3.标准 正确/错误 输出重定向 4.输入重定向 < 5.标准输入 0 1.输出重定向 > 将命令执行之后的结果不打印出来&#xff0c;可以输入在另外一个文件当中。 如&#xff0c;我查看文件a.txt 的前3行&#xff0c;然后不显…

计算机图形图像技术(OpenCV核心功能、图像变换与图像平滑处理)

一、实验原理&#xff1a; 1、显示图像 void imshow(const string &name, InputArray image); ①功能&#xff1a;在指定窗口中显示图像。 ②参数&#xff1a;name为窗口的名字&#xff1b;image为待显示的图像。 ③说明&#xff1a;可显示彩色或灰度的字节图像和浮点数图…

Stm32_串口的帧(不定长)数据接收

目录标题 前言1、串口中断接收固定帧头帧尾数据1.1、任务需求1.2、实现思路1.3、程序源码&#xff1a; 2、串口中断接收用定时器来判断帧结束3、串口中断接收数据空闲中断3.1、串口的空闲中断3.2、实现思路3.3、程序源码 4、串口的空闲中断DMA转运4.1、DMA简介4.2、DMA模式4.3、…

【Gradle】mac环境安装Gradle及配置

官网安装说明&#xff1a;Gradle | Installation 由于Gradle运行依赖jvm&#xff0c;所以事先需要安装jdk&#xff0c;并确认你的jdk版本和gradle版本要求的对应关系&#xff0c;这个官网上有说明&#xff0c;但是我试了一下不太准确&#xff0c;供参考&#xff0c;链接如下&a…

CleanMyMac X4.15.0最新官方和谐版下载

Mac系统进行文件清理&#xff0c;一般是直接将文件拖动入“废纸篓”回收站中&#xff0c;然后通过清理回收站&#xff0c;就完成了一次文件清理的操作&#xff0c;但是这么做并无法保证文件被彻底删除了&#xff0c;有些文件通过一些安全恢复手段依旧是可以恢复的&#xff0c;那…

【算法】约瑟夫环

约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被杀掉&#xff0c;最后剩下一个&#xff0c;其余人都将被杀掉。例如N6&#xff0c;M5&#xff0c;被杀掉的顺序是&#xff1a;5&#xff0c;4&#xff0c;6&#xff0c;2&a…