Syetem Verilog 将视频流输出写入 BMP 图片文件 testbench 激励代码

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_46621272/article/details/126441149


Syetem Verilog 将视频流输出写入 BMP 图片文件 testbench 激励代码


前言

  • Verilog 做图像视频算法仿真时,只能看见相关波形,不能直观查看计算后的图像视频效果。本文以临近缩放算法为例,用 BMP 图片文件代替视频数据来做图像视频缩放算法仿真。最终输出缩放后的 BMP 图片文件。可以通过查看图片的办法直观显示图像缩放算法产生的效果。
  • 本文中阐述的仿真环境适合很多采用 Verilog FPGA 实现的视频图像算法的仿真。比如各种视频缩放、旋转、拉伸等算法,比如视频滤波、降噪等算法。

一、 testbench 激励文件 bmp_for_videoStream.sv 代码

//bmp_for_videoStream.sv
//将视频流输出写入 BMP 图片文件
//本模块不能被综合,只能用来当仿真

module bmp_for_videoStream	#
(
	parameter	iREADY			= 10,			//插入 0-10 级流控信号, 10 是满级全速无等待
	parameter	iBMP_FILE_PATH	= ""
)
(
	input					clk,
	input					rst_n,
	input					frame_sync_n,		//输入视频帧同步复位,低有效
	output					vin_ready,
	input	[2:0][7:0]		vin_dat,			//输入视频数据
	input					vin_valid,			//输入视频数据有效
	input	[15:0]			vin_xres,			//输入视频水平分辨率
	input	[15:0]			vin_yres			//输入视频垂直分辨率
);

	string	FILE_NAME;

	logic	[7:0]		fn = 0;				//帧计数
	logic	[0:53][7:0]	bmp_header;			//BMP 图像文件头
	logic	[31:0]		offsetBits;			//BMP 图像数据位置
	logic	[31:0]		width;				//BMP 图像宽度
	logic	[31:0]		height;				//BMP 图像高度
	logic	[31:0]		sizeImage;			//BMP 图像大小(字节)
	logic	[31:0]		sizePixel;			//BMP 像素数量(像素个数)
	logic	[31:0]		sizeBmpFile;		//BMP 图像文件大小(字节)

	logic	[31:0]		pixel_cnt	= 0;	//像素计数器
	logic				wr_end_flag	= 0;	//写文件结束标记
	logic	[3:0]		cnt = '1;			//延时计数器,在帧同步脉冲到来后,延时一段时间再输出视频流数据

	logic	[15:0]		sx;					//水平像素计数器
	logic	[15:0]		sy;					//垂直像素计数器
	logic	[15:0]		addr_cnt;			//图片数据水平线地址计数器

	integer 			bmp_wp = 0;			//文件指针
	integer 			i;

	assign	offsetBits	= $bits(bmp_header)/8;
	assign	vin_ready	= vin_ready_r;		//流控信号

	always_ff@(posedge clk)
	begin
		if(rst_n == 0)
			cnt <= '1;						//延时计数器,在帧同步脉冲到来后,延时一段时间再输出视频流数据
		else if(frame_sync_n == 0)
			cnt <= 0;
		else if( cnt != '1 )
			cnt <= cnt + 1;
	end

	always_ff@(posedge clk)
	begin
		case(cnt)
		1:	begin
				width		= vin_xres;
				height		= vin_yres;
				sizePixel	= width*height;
				sizeImage	= ((width*3+3)&16'hfffc)*height;			//BMP 像素占用内存大小,必须是4的倍数
				sizeBmpFile	= offsetBits + sizeImage;

				{bmp_header[01],bmp_header[00]}									= 16'h4d42;		//BM	TYPE
				{bmp_header[05],bmp_header[04],bmp_header[03],bmp_header[02]}	= sizeBmpFile;	//SizeBmpFile
				{bmp_header[09],bmp_header[08],bmp_header[07],bmp_header[06]}	= '0;			//Reserverd
				{bmp_header[13],bmp_header[12],bmp_header[11],bmp_header[10]}	= offsetBits;	//OffsetBits
				
				{bmp_header[17],bmp_header[16],bmp_header[15],bmp_header[14]}	= 32'h0000_0028;//Size
				{bmp_header[21],bmp_header[20],bmp_header[19],bmp_header[18]}	= width;		//Width
				{bmp_header[25],bmp_header[24],bmp_header[23],bmp_header[22]}	= height;		//Height
				{bmp_header[27],bmp_header[26]}									= 16'h0001;		//Planes
				{bmp_header[29],bmp_header[28]}									= 16'h0018;		//Bitcount
				{bmp_header[33],bmp_header[32],bmp_header[31],bmp_header[30]}	= '0;			//Compression
				{bmp_header[37],bmp_header[36],bmp_header[35],bmp_header[34]}	= '0;	//sizeImage;	//SizeImage
				{bmp_header[41],bmp_header[40],bmp_header[39],bmp_header[38]}	= 32'h0000_c40e;//XPelsPermeter
				{bmp_header[45],bmp_header[44],bmp_header[43],bmp_header[42]}	= 32'h0000_c40e;//YPelsPermeter
				{bmp_header[49],bmp_header[48],bmp_header[47],bmp_header[46]}	= '0;			//ClrUsed
				{bmp_header[53],bmp_header[52],bmp_header[51],bmp_header[50]}	= '0;			//ClrImportant
				fn			<= fn + 1;
			end
		2:	begin
				$display("vout BMP File Size      = 0x%h",sizeBmpFile);
				$display("vout Image data offset  = 0x%h",offsetBits);
				$display("vout Image width        = 0x%h",width);
				$display("vout Image heigh        = 0x%h",height);
				$display("vout Image size         = 0x%h\n",sizeImage);
				FILE_NAME = $sformatf("%svout_%03d%s",iBMP_FILE_PATH,fn,".bmp");	//BMP 图片文件名
				$display("bmp file name = %s !",FILE_NAME);
			end
		3:	begin
				bmp_wp	= $fopen(FILE_NAME,"wb+");

				if(bmp_wp == 0)begin					//文件建立打开失败 ?
					$display("%s file open error !",FILE_NAME);
					$stop;
				end
			end
		4:	begin
				for(i=0;i<offsetBits;i++)
				begin
					if(bmp_wp == 0)begin				//文件建立打开失败 ?
						$display("%s file open error !",FILE_NAME);
						$stop;
					end
					else begin							//文件建立打开成功
						$fwrite(bmp_wp,"%c",	bmp_header[i]);
					end
				end
			end
		default:;
		endcase
	end
	
	always_ff@(posedge clk)
	begin
		if(frame_sync_n == 0 || rst_n == 0 || cnt != '1)begin
			pixel_cnt	<= 0;
			sx			<= 0;
			sy			<= 0;
			addr_cnt	<= 0;
			wr_end_flag	<= 0;
		end
		else if( vin_ready == 1 && vin_valid == 1 )begin			//视频数据有效 写文件没结束
			pixel_cnt	<= pixel_cnt + 1;			//像素计数器
			if(sx < width -1)begin
				sx			<= sx + 1;				//水平扫描计数
				addr_cnt	<= addr_cnt + 3;		//水平地址计数,一个像素3个字节
			end
			else begin
				sx			<= 0;
				addr_cnt	<= 0;
				sy			<= sy + 1;				//垂直扫描计数,该计数器目前没有使用
			end

			if(bmp_wp == 0)begin					//文件建立打开成功
				$display("%s file open error !",FILE_NAME);
				$stop;
			end
			
			if( wr_end_flag == 0 )
			begin
				if(sx != width-1)begin					//判断当前扫描像素是否行尾
					$fwrite(bmp_wp,"%c%c%c",vin_dat[0],vin_dat[1],vin_dat[2]);	//写像素
				end
				else begin						//每行像素占用的字节数必须是4的倍数
					case(addr_cnt[1:0])
					2'b00:	$fwrite(bmp_wp,"%c%c%c%c",		vin_dat[0],vin_dat[1],vin_dat[2],0);		//
					2'b01:	$fwrite(bmp_wp,"%c%c%c",		vin_dat[0],vin_dat[1],vin_dat[2]);			///
					2'b10:	$fwrite(bmp_wp,"%c%c%c%c%c%c",	vin_dat[0],vin_dat[1],vin_dat[2],0,0,0);	
					2'b11:	$fwrite(bmp_wp,"%c%c%c%c%c",	vin_dat[0],vin_dat[1],vin_dat[2],0,0);		/
					endcase
				end
			end
		end

		if( wr_end_flag	== 0 && pixel_cnt > sizePixel -1)begin		//判断像素计数器是否到结束
			wr_end_flag	<= 1;					//置写文件结束标记
			$fclose(bmp_wp);
//			$stop;
		end
	end	//	always_ff
	
	logic	[15:0]	ready_cnt	= 0;
	logic			vin_ready_r = 0;
	always_ff@(posedge clk)
	begin
		if(frame_sync_n == 0 || rst_n == 0 || ready_cnt >= 9 || cnt != '1)begin
			ready_cnt	<= 0;
		end
		else if(ready_cnt < 9)
			ready_cnt	<= ready_cnt + 1;
	end
	
	always_ff@(posedge clk)
	begin
		if(frame_sync_n == 0 || rst_n == 0 || cnt != '1)begin
			vin_ready_r	<= 0;
		end
		else if(ready_cnt < iREADY || iREADY == 10)
			vin_ready_r	<= 1;
		else
			vin_ready_r	<= 0;
	end

endmodule

二、相关连接

  • System Verilog 视频缩放图像缩放 vivado 仿真 https://blog.csdn.net/qq_46621272/article/details/126439519

三、本仿真工程文件下载,采用 Xilinx vivado 2017.4 版本

  • https://download.csdn.net/download/qq_46621272/86406386

你可能感兴趣的:(视频处理,fpga开发,verilog,systemverilog,视频缩放,图像缩放)