| 一、实现步骤: 
 1.查看了中值滤波实现相关的网站和paper;
 
 2.按照某篇paper的设计思想进行编程实现;
 
 3.对各个模块进行语法检查、波形仿真、时序设计、调试验证;
 
 4.与matlab的中值滤波结果进行比较。
 
 
 二、实现过程:
 
 1.查看了中值滤波实现相关的网站和paper;
 
 在网上看了很多中值滤波的设计,也有一些代码可以下载,也有一片讲解的,只是感觉讲解的比较模糊而且不完整,最后看了几篇硕士论文,论文竟然主要做了中值滤波的工作,发现了一些设计思路,然后就按照自己的想法进行设计。
 
 2.按照某篇paper的设计思想进行编程实现;
 
 整个中值滤波模块分为几个小的模块:3*3窗口生成模块、计数器控制模块、3*3中值滤波模块、顶层模块以及最后的测试模块testbench的编写。
 
 整个框架的设计如下图所示(使用visio画的框架图):
 
 
 
 各个模块的设计:
 
 1)ROM IP核的生成,用于存储原始灰度图像的数据。
 使用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,这也可以通过结果反推回去发现的。
 
 1 `timescale 1ns / 1ps
 2 //////////////////////////////////////////////////////////////////////////////////
 3 // Company:
 4 // Engineer:
 5 //
 6 // Create Date:
 7 // Design Name:
 8 // Module Name:    win3by3_gen
 9 // Project Name:
 10 // Target Devices:
 11 // Tool versions:
 12 // Description:
 13 //
 14 // Dependencies:
 15 //
 16 // Revision:
 17 // Revision 0.01 - File Created
 18 // Additional Comments:
 19 //
 20 //////////////////////////////////////////////////////////////////////////////////
 21 module win3by3_gen(
 22   CLK,
 23   RSTn,
 24   center_pix_sig,
 25   cols,   // the column numbers of the input image
 26   rows,
 27   rom_data_win,   //input-from U1;
 28   column_addr_sig,    //input-from U3; //output [9 : 0] addra;
 29   row_addr_sig,         //input-from U3; //output [9 : 0] addra;
 30   rom_addr_sig,            //output-to U1;
 31   data_out0,           //output-to U4;
 32   data_out1,
 33   data_out2,
 34   data_out3,
 35   data_out4,
 36   data_out5,
 37   data_out6,
 38   data_out7,
 39   data_out8,
 40   win_data_done_sig            //output-to U4/U3;complete the win data;
 41     );
 42
 43   input CLK;
 44   input RSTn;
 45   input [7:0] rom_data_win;
 46   input [9:0] cols;
 47   input [9:0] rows;
 48   input center_pix_sig;  //
 49   input [9:0] column_addr_sig;
 50   input [9:0] row_addr_sig;
 51
 52   output [7:0] data_out0;           //output-to U4;
 53   output [7:0] data_out1;
 54   output [7:0] data_out2;
 55   output [7:0] data_out3;
 56   output [7:0] data_out4;
 57   output [7:0] data_out5;
 58   output [7:0] data_out6;
 59   output [7:0] data_out7;
 60   output [7:0] data_out8;
 61   output [17:0] rom_addr_sig;
 62   output win_data_done_sig;
 63
 64 /******************************************************************************************************************************/
 65
 66   reg [9:0] m;
 67
 68   always @ ( posedge CLK or negedge RSTn )
 69     if ( !RSTn )
 70        m <= 10'd1;
 71      else if (  center_pix_sig )
 72        m <= row_addr_sig[9:0];
 73
 74   /******************************************************************************************************************************/
 75
 76   reg [9:0] n;
 77
 78   always @ ( posedge CLK or negedge RSTn )
 79     if ( !RSTn )
 80        n <= 10'd1;
 81      else if (  center_pix_sig )
 82        n <= column_addr_sig[9:0];
 83
 84   /*****************************************************************************************************************************/
 85
 86   reg [3:0] i;
 87   reg isWinDone;
 88   reg [17:0] rom_addr;
 89   reg [7:0] a11;
 90   reg [7:0] a12;
 91   reg [7:0] a13;
 92   reg [7:0] a21;
 93   reg [7:0] a22;
 94   reg [7:0] a23;
 95   reg [7:0] a31;
 96   reg [7:0] a32;
 97   reg [7:0] a33;
 98
 99 /*****************************************************************************************************************************/
 100
 101 reg get_9point_vld;
 102
 103 always @ ( posedge CLK or negedge RSTn )
 104     if (!RSTn)
 105            get_9point_vld <= 1'b0;
 106      else if ( center_pix_sig )
 107             get_9point_vld <= 1'b1;
 108      else if ( i==4'd10 )
 109             get_9point_vld <= 1'b0;
 110
 111
 112 always @ ( posedge CLK or negedge RSTn )
 113     if ( !RSTn )
 114            isWinDone <= 1'b0;
 115      else if ( i==4'd10 )
 116             isWinDone <= 1'b1;
 117      else
 118             isWinDone <= 1'b0;
 119
 120
 121
 122 always @ ( posedge CLK or negedge RSTn )
 123     if ( !RSTn )
 124            i <= 4'd0;
 125      else if (i == 4'd10)
 126             i <= 4'd0;
 127      else if ( get_9point_vld )
 128             i <= i + 1'b1;
 129
 130
 131
 132
 133 always @ ( posedge CLK or negedge RSTn )
 134     if (!RSTn)
 135             rom_addr <= 0;
 136      else if ( get_9point_vld)
 137        case (i)
 138           4'd0:
 139             if(!(m==1 || n==1)) rom_addr <= (m-2)*cols + (n-1) -1;
 140
 141           4'd1:
 142           if(!(m==1 )) rom_addr <= (m-2)*cols + n -1;
 143
 144           4'd2:
 145             if(!(m==1 || n==cols)) rom_addr <= (m-2)*cols + (n+1) -1;
 146
 147           4'd3:
 148             if(!(n==1)) rom_addr <= (m-1)*cols + (n-1) -1;
 149
 150           4'd4:
 151             rom_addr <= (m-1)*cols + n -1;
 152
 153           4'd5:
 154             if(!(n==cols)) rom_addr <= (m-1)*cols + (n+1) -1;
 155
 156           4'd6:
 157             if(!(m==cols || n==1)) rom_addr <= m*cols + (n-1) -1;
 158
 159           4'd7:
 160             if(!(m==cols)) rom_addr <= m*cols + n -1;
 161
 162           4'd8:
 163             if(!(m==cols || n==cols)) rom_addr <= m*cols + (n+1) -1;
 164
 165           default:;
 166
 167         endcase
 168
 169 always @ ( posedge CLK or negedge RSTn )
 170     if (!RSTn)
 171        begin
 172           a11 <= 0;
 173           a12 <= 0;
 174           a13 <= 0;
 175           a21 <= 0;
 176           a22 <= 0;
 177           a23 <= 0;
 178           a31 <= 0;
 179           a32 <= 0;
 180           a33 <= 0;
 181         end
 182      else if ( get_9point_vld )
 183
 184        case (i)
 185
 186           4'd2:
 187           if ( m==1 || n==1 )
 188                 a11 <= 0;
 189           else
 190                 a11 <= rom_data_win;
 191
 192           4'd3:
 193           if ( m==1 )  a12 <= 0;
 194           else a12 <= rom_data_win;
 195
 196           4'd4:
 197           if ( m==1 || n==cols ) a13 <= 0;
 198           else a13 <= rom_data_win;
 199
 200           4'd5:
 201           if ( n==1 ) a21 <= 0;
 202           else  a21 <= rom_data_win;
 203
 204           4'd6:
 205           a22 <= rom_data_win;
 206
 207           4'd7:
 208           if ( n==cols ) a23 <= 0;
 209           else a23 <= rom_data_win;
 210
 211           4'd8:
 212           if ( m==cols || n==1 ) a31 <= 0;
 213           else a31 <= rom_data_win;
 214
 215           4'd9:
 216           if ( m==cols ) a32 <= 0;
 217           else a32 <= rom_data_win;
 218
 219           4'd10:
 220           if ( m==cols || n==cols ) a33 <= 0;
 221           else a33 <= rom_data_win;
 222
 223           default:;
 224
 225       endcase
 226
 227 /**********************************************************************************************/
 228
 229   assign win_data_done_sig = isWinDone;
 230   assign rom_addr_sig = rom_addr;
 231
 232   assign data_out0 = a11;
 233   assign data_out1 = a12;
 234   assign data_out2 = a13;
 235   assign data_out3 = a21;
 236   assign data_out4 = a22;
 237   assign data_out5 = a23;
 238   assign data_out6 = a31;
 239   assign data_out7 = a32;
 240   assign data_out8 = a33;
 241
 242 /**********************************************************************************************/
 243
 244 endmodule
 
 
 3)计数器控制模块,主要用于获得中心像素点的地址信息。
 
 (1)系统模块开始信号之后开始获取第一个中心像素点,注意初始化信号值和系统开始的信号值的区别;
 
 (2)该时刻得到的的数据将在下一个时刻产生结果,该时刻的数据并没有改变;
 
 (3)注意中心像素点的行、列位置信息的计算;
 
 `timescale 1ns / 1ps
 //////////////////////////////////////////////////////////////////////////////////
 // Company:
 // Engineer:
 //
 // Create Date:
 // 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:
 // 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:
 // 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:
 // 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(</span><span style="color: #800000;">"</span><span style="color: #800000;">The all time is %d \n</span><span style="color: #800000;">"</span>,$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
 
 整体的代码就是这样的。
 
 3.对各个模块进行语法检查、波形仿真、时序设计、调试验证;
 
 本人觉得原理清楚之后按部就班的编写代码还好,只是刚接触波形仿真和调试的时候是真心不顺心,还好有同事帮忙调试;在调试的过程中其实会学习到很多东西,很多经验,以及很简单的但你之前就是不知道的知识,这就是一个实践的过程,有时候你根本不知道错误在哪里,这怎么会是错误的呢,为什么不可以这样写,我觉得这样写才是正确的,这些就是在调试过程中本人的真实心情写照呀。可是,没有那么多为什么,verilog就是这样编程的,只是你不知道而已!这才是最伤人的,因为你不知道!
 
 仿真调试的过程中遇到的问题以及解决方法有空专门写一篇,调试的过程中最好是一个一个模块的测试,特别是关键信号的数值,最好搞懂整体模块和各个模块的时序设计过程,推荐使用TimeDesigner进行波形的设计;另外还需要有关联的两个甚至多个不同模块信号的交叉仿真验证。
 
 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的方法进行处理的。
 
 结论
 
 中值滤波终于告一段落了!简单的问题还是需要深入进去研究的,实践的过程中你才会发现自己之前了解的东西是多么的浅薄,对已知的知识掌握的是多么的流于表面!
 
 最后结果的数据还是很让人开心的!
 |