FPGA图像处理(一) ----- 仿真测试工程(读写BMP图片)

搭建图像处理仿真测试工程,实现读写bmp文件的功能

一、SystemVerilog/Verilog 读写文件函数

1. 打开文件函数 

示例:
integer fd;
fd = $fopen("xxx.bmp","rb");

2. 关闭文件函数 

 

3. 读写文件函数 

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

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

(2) $fscanf  和 $fwrite

示例:读写1920个数据位宽为8bit的数据文件
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
    $fclose(fd);

    // 写文件
    fd = $fopen("./out.txt","wb");
    for( i=0; i<LEN; i=i+1)begin
        $fwrite(fd ,"%c",data[i]);
    end
    $fclose(fd);
end

4. 文件定位函数

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

(2) 重定位函数 $fseek

二、BMP文件说明

以1 x 1 的像素为例:

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

1. 图像处理仿真测试工程框架

2. 工程设计 

(1)定义图片文件位置、不同分辨率的图片大小、以及图像的横/纵向的消隐区大小

//`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 frame1

(2)读取BMP文件的数据

先初始化图片RGB数据,再读取BMP图片文件,对BMP的信息头以及BGR数据进行更新

`define LEN_HEADER	 54// 0x33                    bmp文件头 + 信息头
`define IMG_ALL	     (`IMG_HEIGHT*`IMG_WIDTH*3) //图片像素总数据 RGB
`define IMG_SIZE     (`IMG_HEIGHT*`IMG_WIDTH)   //图片大小
`define IMG_BMP_SIZE (`IMG_ALL + `LEN_HEADER)   //BMP图片总大小

`define NULL         0
`define DATA_WIDTH   8
    integer ret, i, j, idx;
    integer fdI;

    reg	[`DATA_WIDTH-1:0] bmp_head_r[0:`LEN_HEADER-1];//Image 1 Header
    reg	[`DATA_WIDTH-1:0] imgR_r[0:`IMG_SIZE-1]; //Image-- R Channel
    reg	[`DATA_WIDTH-1:0] imgG_r[0:`IMG_SIZE-1]; //Image-- G Channel
    reg	[`DATA_WIDTH-1:0] imgB_r[0:`IMG_SIZE-1]; //Image-- B Channel    

    wire [31:0] bmp_size, bmp_width, bmp_height;   
    reg init_r;

    ///////////////////////////////////读取BMP文件
    assign bmp_size   =  {bmp_head_r[5] , bmp_head_r[4] , bmp_head_r[3] , bmp_head_r[2] };
    assign bmp_width  =  {bmp_head_r[21], bmp_head_r[20], bmp_head_r[19], bmp_head_r[18]};
    assign bmp_height =  {bmp_head_r[25], bmp_head_r[24], bmp_head_r[23], bmp_head_r[22]};

    initial begin
	init_r = 1'b0;
	for (i = 0; i < `IMG_SIZE; i=i+1)begin
		imgB_r[i] = 0;			
		imgG_r[i] = 0;
		imgR_r[i] = 0;
	end
			
    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
		

 (3)写BMP文件数据

首先将读出来的数据进过图像处理算法的模块,产生输出数据;这边图像处理的算法模块就是简单的原图数据,本文只是为了验证框架的有效性。

然后先写入文件的头信息,再将模块的数据数据按照倒序存储BGR数据,需要移动文件内的偏移量

    integer fdO;
    integer file_end_offset, zero_len;    

    reg [31:0] h_cnt_r, v_cnt_r;
	reg [31:0] data_cnt_r;
    reg [31:0] addr_r;  

    wire valid_i;
    wire [`DATA_WIDTH*3-1:0] img_data_i;
    wire valid_o;
    wire [`DATA_WIDTH*3-1:0] img_data_o;

	reg [31:0] out_data_cnt_r;
    reg valid_o_r;

    wire [`DATA_WIDTH-1:0] R_o_w, G_o_w, B_o_w;
///////////////////////////////////图像算法模块
image_process u_image_process(
    .clk        ( clk        ),
    .reset      ( reset      ),
    .img_width  ( `IMG_WIDTH  ),
    .img_height ( `IMG_HEIGHT ),
    .valid_i    ( valid_i    ),
    .img_data_i ( img_data_i ),
    .valid_o    ( valid_o    ),
    .img_data_o ( img_data_o  )
);

    always @(posedge clk or posedge reset) begin
        if (reset) begin
            {h_cnt_r, v_cnt_r} <= 'b0;
            addr_r <= 'b0;
			data_cnt_r <= 'b0;
        end else begin
            h_cnt_r <= (h_cnt_r == `IMG_WIDTH + `H_BLANK - 1) ? 'b0 : h_cnt_r + 1'b1;
            v_cnt_r <= (h_cnt_r == `IMG_WIDTH + `H_BLANK - 1) ? ((v_cnt_r == `IMG_HEIGHT + `V_BLANK - 1) ? 'b0 : v_cnt_r + 1'b1) : v_cnt_r;
            addr_r <= (addr_r == `IMG_SIZE - 1) ?  'b0 : valid_i ? (addr_r + 'd1) : addr_r;
			data_cnt_r <= valid_i ? ((data_cnt_r == `IMG_WIDTH - 1) ? 'b0 : data_cnt_r + 1) : data_cnt_r;
        end
    end

    assign valid_i = (h_cnt_r < `IMG_WIDTH)&&(v_cnt_r < `IMG_HEIGHT) ? 1'b1 : 1'b0;
    assign img_data_i = {imgR_r[addr_r], imgG_r[addr_r], imgB_r[addr_r]};
    fdO = $fopen(`OUTPUT_FILE,"wb");
    //写入文件头  
    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);
    init_r = 1'b1;
    end

///////////////////////////////////写入BMP文件

    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

(4)仿真流程

​
	///////////////////////////////////时钟和初始化
    //时钟
    always
    begin
        #(TIME/2) clk = ~clk;
    end	
	
    //仿真控制
    initial begin   
    reset = 1'b1;
    zero_len = 'b0;
    #(TIME*10);
    reset = 1'b0;	
	wait(init_r);
	$display("> Initial Done");
	wait(out_data_cnt_r == (`IMG_SIZE-1));//检测一幅图像完成
    #(TIME*2);
    //文件末尾补0
    $fseek(fdO, 0, `SEEK_END);
    zero_len = $ftell(fdO); 
    zero_len = 4- zero_len[1:0];
    for(i=0;i < zero_len;i=i+1)   
        $fwrite(fdO, "%c", 0);   
    $fclose(fdO);
	$display("> Simulate Done");
    $stop;
    end

​

3.仿真结果

成功建立仿真流程,以后的图像处理算法模块PL端编写完之后,先经过该仿真工程对算法进行验证

本文算法是原样输出,结果正确。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值