verilog实现中值滤波

转自:https://www.cnblogs.com/happyamyhope/

前言:

首先谢谢原博主的文章,对我的帮助很大,提供了一个完整的思路,极大方便了我将算法移植到FPGA上。

实现步骤:

1.查看了中值滤波实现相关的网站和paper;

2.按照某篇paper的设计思想进行编程实现;

3.对各个模块进行语法检查、波形仿真、时序设计、调试验证;

4.与matlab的中值滤波结果进行比较。

实现过程:

1.查看了中值滤波实现相关的网站和paper;

在网上看了很多中值滤波的设计,也有一些代码可以下载,也有一片讲解的,只是感觉讲解的比较模糊而且不完整,最后看了几篇硕士论文,论文竟然主要做了中值滤波的工作,发现了一些设计思路,然后就按照自己的想法进行设计。

2.按照某篇paper的设计思想进行编程实现;

整个中值滤波模块分为几个小的模块:3*3窗口生成模块、计数器控制模块、3*3中值滤波模块、顶层模块以及最后的测试模块testbench的编写。

整个框架的设计如下图所示(使用visio画的框架图):

各个模块的设计:

1)ROM IP核的生成,用于存储原始灰度图像的数据。

可以参考http://www.cnblogs.com/happyamyhope/p/5498745.html

使用matlab生成.coe图像数据文件,然后使用Xilinx ISE工具将.coe文件添加到ROM核进行数据初始化,按步骤得到ROM模块,参考生成的.v文件在顶层模块直接调用即可。

rom_512by512 rom_512by512_inst
  (
    .clka(CLK),           //input clka;
    .addra(rom_addr),     //input-from 
    .douta(rom_data)      //output-to 
  );

注意ROM的存储空间的大小;

2)3*3窗口生成模块,用于生成滤波的滑动窗口,得到窗口内的所有元素数据。

功能:

(1)根据中心像素点得到所在其所在的行、列位置;

(2)根据该模块的开始信号设计得到获取数据的有效时间序列;

(3)在读取数据的有效时序内,得到窗口内的所有元素数据;

(4)窗口数据的获取按照一定的时序顺序来获得,类似于黑金推荐的“仿顺序操作”,这个比较适合my style;不过后来发现调试的过程中被项目组的硬件人员改动了一些,甚至说不好,感觉可能是本人还没有理解掌握吃透“仿顺序操作”的精髓吧。

(5)根据中心像素点的行、列位置信息得到每个窗口元素的ROM地址,根据某一时刻ROM地址,下一时刻调用ROM模块得到对应的元素数据,下一时刻将数据锁存,然后再读取该地址的数据;所以要注意地址和数据的获取不是在同一时刻,而是需要延迟两个时刻;

(6)还需要注意的是图像的边界问题的特殊化处理;一般图像处理都会遇到边界问题,这个需要谨慎;

(7)对matlab的中值滤波函数medfilt2原理的深入掌握对我们编写这一模块非常重要。matlab并没有主要过程的代码,看注释默认情况下边界元素设置为0,这也可以通过结果反推回去发现的。

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    09:27:48 05/18/2016 
// Design Name: 
// Module Name:    win3by3_gen 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module win3by3_gen(
  CLK, 
  RSTn,
  center_pix_sig,
  cols,   // the column numbers of the input image
  rows,
  rom_data_win,   //input-from U1; 
  column_addr_sig,    //input-from U3; //output [9 : 0] addra; 
  row_addr_sig,         //input-from U3; //output [9 : 0] addra;
  rom_addr_sig,            //output-to U1; 
  data_out0,           //output-to U4;
  data_out1,
  data_out2,
  data_out3,
  data_out4,
  data_out5,
  data_out6,
  data_out7,
  data_out8,
  win_data_done_sig            //output-to U4/U3;complete the win data;
    );

  input CLK; 
  input RSTn;
  input [7:0] rom_data_win;
  input [9:0] cols;
  input [9:0] rows;
  input center_pix_sig;  // 
  input [9:0] column_addr_sig;
  input [9:0] row_addr_sig;
  
  output [7:0] data_out0;           //output-to U4;
  output [7:0] data_out1;
  output [7:0] data_out2;
  output [7:0] data_out3;
  output [7:0] data_out4;
  output [7:0] data_out5;
  output [7:0] data_out6;
  output [7:0] data_out7;
  output [7:0] data_out8;
  output [17:0] rom_addr_sig;
  output win_data_done_sig;
  
/***********************************************************************************/ 
  
  reg [9:0] m;
  
  always @ ( posedge CLK or negedge RSTn )
    if ( !RSTn )
       m <= 10'd1;
     else if (  center_pix_sig )
       m <= row_addr_sig[9:0];  
       
  /***********************************************************************************/ 
  
  reg [9:0] n;
  
  always @ ( posedge CLK or negedge RSTn )
    if ( !RSTn )
       n <= 10'd1;
     else if (  center_pix_sig )
       n <= column_addr_sig[9:0];    
        
  /***********************************************************************************/ 
  
  reg [3:0] i; 
  reg isWinDone;
  reg [17:0] rom_addr;
  reg [7:0] a11;
  reg [7:0] a12;
  reg [7:0] a13;
  reg [7:0] a21;
  reg [7:0] a22;
  reg [7:0] a23;
  reg [7:0] a31;
  reg [7:0] a32;
  reg [7:0] a33;
     
/***********************************************************************************/ 

reg get_9point_vld;

always @ ( posedge CLK or negedge RSTn )
    if (!RSTn)
           get_9point_vld <= 1'b0;
     else if ( center_pix_sig )  
            get_9point_vld <= 1'b1;
     else if ( i==4'd10 ) 
            get_9point_vld <= 1'b0;


always @ ( posedge CLK or negedge RSTn )
    if ( !RSTn )
           isWinDone <= 1'b0;
     else if ( i==4'd10 )  
            isWinDone <= 1'b1;
     else 
            isWinDone <= 1'b0;



always @ ( posedge CLK or negedge RSTn )
    if ( !RSTn )
           i <= 4'd0;
     else if (i == 4'd10)  
            i <= 4'd0;
     else if ( get_9point_vld ) 
            i <= i + 1'b1;



        
always @ ( posedge CLK or negedge RSTn )
    if (!RSTn) 
            rom_addr <= 0;
     else if ( get_9point_vld)
       case (i)
          4'd0:
            if(!(m==1 || n==1)) rom_addr <= (m-2)*cols + (n-1) -1;   
          
          4'd1:
          if(!(m==1 )) rom_addr <= (m-2)*cols + n -1; 
           
          4'd2:
            if(!(m==1 || n==cols)) rom_addr <= (m-2)*cols + (n+1) -1; 
          
          4'd3:
            if(!(n==1)) rom_addr <= (m-1)*cols + (n-1) -1; 
          
          4'd4:
            rom_addr <= (m-1)*cols + n -1; 
          
          4'd5:
            if(!(n==cols)) rom_addr <= (m-1)*cols + (n+1) -1; 
          
          4'd6:
            if(!(m==cols || n==1)) rom_addr <= m*cols + (n-1) -1; 
          
          4'd7:
            if(!(m==cols)) rom_addr <= m*cols + n -1; 
          
          4'd8:
            if(!(m==cols || n==cols)) rom_addr <= m*cols + (n+1) -1; 
             
          default:;

        endcase
        
always @ ( posedge CLK or negedge RSTn )
    if (!RSTn)
       begin
          a11 <= 0; 
          a12 <= 0; 
          a13 <= 0; 
          a21 <= 0; 
          a22 <= 0; 
          a23 <= 0; 
          a31 <= 0; 
          a32 <= 0;
          a33 <= 0;
        end
     else if ( get_9point_vld )
     
       case (i)
  
          4'd2:
          if ( m==1 || n==1 ) 
                a11 <= 0;     
          else 
                a11 <= rom_data_win;      
          
          4'd3:
          if ( m==1 )  a12 <= 0; 
          else a12 <= rom_data_win;       
          
          4'd4:
          if ( m==1 || n==cols ) a13 <= 0; 
          else a13 <= rom_data_win; 
          
          4'd5:
          if ( n==1 ) a21 <= 0; 
          else  a21 <= rom_data_win; 
          
          4'd6:
          a22 <= rom_data_win; 
                    
          4'd7:
          if ( n==cols ) a23 <= 0; 
          else a23 <= rom_data_win;
          
          4'd8:
          if ( m==cols || n==1 ) a31 <= 0;
          else a31 <= rom_data_win;  
          
          4'd9:
          if ( m==cols ) a32 <= 0;
          else a32 <= rom_data_win;
          
          4'd10:
          if ( m==cols || n==cols ) a33 <= 0; 
          else a33 <= rom_data_win;  
          
          default:;
          
      endcase
  
/***********************************************************************************/
  
  assign win_data_done_sig = isWinDone;
  assign rom_addr_sig = rom_addr;
  
  assign data_out0 = a11;
  assign data_out1 = a12;
  assign data_out2 = a13;
  assign data_out3 = a21;
  assign data_out4 = a22;
  assign data_out5 = a23;
  assign data_out6 = a31;
  assign data_out7 = a32;
  assign data_out8 = a33;
  
/***********************************************************************************/ 
 
endmodule

3)计数器控制模块,主要用于获得中心像素点的地址信息。

(1)系统模块开始信号之后开始获取第一个中心像素点,注意初始化信号值和系统开始的信号值的区别;

(2)该时刻得到的的数据将在下一个时刻产生结果,该时刻的数据并没有改变;

(3)注意中心像素点的行、列位置信息的计算;

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    09:28:59 05/18/2016 
// Design Name: 
// Module Name:    counter_ctrl 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module counter_ctrl(
  CLK,
  RSTn,
  start_sig,  //input-from top
  nxt_pix_sig,     //input-from --start next center point pixel
  cols,                          
  column_addr_sig,  //output
  row_addr_sig,     //output-to 
  pix_done_sig   //output-to
    );
     
  input CLK;
  input RSTn;
  input start_sig;
  input nxt_pix_sig;
  input [9:0] cols;
  
  output pix_done_sig;  
  output [9:0] column_addr_sig;    
  output [9:0] row_addr_sig;   
  
 /**********************************************************************************/
  
  reg isCtrlDone;
  //reg isWinStart;
  reg [17:0] imk;   //The k-th pixel of the image
  reg [9:0] row_addr;  // The row of the centeral pixel
  reg [9:0] column_addr;   // The column of the centeral pixel
  
  reg start_sig_d;
  
  wire start_sig_rising_vld;
  
   always @ (posedge CLK or negedge RSTn)   //Asynchronous reset  
    if (!RSTn)
        start_sig_d <= 0;
     else 
        start_sig_d <= start_sig;
  
  assign start_sig_rising_vld = start_sig & (~start_sig_d);
  
  always @ (posedge CLK or negedge RSTn)   //Asynchronous reset
    if (!RSTn)
       begin  
        imk <= 18'b0; 
        column_addr <= 10'b0; 
        row_addr <= 10'b0;
        isCtrlDone <= 1'b0;    
        end
     else if (start_sig_rising_vld)
       begin  
        imk <= 18'b1; 
        column_addr <= 10'b1; 
        row_addr <= 10'b1;
        isCtrlDone <= 1'b1;    
        end    
     else if ( nxt_pix_sig )
       begin  
          imk <= imk + 1'b1;
          row_addr <= imk / cols + 1;   
          column_addr <= imk % cols + 1;   
        isCtrlDone <= 1'b1; 
        end
     else isCtrlDone <= 1'b0;    
          
/***********************************************************************************/
  
  assign row_addr_sig = row_addr;
  assign column_addr_sig = column_addr;
  assign pix_done_sig = isCtrlDone;
  
/***********************************************************************************/
endmodule

4) 3*3中值滤波模块

功能:得到某一中心像素点的3*3滑窗区域的灰度值的中值,作为中心像素点的值;

中值滤波原理,网上有很多,大家可以查看一下。

本项目采用的是快速中值滤波的方法。

(1)若是3*3窗口生成模块完成之后就计算下一个中心像素点,需要将该中心像素点的窗口元素锁存起来,以防计算过程中将这些元素掩盖,不能正确进行中值滤波的计算;

always @ ( posedge CLK or negedge RSTn )
    if (!RSTn)
      begin
            a11 <= 0;
            a12 <= 0;
            a13 <= 0;
            a21 <= 0;
            a22 <= 0;
            a23 <= 0;
            a31 <= 0;
            a32 <= 0;
            a33 <= 0;
        end
     else if (win_data_sig)
       begin
            a11 <= data_in0;
            a12 <= data_in1;
            a13 <= data_in2;
            a21 <= data_in3;
            a22 <= data_in4;
            a23 <= data_in5;
            a31 <= data_in6;
            a32 <= data_in7;
            a33 <= data_in8;
        end

(2)需要在时序的有效区域内进行计算,怎么设计信号的有效性;

always @ ( posedge CLK or negedge RSTn )
    if (!RSTn)
        cal_vld <= 1'b0;
    else if( win_data_sig )
        cal_vld <= 1'b1;
    else if( i==3'd3 )
        cal_vld <= 0;

(3)仿顺序操作可以分开进行;每一个时刻只进行一个操作,这样可能更明了(代码中没有这样做);

always @ ( posedge CLK or negedge RSTn )
    if (!RSTn)
        i <= 3'd0;
    else if( cal_vld & ( i!=3 ) )
        i <= i + 1;
    else
        i <= 0;

(4)verilog编程调用函数的方法,指出输入信号,函数内可以使用其他定义声明的信号,最后的输出信号作为调用函数的结果(突然想起来,如果输出信号有多个元素呢,又该怎么办呢?大家可以想想);

function [7:0] max;//if the data is signed number, please add the char signed behind key function; 
    input [7:0] a, b, c;
    begin
        max = (((a >= b) ? a : b) >= c ) ?  ((a >= b) ? a : b) : c;
    end
endfunction

该模块的代码:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    09:28:20 05/18/2016 
// Design Name: 
// Module Name:    medfilter3by3 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
module medfilter3by3(
	CLK,
	RSTn,
	win_data_sig,  		//input-from module of win3by3_gen; 
	medfilt_done_sig,   //output-to top;
	data_in0,        	//input-from module of win3by3_gen;
	data_in1,
	data_in2,
	data_in3,
	data_in4,
	data_in5,
	data_in6,
	data_in7,
	data_in8,
	medfilt_data_out    //output-to top; 
	);

	input CLK;
	input RSTn;
	input win_data_sig;
	input [7:0] data_in0;           //output-to ;
	input [7:0] data_in1;
	input [7:0] data_in2;
	input [7:0] data_in3;
	input [7:0] data_in4;
	input [7:0] data_in5;
	input [7:0] data_in6;
	input [7:0] data_in7;
	input [7:0] data_in8;

	output medfilt_done_sig;
	output [7:0] medfilt_data_out;

	/******************************************************************************/ 
	reg [7:0] a11;
	reg [7:0] a12;
	reg [7:0] a13;
	reg [7:0] a21;
	reg [7:0] a22;
	reg [7:0] a23;
	reg [7:0] a31;
	reg [7:0] a32;
	reg [7:0] a33;

	reg [7:0] b11;
	reg [7:0] b12;
	reg [7:0] b13;
	reg [7:0] b21;
	reg [7:0] b22;
	reg [7:0] b23;
	reg [7:0] b31;
	reg [7:0] b32;
	reg [7:0] b33;

	reg [7:0] c11;
	reg [7:0] c12;
	reg [7:0] c13;
	reg [7:0] c21;
	reg [7:0] c22;
	reg [7:0] c23;
	reg [7:0] c31;
	reg [7:0] c32;
	reg [7:0] c33;

	reg [2:0] i;
	reg [7:0] medfilt_data;
	reg filt_done;

	reg cal_vld;


	always @ ( posedge CLK or negedge RSTn )
		if (!RSTn)
			begin
				a11 <= 0;
				a12 <= 0;
				a13 <= 0;
				a21 <= 0;
				a22 <= 0;
				a23 <= 0;
				a31 <= 0;
				a32 <= 0;
				a33 <= 0;
			end
		else if (win_data_sig)
			begin
				a11 <= data_in0;
				a12 <= data_in1;
				a13 <= data_in2;
				a21 <= data_in3;
				a22 <= data_in4;
				a23 <= data_in5;
				a31 <= data_in6;
				a32 <= data_in7;
				a33 <= data_in8;
			end

	always @ ( posedge CLK or negedge RSTn )
		if (!RSTn)
			i <= 3'd0;
		else if( cal_vld & ( i!=3 ) )
			i <= i + 1;
		else 
			i <= 0;

	always @ ( posedge CLK or negedge RSTn )
		if (!RSTn)
			cal_vld <= 1'b0;
		else if( win_data_sig )
			cal_vld <= 1'b1;
		else if( i==3'd3 )
			cal_vld <= 0;            


	always @ ( posedge CLK or negedge RSTn )
		if (!RSTn)
			begin
				filt_done <= 1'b0;
				b11 <= 0;
				b12 <= 0;
				b13 <= 0;
				b21 <= 0;
				b22 <= 0;
				b23 <= 0;
				b31 <= 0;
				b32 <= 0;
				b33 <= 0;
				c11 <= 0;
				c12 <= 0;
				c13 <= 0;
				c21 <= 0;
				c22 <= 0;
				c23 <= 0;
				c31 <= 0;
				c32 <= 0;
				c33 <= 0;
				medfilt_data <= 0;
			end
		else if( cal_vld )
			case(i)
				3'd0:
					begin
						b11 <= max(a11, a21, a31); 
						b12 <= max(a12, a22, a32); 
						b13 <= max(a13, a23, a33);
						b21 <= med(a11, a21, a31); 
						b22 <= med(a12, a22, a32); 
						b23 <= med(a13, a23, a33);
						b31 <= min(a11, a21, a31); 
						b32 <= min(a12, a22, a32); 
						b33 <= min(a13, a23, a33);
					end

				3'd1:
					begin
						c31 <= max(b31, b32, b33);
						c22 <= med(b21, b22, b23);
						c13 <= min(b11, b12, b13); 
					end

				3'd2:
					begin
						medfilt_data <= med(c13, c22, c31);
						filt_done<=1'b1;
					end

				3'd3:
					filt_done <= 1'b0; 

				default:;

			endcase

	/*******************************************************************************/ 

	function [7:0] max;//if the data is signed number, please add the char signed behind key function; 
		input [7:0] a, b, c;
		begin
			max = (((a >= b) ? a : b) >= c ) ?  ((a >= b) ? a : b) : c;
		end
	endfunction

	function [7:0] med;
		input [7:0] a, b, c;
		begin
			med = a < b ? (b < c ? b : a < c ? c : a) : (b > c ? b : a > c ? c : a);
		end
	endfunction

	function [7:0] min;
		input [7:0] a, b, c;
		begin
			min= (((a <= b) ? a : b) <= c ) ?  ((a <= b) ? a : b) : c;
		end
	endfunction

	/*******************************************************************************/ 

	assign medfilt_data_out = medfilt_data;
	assign medfilt_done_sig = filt_done;

	/*******************************************************************************/ 

endmodule

5)顶层模块,用于将低层的各个功能/控制模块衔接起来,得到结果;

注意输入输出信号,以及不同模块之间是如何进行连线的。

信号的名称尽量有其特别的意义,不要重复使用同一个信号名称,容易造成混乱;

区别wire和reg类型数据的使用情况;

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    09:29:33 05/18/2016 
// Design Name: 
// Module Name:    medfilter2 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////

module medfilter2  
(
  CLK, 
  RSTn,
  Start_sig,
  Done_sig,
  Data_out
);
     
  input CLK;
  input RSTn;
  input Start_sig;
  output Done_sig;
  output [7:0] Data_out;
  
  /********************************************************************/
  
  wire [17:0] rom_addr; //
  wire [7:0] rom_data;  // 

  rom_512by512 rom_512by512_inst
  (
    .clka(CLK),          //input clka;
    .addra(rom_addr),   //input-from; 
    .douta(rom_data)     //output-to ; 
  );

  /******************************************************************************/
  
  //wire [7:0] win_data[8:0];
  wire [7:0] data_out0;           //output-to ;
  wire [7:0] data_out1;
  wire [7:0] data_out2;
  wire [7:0] data_out3;
  wire [7:0] data_out4;
  wire [7:0] data_out5;
  wire [7:0] data_out6;
  wire [7:0] data_out7;
  wire [7:0] data_out8;
  wire win_done_sig;
  
 wire [9:0] column_addr_sig;
 wire [9:0] row_addr_sig;
 
  win3by3_gen win3by3_gen_inst (
  .CLK(CLK), 
  .RSTn(RSTn),
  .center_pix_sig(win_start_sig), //input-from ; 
  .cols(10'd512),   // the column numbers of the input image
  .rows(10'd512),   // the row numbers of the input image
  .rom_data_win(rom_data),    //input-from ; 
  .column_addr_sig(column_addr_sig),    //input-from ; //output [9 : 0] addra; 
  .row_addr_sig(row_addr_sig),         //input-from ; //output [9 : 0] addra;
  .rom_addr_sig(rom_addr),   //output-to ; 
  .data_out0(data_out0),           //output-to ;
  .data_out1(data_out1),
  .data_out2(data_out2),
  .data_out3(data_out3),
  .data_out4(data_out4),
  .data_out5(data_out5),
  .data_out6(data_out6),
  .data_out7(data_out7),
  .data_out8(data_out8),
  .win_data_done_sig(win_done_sig)  //output-to U4/U3; 
    );
  
  /******************************************************************************/ 
   
  counter_ctrl counter_ctrl_inst(
  .CLK(CLK),
  .RSTn(RSTn),
  .start_sig(Start_sig),  //input-from top 
  .nxt_pix_sig(win_done_sig),  //input-from 
  .cols(10'd512), 
  .column_addr_sig(column_addr_sig),  //output-to 
  .row_addr_sig(row_addr_sig),     //output-to 
  .pix_done_sig(win_start_sig)   //output-to    
  );
  
/*****************************************************************************/
 
 wire medfilt_done_sig;
 wire [7:0] medfilt_data_wire;
 
 medfilter3by3 medfilter3by3_inst
(
  .CLK(CLK),
  .RSTn(RSTn), 
  .win_data_sig(win_done_sig),  //input-from; 
  .medfilt_done_sig(medfilt_done_sig), //output-to;
  .data_in0(data_out0),        //input-from ;
  .data_in1(data_out1),
  .data_in2(data_out2),
  .data_in3(data_out3),
  .data_in4(data_out4),
  .data_in5(data_out5),
  .data_in6(data_out6),
  .data_in7(data_out7),
  .data_in8(data_out8),
  .medfilt_data_out(medfilt_data_wire)     //output-to top; 
); 

/*********************************************************************/
 wire Done_sig;
 wire [7:0] Data_out;
 assign Done_sig = medfilt_done_sig;
 assign Data_out = medfilt_data_wire;
 
/**********************************************************************/
endmodule

6)测试模块

如何将数据写入文件,需要定义文件的名称和类型;

integer fouti;

需要在初始化部分打开文件:

fouti = $fopen("medfilter2_re.txt");

代码如下:

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer:
//
// Create Date:   13:57:14 05/24/2016
// Design Name:   medfilter2
// Module Name:   E:/stereo_match_pro/stereo_match_FPGA0518/medfilter_tb.v
// Project Name:  stereo_match_FPGA0518
// Target Device:  
// Tool versions:  
// Description: 
//
// Verilog Test Fixture created by ISE for module: medfilter2
//
// Dependencies:
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
////////////////////////////////////////////////////////////////////////////////

module medfilter_tb;

    // Inputs
    reg CLK;
    reg RSTn;
    reg Start_sig;
    reg [18:0] pix_cnt;   //512*512=262144=100,0000,0000,0000,0000
    

    // Outputs
    wire Done_sig;
    wire [7:0] Data_out;
    integer fouti;
        

    // Instantiate the Unit Under Test (UUT)
    medfilter2 uut (
        .CLK(CLK), 
        .RSTn(RSTn), 
        .Start_sig(Start_sig), 
        .Done_sig(Done_sig), 
        .Data_out(Data_out)
    );
    
    //assign Data_out = 0;
   //assign Done_sig = 0;

    initial begin
        // Initialize Inputs
        CLK = 0;
        RSTn = 1;
        Start_sig = 0;
        
        fouti = $fopen("medfilter2_re.txt");

        // Wait 100 ns for global reset to finish
        #100;   // To reset the system
        // Add stimulus here
        RSTn = 0;
        Start_sig = 1;
        pix_cnt = 0;
        
        #100;   // To start the system
        // Add stimulus here
        RSTn = 1;
        pix_cnt = 1;
    
    end
    
    always #10 CLK = ~CLK;
    
    always@(posedge CLK)
    begin
        if(Done_sig)
           pix_cnt <= pix_cnt + 1;
    end
    
    always@(posedge CLK)
    begin
        if(pix_cnt == 19'd262145)
           begin 
              Start_sig <= 0; 
              $display("Image Medfilter Completed!\n");
              $display("The all time is %d \n",$time);
              $stop;
            end
    end

    

    always@(posedge CLK)
    begin
        if(Done_sig)
            begin
              $fwrite(fouti, "%d", Data_out, "\n");
              $display("%d",pix_cnt);
            end
    end
     
endmodule

整体的代码就是这样的。

4.与matlab的中值滤波结果进行比较

使用matlab编程基于自带的中值滤波函数得到处理之后的图像与数据,并将verilog得到的滤波数据转换为图像,将二者进行比较。

使用matlab自带的中值滤波函数medfilt2生成原图像的灰度图像的滤波数据;

% mcode to median filter for one jpg image, and create a image data file
src = imread('lena.jpg');
gray = rgb2gray(src);
 
medfilt2im = medfilt2( gray );
[m, n] = size( medfilt2im );                  % m行 n列
 
N = m*n;                               %%数据的长度,即存储器深度。
word_len = 8;                          %%每个单元的占据的位数,需自己设定
lena_gray = reshape(gray', 1, N);% 1行N列
lena_medfilt = reshape(medfilt2im', 1, N);% 1行N列
 
fid_gray=fopen('lena_gray.txt', 'wt');       %打开文件
fid_medfilt=fopen('lena_medfilt.txt', 'wt');       %打开文件
% fprintf(fid, 'MEMORY_INITIALIZATION_RADIX=16;\n');
% fprintf(fid, 'MEMORY_INITIALIZATION_VECTOR=\n');
 
 
for i = 1 : N-1
    fprintf(fid_gray, '%d,\n', lena_gray(i));%使用%x表示十六进制数
end
fprintf(fid_gray, '%d;\n', data(N));                 %%输出结尾,每个数据后面用逗号或者空格或者换行符隔开,最后一个数据后面加分号
fclose(fid_gray);                            %%关闭文件
 
for i = 1 : N-1
    fprintf(fid_medfilt, '%d,\n', lena_medfilt(i));%使用%x表示十六进制数
end
fprintf(fid_medfilt, '%d;\n', lena_medfilt(N));                 %%输出结尾,每个数据后面用逗号或者空格或者换行符隔开,最后一个数据后面加分号
fclose(fid_medfilt);                            %%关闭文件

将medfilt2函数和verilog产生的滤波数据转换为图像,并与matlab直接产生的滤波图像进行对比,代码如下:

% code to create image data from txt file
clc;
clear all;
close all;
I_rgb = imread('lena.jpg');
subplot(2, 3, 1), imshow(I_rgb), title('lena-rgb')
 
I_gray = rgb2gray(I_rgb);
subplot(2, 3, 2), imshow(I_gray), title('lena-gray')
 
medfilt_m_load = load('.\lena_medfilt.txt');
%medfilt_m_load = load('.\lena.coe');
medfilt_v_load = load('.\medfilter2_reV1.txt'); % verilog 产生的中值滤波之后数据
 
medfilt2im = medfilt2( I_gray );
subplot(2, 3, 3), imshow(medfilt2im), title('lena-medfilt2')
 
m = 512;
n = 512;
medfilt_m = reshape(medfilt_m_load, m, n);
medfilt_v = reshape(medfilt_v_load, m, n);
medfilt_m = uint8(medfilt_m');
medfilt_v = uint8(medfilt_v');
 
aa = medfilt2im - medfilt_m;
bb = medfilt2im - medfilt_v;
cc = medfilt_m - medfilt_v;
 
subplot(2, 3, 5), imshow(medfilt_m), title('medfilt-matlab');
subplot(2, 3, 6), imshow(medfilt_v), title('medfilt-verilog');

显示的结果如下图所示:

结果:两种滤波产生的图像数据完全一致,不过感觉函数直接产生的图像颜色更深一些,不知道为什么。

这里需要了解一下medfilt2这个函数的原理。结果数据表明,默认情况下该函数对图像边界采用的是补0的方法进行处理的。

结论

中值滤波终于告一段落了!简单的问题还是需要深入进去研究的,实践的过程中你才会发现自己之前了解的东西是多么的浅薄,对已知的知识掌握的是多么的流于表面!

猜你喜欢

转载自blog.csdn.net/weixin_38621214/article/details/83743971