前言
项目需要,想要实现算法中的其中一步即中值滤波,同时,因为图像处理部分中值滤波相对来说还是比较简单的,将中值滤波的硬件实现作为进入FPGA领域的第一次尝试。虽然说网上有较多关于中值滤波的文档,可是说实话,其一没有详细地讲解实现方法及原因,其二没有关于完整过程的叙述,其三有些网站上有代码但是下载下来几乎没有用,因为你根本看不明白,俗话说得好,吃别人嚼过的馍真tm的没味儿还会难受。所以,还是需要自己静下心来分析原理、设计模块、编写实现以及仿真调试。对于FPGA新手来说,前三部分还能自己慢慢摸索,最后一步真的完全无措,这真的需要经验积累呀,那是你没办法搞定的,你觉得明明正确的语句可是在这里就是不行,就是不能这样来实现,只能先向大神求救,在这里真的要谢谢项目组的zjl,在他那里也学到很多FPGA的实现方法和注意事项。
其实刚学习FPGA那会儿,先看的语法知识,感觉很简单,后来用的时候发现还是需要查找翻书,所以只有能够在实践过程中熟练应用才说明真正地掌握,宝宝还差得远呢!那些简单的数电的组合逻辑模块看得很明白,也很简单,毕竟本渣大学的数电也不是白学的!可是,一涉及到项目特别是搞图像算法的,感觉就晕头转向,茫然无措。其实宝宝还是很想在图像处理这个方向好好努力呢。偶然看到http://www.heijin.org/forum.php,网站上有很多学习资料,而且很适合软件转到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,这也可以通过结果反推回去发现的。
1 `timescale 1ns / 1ps 2 ////////////////////////////////////////////////////////////////////////////////// 3 // Company: 4 // Engineer: 5 // 6 // Create Date: 09:27:48 05/18/2016 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)计数器控制模块,主要用于获得中心像素点的地址信息。
3.对各个模块进行语法检查、波形仿真、时序设计、调试验证;