0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

FPGA verilog實(shí)現(xiàn)中值濾波

FPGA學(xué)習(xí)交流 ? 2018-10-12 14:58 ? 次閱讀

一、實(shí)現(xiàn)步驟:

1.查看了中值濾波實(shí)現(xiàn)相關(guān)的網(wǎng)站和paper;

2.按照某篇paper的設(shè)計(jì)思想進(jìn)行編程實(shí)現(xiàn);

3.對各個模塊進(jìn)行語法檢查、波形仿真、時(shí)序設(shè)計(jì)、調(diào)試驗(yàn)證;

4.與matlab的中值濾波結(jié)果進(jìn)行比較。


二、實(shí)現(xiàn)過程:

1.查看了中值濾波實(shí)現(xiàn)相關(guān)的網(wǎng)站和paper;

在網(wǎng)上看了很多中值濾波的設(shè)計(jì),也有一些代碼可以下載,也有一片講解的,只是感覺講解的比較模糊而且不完整,最后看了幾篇碩士論文,論文竟然主要做了中值濾波的工作,發(fā)現(xiàn)了一些設(shè)計(jì)思路,然后就按照自己的想法進(jìn)行設(shè)計(jì)。

2.按照某篇paper的設(shè)計(jì)思想進(jìn)行編程實(shí)現(xiàn);

整個中值濾波模塊分為幾個小的模塊:3*3窗口生成模塊、計(jì)數(shù)器控制模塊、3*3中值濾波模塊、頂層模塊以及最后的測試模塊testbench的編寫。

整個框架的設(shè)計(jì)如下圖所示(使用visio畫的框架圖):

102651pyyca2z2yy732ycp.png


各個模塊的設(shè)計(jì):

1)ROM IP核的生成,用于存儲原始灰度圖像的數(shù)據(jù)。
使用matlab生成.coe圖像數(shù)據(jù)文件,然后使用Xilinx ISE工具將.coe文件添加到ROM核進(jìn)行數(shù)據(jù)初始化,按步驟得到ROM模塊,參考生成的.v文件在頂層模塊直接調(diào)用即可。

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


注意ROM的存儲空間的大?。?br />
2)3*3窗口生成模塊,用于生成濾波的滑動窗口,得到窗口內(nèi)的所有元素?cái)?shù)據(jù)。

功能:

(1)根據(jù)中心像素點(diǎn)得到所在其所在的行、列位置;

(2)根據(jù)該模塊的開始信號設(shè)計(jì)得到獲取數(shù)據(jù)的有效時(shí)間序列;

(3)在讀取數(shù)據(jù)的有效時(shí)序內(nèi),得到窗口內(nèi)的所有元素?cái)?shù)據(jù);

(4)窗口數(shù)據(jù)的獲取按照一定的時(shí)序順序來獲得,類似于黑金推薦的“仿順序操作”,這個比較適合my style;不過后來發(fā)現(xiàn)調(diào)試的過程中被項(xiàng)目組的硬件人員改動了一些,甚至說不好,感覺可能是本人還沒有理解掌握吃透“仿順序操作”的精髓吧。

(5)根據(jù)中心像素點(diǎn)的行、列位置信息得到每個窗口元素的ROM地址,根據(jù)某一時(shí)刻ROM地址,下一時(shí)刻調(diào)用ROM模塊得到對應(yīng)的元素?cái)?shù)據(jù),下一時(shí)刻將數(shù)據(jù)鎖存,然后再讀取該地址的數(shù)據(jù);所以要注意地址和數(shù)據(jù)的獲取不是在同一時(shí)刻,而是需要延遲兩個時(shí)刻;

(6)還需要注意的是圖像的邊界問題的特殊化處理;一般圖像處理都會遇到邊界問題,這個需要謹(jǐn)慎;

(7)對matlab的中值濾波函數(shù)medfilt2原理的深入掌握對我們編寫這一模塊非常重要。matlab并沒有主要過程的代碼,看注釋默認(rèn)情況下邊界元素設(shè)置為0,這也可以通過結(jié)果反推回去發(fā)現(xiàn)的。

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)計(jì)數(shù)器控制模塊,主要用于獲得中心像素點(diǎn)的地址信息。

(1)系統(tǒng)模塊開始信號之后開始獲取第一個中心像素點(diǎn),注意初始化信號值和系統(tǒng)開始的信號值的區(qū)別;

(2)該時(shí)刻得到的的數(shù)據(jù)將在下一個時(shí)刻產(chǎn)生結(jié)果,該時(shí)刻的數(shù)據(jù)并沒有改變;

(3)注意中心像素點(diǎn)的行、列位置信息的計(jì)算;

`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中值濾波模塊

功能:得到某一中心像素點(diǎn)的3*3滑窗區(qū)域的灰度值的中值,作為中心像素點(diǎn)的值;

中值濾波原理,網(wǎng)上有很多,大家可以查看一下。

本項(xiàng)目采用的是快速中值濾波的方法。

(1)若是3*3窗口生成模塊完成之后就計(jì)算下一個中心像素點(diǎn),需要將該中心像素點(diǎn)的窗口元素鎖存起來,以防計(jì)算過程中將這些元素掩蓋,不能正確進(jìn)行中值濾波的計(jì)算;

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)需要在時(shí)序的有效區(qū)域內(nèi)進(jìn)行計(jì)算,怎么設(shè)計(jì)信號的有效性;

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)仿順序操作可以分開進(jìn)行;每一個時(shí)刻只進(jìn)行一個操作,這樣可能更明了(代碼中沒有這樣做);

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編程調(diào)用函數(shù)的方法,指出輸入信號,函數(shù)內(nèi)可以使用其他定義聲明的信號,最后的輸出信號作為調(diào)用函數(shù)的結(jié)果(突然想起來,如果輸出信號有多個元素呢,又該怎么辦呢?大家可以想想);

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)頂層模塊,用于將低層的各個功能/控制模塊銜接起來,得到結(jié)果;

注意輸入輸出信號,以及不同模塊之間是如何進(jìn)行連線的。

信號的名稱盡量有其特別的意義,不要重復(fù)使用同一個信號名稱,容易造成混亂;

區(qū)別wire和reg類型數(shù)據(jù)的使用情況;

`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)測試模塊

如何將數(shù)據(jù)寫入文件,需要定義文件的名稱和類型;

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("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

整體的代碼就是這樣的。

3.對各個模塊進(jìn)行語法檢查、波形仿真、時(shí)序設(shè)計(jì)、調(diào)試驗(yàn)證;

本人覺得原理清楚之后按部就班的編寫代碼還好,只是剛接觸波形仿真和調(diào)試的時(shí)候是真心不順心,還好有同事幫忙調(diào)試;在調(diào)試的過程中其實(shí)會學(xué)習(xí)到很多東西,很多經(jīng)驗(yàn),以及很簡單的但你之前就是不知道的知識,這就是一個實(shí)踐的過程,有時(shí)候你根本不知道錯誤在哪里,這怎么會是錯誤的呢,為什么不可以這樣寫,我覺得這樣寫才是正確的,這些就是在調(diào)試過程中本人的真實(shí)心情寫照呀。可是,沒有那么多為什么,verilog就是這樣編程的,只是你不知道而已!這才是最傷人的,因?yàn)槟悴恢溃?br />
仿真調(diào)試的過程中遇到的問題以及解決方法有空專門寫一篇,調(diào)試的過程中最好是一個一個模塊的測試,特別是關(guān)鍵信號的數(shù)值,最好搞懂整體模塊和各個模塊的時(shí)序設(shè)計(jì)過程,推薦使用TimeDesigner進(jìn)行波形的設(shè)計(jì);另外還需要有關(guān)聯(lián)的兩個甚至多個不同模塊信號的交叉仿真驗(yàn)證。

4.與matlab的中值濾波結(jié)果進(jìn)行比較

使用matlab編程基于自帶的中值濾波函數(shù)得到處理之后的圖像與數(shù)據(jù),并將verilog得到的濾波數(shù)據(jù)轉(zhuǎn)換為圖像,將二者進(jìn)行比較。

使用matlab自帶的中值濾波函數(shù)medfilt2生成原圖像的灰度圖像的濾波數(shù)據(jù);

% 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; %%數(shù)據(jù)的長度,即存儲器深度。
word_len = 8; %%每個單元的占據(jù)的位數(shù),需自己設(shè)定
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表示十六進(jìn)制數(shù)
end
fprintf(fid_gray, '%d;\n', data(N)); %%輸出結(jié)尾,每個數(shù)據(jù)后面用逗號或者空格或者換行符隔開,最后一個數(shù)據(jù)后面加分號
fclose(fid_gray); %%關(guān)閉文件

for i = 1 : N-1
fprintf(fid_medfilt, '%d,\n', lena_medfilt(i));%使用%x表示十六進(jìn)制數(shù)
end
fprintf(fid_medfilt, '%d;\n', lena_medfilt(N)); %%輸出結(jié)尾,每個數(shù)據(jù)后面用逗號或者空格或者換行符隔開,最后一個數(shù)據(jù)后面加分號
fclose(fid_medfilt); %%關(guān)閉文件

將medfilt2函數(shù)和verilog產(chǎn)生的濾波數(shù)據(jù)轉(zhuǎn)換為圖像,并與matlab直接產(chǎn)生的濾波圖像進(jìn)行對比,代碼如下:

% 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 產(chǎn)生的中值濾波之后數(shù)據(jù)

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');

顯示的結(jié)果如下圖所示:


結(jié)果:兩種濾波產(chǎn)生的圖像數(shù)據(jù)完全一致,不過感覺函數(shù)直接產(chǎn)生的圖像顏色更深一些,不知道為什么。

這里需要了解一下medfilt2這個函數(shù)的原理。結(jié)果數(shù)據(jù)表明,默認(rèn)情況下該函數(shù)對圖像邊界采用的是補(bǔ)0的方法進(jìn)行處理的。

結(jié)論

中值濾波終于告一段落了!簡單的問題還是需要深入進(jìn)去研究的,實(shí)踐的過程中你才會發(fā)現(xiàn)自己之前了解的東西是多么的淺薄,對已知的知識掌握的是多么的流于表面!

最后結(jié)果的數(shù)據(jù)還是很讓人開心的!

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • FPGA
    +關(guān)注

    關(guān)注

    1625

    文章

    21636

    瀏覽量

    601308
收藏 人收藏

    評論

    相關(guān)推薦

    Verilog vhdl fpga

    相關(guān)專業(yè),具有良好的專業(yè)基礎(chǔ)知識。 感興趣可滴滴 JYHXDX534 2.工作年限不限,有工作經(jīng)驗(yàn)或優(yōu)秀應(yīng)屆畢業(yè)生亦可。 3.對FPGA芯片架構(gòu)和資源有深入的理解,精通Verilog HDL、VHDL
    發(fā)表于 11-12 16:40

    基于FPGA實(shí)現(xiàn)FIR數(shù)字濾波

    。隨著現(xiàn)代數(shù)字通信系統(tǒng)對于高精度、高處理速度的需求,越來越多的研究轉(zhuǎn)向采用FPGA實(shí)現(xiàn)FIR濾波器。而對于FIR濾波器要充分考慮其資源與運(yùn)行速度的合理優(yōu)化,各種不同的FIR
    的頭像 發(fā)表于 11-05 16:26 ?167次閱讀
    基于<b class='flag-5'>FPGA</b><b class='flag-5'>實(shí)現(xiàn)</b>FIR數(shù)字<b class='flag-5'>濾波</b>器

    FPGA Verilog HDL有什么奇技巧?

    一開始就確定為某個值。ASIC 通常是通過上電復(fù)位來實(shí)現(xiàn)賦初值的。 在 FPGA 設(shè)計(jì)中,雖然可以在聲明 reg 變量時(shí)對其賦初值,或者通過復(fù)位來賦初值,但最好還是采用復(fù)位賦初值的方式。如果只靠聲明
    發(fā)表于 09-12 19:10

    如何用FPGA實(shí)現(xiàn)一個通信系統(tǒng)的發(fā)射端接收機(jī)?

    是學(xué)習(xí)規(guī)劃: 對于零基礎(chǔ)但略懂 Verilog 語法和通信原理的人,以下是一個規(guī)劃的學(xué)習(xí)路線來用 FPGA 實(shí)現(xiàn)一個 5GHz 頻段、通信距離約 10km 的通信系統(tǒng)的發(fā)射端和接收機(jī): 深入學(xué)習(xí)數(shù)字通信
    發(fā)表于 09-10 19:15

    【招聘】verilog vhdl FPGA

    1.熟悉FPGA架構(gòu)及應(yīng)用,熟悉圖像算法的FPGA實(shí)現(xiàn)。 2.熟悉verilog vhdl,熟悉Xilinx或Intel等開發(fā)工具。 3.有AI算法
    發(fā)表于 09-02 15:50

    中值濾波窗口大小對結(jié)果影響有哪些

    中值濾波是一種常用的數(shù)字濾波技術(shù),它通過將信號中的每個點(diǎn)用其鄰域內(nèi)的中值替換來實(shí)現(xiàn)信號的平滑和去噪。中值
    的頭像 發(fā)表于 07-29 09:10 ?672次閱讀

    基于matlab FPGA verilog的FIR濾波器設(shè)計(jì)

    今天和大俠簡單聊一聊基于matlab FPGA verilog的FIR濾波器設(shè)計(jì),話不多說,上貨。 本次設(shè)計(jì)實(shí)現(xiàn)8階濾波器,9個系數(shù)
    發(fā)表于 07-04 20:11

    FPGA verilog HDL實(shí)現(xiàn)中值濾波

    今天給大俠簡單帶來FPGA verilog HDL實(shí)現(xiàn)中值濾波,話不多說,上貨。一、實(shí)現(xiàn)步驟:
    發(fā)表于 06-18 18:50

    matlab與FPGA數(shù)字信號處理系列 Verilog 實(shí)現(xiàn)并行 FIR 濾波

    FPGA 實(shí)現(xiàn) FIR 濾波器時(shí),最常用的是直接型結(jié)構(gòu),簡單方便,在實(shí)現(xiàn)直接型結(jié)構(gòu)時(shí),可以選擇串行結(jié)構(gòu)/并行結(jié)構(gòu)/分布式結(jié)構(gòu)。 并行結(jié)構(gòu)即并行實(shí)
    發(fā)表于 05-24 07:48

    FPGA設(shè)計(jì)中 Verilog HDL實(shí)現(xiàn)基本的圖像濾波處理仿真

    今天給大俠帶來FPGA設(shè)計(jì)中用Verilog HDL實(shí)現(xiàn)基本的圖像濾波處理仿真,話不多說,上貨。 1、用matlab代碼,準(zhǔn)備好把圖片轉(zhuǎn)化成Vivado Simulator識別的
    發(fā)表于 05-20 16:44

    哪有FPGAverilog編程基礎(chǔ)知識?

    沒接觸過FPGA開發(fā),那個verilog編程有什么入門基礎(chǔ)知識學(xué)習(xí)的?
    發(fā)表于 04-29 23:09

    fpga是用c語言還是verilog

    FPGA(現(xiàn)場可編程邏輯門陣列)開發(fā)主要使用的編程語言是硬件描述語言(HDL),其中Verilog是最常用的編程語言之一。而C語言通常用于傳統(tǒng)的軟件編程,與FPGA的硬件編程有所區(qū)別。
    的頭像 發(fā)表于 03-27 14:38 ?1718次閱讀

    中值濾波去除噪聲的原理

    中值濾波去除噪聲的原理? 中值濾波是一種數(shù)字圖像處理中常用的去噪方法,其原理是通過將每個像素周圍鄰域內(nèi)的像素值按照大小排序,然后將排序后的中間值作為該像素的新值。
    的頭像 發(fā)表于 03-14 16:54 ?1649次閱讀

    FPGA實(shí)現(xiàn)原理

    控制這些開關(guān),從而定義FPGA內(nèi)部的信號路徑。 FPGA的工作原理主要涉及以下步驟: 設(shè)計(jì)描述 :首先,用戶需要使用硬件描述語言(如VHDL或Verilog)來描述他們想要實(shí)現(xiàn)的數(shù)字系
    發(fā)表于 01-26 10:03

    中值濾波的原理和C代碼

    中值濾波是一種非線性數(shù)字濾波技術(shù),主要應(yīng)用于信號處理和圖像處理領(lǐng)域,用于減小信號中的噪聲和離群值。中值濾波的核心思想是通過計(jì)算一組數(shù)據(jù)點(diǎn)的中
    的頭像 發(fā)表于 12-05 08:00 ?1459次閱讀
    <b class='flag-5'>中值</b><b class='flag-5'>濾波</b>的原理和C代碼