vivado中实现图像RGB转灰度该如何操作啊?测试激励该如何写。

因为硕士毕业论文的实验需要使用ZYNQ实现图像的处理,所以一直在研究如何使用FPGA处理图像。本实验打算首先从灰度转化中值滤波等实验,但老是卡在图像仿真测试上,不知道该如何写vivado的测试激励。主要有以下几点:

1、不知道如何将图像的信息导入到测试文件中的那些例化接口,有使用.bat 文件的,有直接使用BMP图像格式的,但是不清楚这些导入的图像信息如何配置到例化的模块接口里的。并且其中的行场信号该如何配置?是这个图像信息中本身就有的,还是需要在测试激励文件中单独配置?

2、不清楚处理后的测试文件是如何写到新的图像文件信息中的。

经过一段时间的学习,我终于知道如何写测试激励了,在这里我是使用vivado工具自带的那个仿真,使用的输入源为bmp格式的图像,不需要将图像转为.bat格式了,这样能够省去繁琐的MATLAB转换步骤。测试代码只要是参照B站大磊FPGA的视频。

`timescale 1ns / 1ns
//使用BMP格式照片仿真VIP视频图像处理算法
module vivado_sim();
	integer  iBmpFileId   ;  //承接输入的BMP文件
	integer  oBmpFileId_1 ;  //输出BMP图像1,
	
	integer  iIndex      = 0  ; //输出bmp数据索引
	integer  pixel_index = 0  ; //输出像素索引
	
	integer  iCode;
	
	integer iBmpWidth ;     //输入图像宽度
	integer iBmpHight ;	//输入图像高度
	integer iBmpSize  ;	//输入图像尺寸
	integer iDataStartIndex;//输入图像偏移量
	
	reg [ 7:0] rBmpData      [0:2000000];    //用于寄存输入BMP图片中的字节数据(包括54字节的文件头)
	reg [ 7:0] Vip_BmpData_1 [0:2000000];    //用于寄存视频图像处理之后 的BMP图片 数据 
	
	reg [31:0] rBmpWord;                //输出BMP图片时用于寄存数据(以word为单位,即4byte)

	reg [ 7:0] pixel_data;              //输出视频流时的像素数据

	reg clk;
	reg rst_n;
	
	reg [ 7:0] vip_pixel_data_1 [0:921600];   	//640x480x3
	
	wire 		PIC1_vip_out_frame_vsync;   
    wire 		PIC1_vip_out_frame_href ;   
    wire 		PIC1_vip_out_frame_clken;    
    wire [7:0]	PIC1_vip_out_img_R     ;   
    wire [7:0]	PIC1_vip_out_img_G     ;   
    wire [7:0]	PIC1_vip_out_img_B     ;  
	
	initial begin 
		iBmpFileId = $fopen("1_Jing_J66819.bmp","rb") ;
		//将输入BMP图片加载到数组中 21_Su_A65NF7
		iCode = $fread(rBmpData,iBmpFileId);
	 
	    //根据BMP图片文件头的格式,分别计算出图片的 宽度 /高度 /像素数据偏移量 /图片字节数
		iBmpWidth       = {rBmpData[21],rBmpData[20],rBmpData[19],rBmpData[18]};
		iBmpHight       = {rBmpData[25],rBmpData[24],rBmpData[23],rBmpData[22]};
		iBmpSize        = {rBmpData[ 5],rBmpData[ 4],rBmpData[ 3],rBmpData[ 2]};
		iDataStartIndex = {rBmpData[13],rBmpData[12],rBmpData[11],rBmpData[10]};
	    
	    //关闭输入BMP图片
		$fclose(iBmpFileId);
		
		//延迟13ms,等待第一帧VIP处理结束
	    #13000000 
		//输出第一张		
		oBmpFileId_1 = $fopen("output_file_1.bmp","wb+");
	    //加载图像处理后,BMP图片的文件头和像素数据
		//---------------------------------------------		
		//输出第一张
		
		for (iIndex = 0; iIndex < iBmpSize; iIndex = iIndex + 1) begin
			if(iIndex < 54)
	            Vip_BmpData_1[iIndex] = rBmpData[iIndex];
	        else
	            Vip_BmpData_1[iIndex] = vip_pixel_data_1[iIndex-54];
		end
	    //将数组中的数据写到输出BMP图片中    
		for (iIndex = 0; iIndex < iBmpSize; iIndex = iIndex + 1) begin
			rBmpWord = Vip_BmpData_1[iIndex];
			$fwrite(oBmpFileId_1,"%c",rBmpWord);
		end

		//关闭输出BMP图片
	$fclose(oBmpFileId_1);
	
end  
//initial end
//--------------------------------------------- 

//---------------------------------------------		
//初始化时钟和复位信号
reg inita_done ;

initial begin
    clk     = 1;
    rst_n   = 0;
	inita_done = 0 ;
    #110
    rst_n   = 1;
	#22_00
	inita_done = 1 ;
end 


//产生50MHz时钟
always #10 clk = ~clk;
 
//---------------------------------------------	

//---------------------------------------------		
//在时钟驱动下,从数组中读出像素数据,用于在Modelsim中查看BMP中的数据 
always@(posedge clk or negedge rst_n)begin
    if(!rst_n) begin
        pixel_data  <=  8'd0;
        pixel_index <=  0;
    end
    else begin
        pixel_data  <=  rBmpData[pixel_index];
        pixel_index <=  pixel_index+1;
    end
end
//---------------------------------------------
//---------------------------------------------
//产生摄像头时序 

wire		cmos_vsync ;
reg			cmos_href;
wire        cmos_clken;
reg	[23:0]	cmos_data;	
		 
reg         cmos_clken_r;

reg [31:0]  cmos_index;

parameter [10:0] IMG_HDISP = 11'd640;
parameter [10:0] IMG_VDISP = 11'd480;

localparam H_SYNC = 11'd5;		
localparam H_BACK = 11'd5;		
localparam H_DISP = IMG_HDISP;	
localparam H_FRONT = 11'd5;		
localparam H_TOTAL = H_SYNC + H_BACK + H_DISP + H_FRONT;	

localparam V_SYNC = 11'd1;		
localparam V_BACK = 11'd0;		
localparam V_DISP = IMG_VDISP;	
localparam V_FRONT = 11'd1;		
localparam V_TOTAL = V_SYNC + V_BACK + V_DISP + V_FRONT;

//---------------------------------------------
//模拟 OV7725/OV5640 驱动模块输出的时钟使能
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		cmos_clken_r <= 0;
	else
        cmos_clken_r <= ~cmos_clken_r;
end

//---------------------------------------------
//水平计数器
reg	[10:0]	hcnt;
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		hcnt <= 11'd0;
	else if(cmos_clken_r) 
		hcnt <= (hcnt < H_TOTAL - 1'b1) ? hcnt + 1'b1 : 11'd0;
end

//---------------------------------------------
//竖直计数器
reg	[10:0]	vcnt;
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		vcnt <= 11'd0;		
	else if(cmos_clken_r) begin
		if(hcnt == H_TOTAL - 1'b1)
			vcnt <= (vcnt < V_TOTAL - 1'b1) ? vcnt + 1'b1 : 11'd0;
		else
			vcnt <= vcnt;
    end
end

//---------------------------------------------
//场同步
reg	cmos_vsync_r;
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		cmos_vsync_r <= 1'b0;			//H: Vaild, L: inVaild
	else begin
		if(vcnt <= V_SYNC - 1'b1)
			cmos_vsync_r <= 1'b0; 	//H: Vaild, L: inVaild
		else
			cmos_vsync_r <= 1'b1; 	//H: Vaild, L: inVaild
    end
end
assign	cmos_vsync	= cmos_vsync_r;

//---------------------------------------------
//行有效
wire	frame_valid_ahead =  ( vcnt >= V_SYNC + V_BACK  && vcnt < V_SYNC + V_BACK + V_DISP
                            && hcnt >= H_SYNC + H_BACK  && hcnt < H_SYNC + H_BACK + H_DISP ) 
						? 1'b1 : 1'b0;
      
reg			cmos_href_r;      
always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		cmos_href_r <= 0;
	else begin
		if(frame_valid_ahead)
			cmos_href_r <= 1;
		else
			cmos_href_r <= 0;
    end
end

always@(posedge clk or negedge rst_n) begin
	if(!rst_n)
		cmos_href <= 0;
	else
        cmos_href <= cmos_href_r;
end

assign cmos_clken = cmos_href & cmos_clken_r;

//-------------------------------------
	//从数组中以视频格式输出像素数据
	wire [10:0] x_pos;
	wire [10:0] y_pos;

	assign x_pos = frame_valid_ahead ? (hcnt - (H_SYNC + H_BACK )) : 0;
	assign y_pos = frame_valid_ahead ? (vcnt - (V_SYNC + V_BACK )) : 0; 
always@(posedge clk or negedge rst_n)begin
   if(!rst_n) begin
       cmos_index   <=  0;
       cmos_data    <=  24'd0;
   end
   else begin
       //cmos_index   <=  y_pos * 1920  + x_pos*3 + 54;         //  3*(y*640 + x) + 54
       
       //读取图片时上下翻转
       cmos_index   <=  (479- y_pos) * 1920  + x_pos*3 + 54;         //  3*((479-y)*640 + x) + 54

       cmos_data    <=  {rBmpData[cmos_index], rBmpData[cmos_index+1] , rBmpData[cmos_index+2]};
   end
end

	wire 		per_frame_vsync	=	cmos_vsync ;	
	wire 		per_frame_href	=	cmos_href;	
	wire 		per_frame_clken	=	cmos_clken;	
	wire [7:0]	per_img_red		=	cmos_data[ 7: 0];	   	
	wire [7:0]	per_img_green	=	cmos_data[15: 8];   	            
	wire [7:0]	per_img_blue	=	cmos_data[23:16]; 


	wire        per0_frame_vsync	;
	wire        per0_frame_href		;
	wire        per0_frame_clken	;
	wire [7:0]  per0_img_Y			;
	wire [7:0]  per0_img_Cb	   		;
	wire [7:0]  per0_img_Cr	    	;
	
	VIP_RGB888_YCbCr444  u_VIP_RGB888_YCbCr444
(
	//global clock
	.clk(clk),  				//cmos video pixel clock
	.rst_n(rst_n),				//global reset

	//Image data prepred to be processd
	.per_frame_vsync	(per_frame_vsync),	//Prepared Image data vsync valid signal
	.per_frame_href		(per_frame_href),		//Prepared Image data href vaild  signal
	.per_frame_clken	(per_frame_clken),	//Prepared Image data output/capture enable clock	
	.per_img_red		(per_img_red),		//Prepared Image red data to be processed
	.per_img_green		(per_img_green),		//Prepared Image green data to be processed
	.per_img_blue		(per_img_blue),		//Prepared Image blue data to be processed
	
	//Image data has been processd
	.post_frame_vsync	(PIC1_vip_out_frame_vsync),	//Processed Image data vsync valid signal
	.post_frame_href	(PIC1_vip_out_frame_href),	//Processed Image data href vaild  signal
	.post_frame_clken	(PIC1_vip_out_frame_clken),	//Processed Image data output/capture enable clock	
	.post_img_Y			(PIC1_vip_out_img_R),			//Processed Image brightness output
	.post_img_Cb		(PIC1_vip_out_img_G),		//Processed Image blue shading output
	.post_img_Cr		(PIC1_vip_out_img_B)			//Processed Image red shading output
);

	
                                        
 //寄存图像处理之后的像素数据
//-------------------------------------
//第一张图

reg	[7:0]	frame_cnt_1;
reg [31:0] 	vip_cnt_1; 
reg         PIC1_out_frame_vsync_r;    //寄存VIP输出的场同步  
//------------------------------------------------------------------
always@(posedge clk or negedge rst_n)begin
   if(!rst_n) 
        PIC1_out_frame_vsync_r   <=  1'b0;
   else 
        PIC1_out_frame_vsync_r   <=  PIC1_vip_out_frame_vsync;
end 
//------------------------------------------------------------------
always@(posedge clk or negedge rst_n)begin
   if(!rst_n) 
        frame_cnt_1    <=  8'b0;
   else if(inita_done &&((!PIC1_out_frame_vsync_r )&  (PIC1_vip_out_frame_vsync)))   
		if(frame_cnt_1 < 8'd12)
			frame_cnt_1    <=  frame_cnt_1 + 1'b1; 
		else
			frame_cnt_1    <=  frame_cnt_1;
   else
		frame_cnt_1    <=  frame_cnt_1 ;
end

always@(posedge clk or negedge rst_n)begin
   if(!rst_n) begin
        vip_cnt_1 <=  32'd0;
   end
//输出第一帧数据
   else if(frame_cnt_1 == 8'd1) begin
        if(PIC1_vip_out_frame_href & PIC1_vip_out_frame_clken) begin
            vip_cnt_1 <=  vip_cnt_1 + 3;
            vip_pixel_data_1[(479-(vip_cnt_1/1920))*1920 + (vip_cnt_1%1920)+0] <= PIC1_vip_out_img_B ;
            vip_pixel_data_1[(479-(vip_cnt_1/1920))*1920 + (vip_cnt_1%1920)+1] <= PIC1_vip_out_img_G ;
            vip_pixel_data_1[(479-(vip_cnt_1/1920))*1920 + (vip_cnt_1%1920)+2] <= PIC1_vip_out_img_R ;
        end
   end
   
end

endmodule 

1、仿真图像的传入和输出需要实现用到fopen函数,在传入仿真图像时需要使用fopen函数将图像导入到一个数组中,在输入处理完的图像时将处理后的数组写入到照片中。

2、在测试文件中配置时钟信号、复位信号、场信号、行信号、数据信号等,在复位信号使能后,每当有一个到来时,都会有有一个图像数据通过之前的输入图像数组写入到待处理的数据信号中。然后这些数据就会传入到自己写的图像处理模块中进行处理。

最然说只有几行字,但是这个问题困扰了我好久,如果要是认认真真的去琢磨加上有人帮忙的话,估计几天就可以解决这个问题,可惜的事身边搞这个的人比较少,网上的一些教程也不是完全针对我这个痛点的,并且在一些相关的帖子底下请教也是迟迟得不到回复。虽然解决这个问题在一些大佬眼里比较简单,但是当我自己独立完成后还是有不小的成就感。

还有一点就是在查阅问题的时候老是分心,比如这次查如何写测试激励的问题,老是查着查着去看别什么神经网络加速,二值化等知识去了,以后一定要专心。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值