1.均值滤波算法的理论
所有的滤波算法都是通过当前像素周边的像素,以一定的权重加权计算滤波后的结果。因此主要涉及两个变量:窗口内像素的权重值,以及窗口的大小。滤波的窗口有3x3、5x5、7x7、11x11等,窗口的尺度越大,相应的计算量越大,效果也越明显。
均值滤波可以简单的表示为在邻域窗3x3内,所有的像素权重相同,简单加权后求平均值,因此,图像中的噪声并没有被去除,只是被平均了而已。此外,均值滤波除了抑制噪声,也有平滑纹理的效果。如果窗口很大,也会产生模糊的效果。
2.均值滤波的FPGA实现
通过在图像上进行滑窗处理,可以获得以目标像素为中心的3x3窗口,从图像左上角开始,每次计算完当前像素后,再往右滑动一个像素,以新的窗口计算新的像素;当窗口滑动到行内最后一个像素并完成计算后,另起一行重新开始滑窗运算操作。
为了生成以目标像素为中心的3x3窗口,需要缓存3行像素,但在设计时只需要缓存两行像素,第三行像素实时输入即可。以FIFO方式对行像素进行缓存,并以菊花链的形式连接行缓存,即将当前行缓存的输出接到下一个行缓存的输入。
矩阵代码:
module Matrix_Generate_3x3_8Bit
#(
parameter [10:0] IMG_HDISP = 11'd640;
parameter [10:0] IMG_VDISP = 11'd480;
parameter [10:0] DELAY_NUM = 11'd10
)
(
input clk,
input rst_n,
input per_img_vsync,
input per_img_href,
input [7:0] per_img_gray,
output matrix_img_vsync,
output matrix_img_href,
output matrix_top_edge_flag,
output matrix_bottom_edge_flag,
output matrix_left_edge_flag,
output matrix_right_edge_flag,
output reg [7:0] matrix_p11;
output reg [7:0] matrix_p12;
output reg [7:0] matrix_p13;
output reg [7:0] matrix_p21;
output reg [7:0] matrix_p22;
output reg [7:0] matrix_p23;
output reg [7:0] matrix_p31;
output reg [7:0] matrix_p32;
output reg [7:0] matrix_p33;
);
reg [10:0] hcnt;
always@(posedge clk or rst_n)begin
if(!rst_n)
hcnt <= 11'b0;
else begin
if(per_img_href == 1'b1)
hcnt <= hcnt + 1'b1;
else
hcnt <= 11'b0;
end
end
reg per_img_href_dly;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
per_img_href_dly <= 1'b0;
else
per_img_href_dly <= per_img_href;
end
wire img_href_neg = ~per_img_href & per_img_href_dly;
reg [10:0] vcnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
vcnt <= 11'b0;
else begin
if(per_img_vsync == 1'b0)
vcnt <= 11'b0;
else if(img_href_neg == 1'b1)
vcnt <= vcnt + 1'b1;
else
vcnt <= vcnt;
end
end
reg [10:0] extend_last_row_cnt;
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
extend_last_row_cnt <= 11'b0;
else begin
if((per_img_href == 1'b1)&&(vcnt == IMG_VDISP - 1'b1)&&(hcnt==IMG_HDISP - 1'b1)
extend_last_row_cnt <= extend_last_row_cnt +1'b1;
else
extend_last_row_cnt <= 11'b0;
end
end
wire extend_last_row_en = (extend_last_row_cnt > DELAY_NUM)
wire fifol_wenb;
wire [7:0] fifol_wdata;
wire fifol_renb;
wire [7:0] fifol_rdata;
wire fifo2_wdata;
wire [7:0] fifo2_wdata;
wire fifo2_renb;
wire [7:0] fifo2_rdata;
assign fifol_wenb = per_img_href;
assign fifol_wdata = per_img_gray;
assign fifo1_renb = per_img_href & (vcnt > 11'b0) | extend_last_row_en;
assign fifo2_wenb = per_img_href & (vcnt > 11'b0);
assign fifo2_wdata = fifo1_rdata;
assign fifo2_renb = per_img_href & (vcnt > 11'b1) | extend_last_row_en;
sync_fifo
#(
.C_FIFO_WIDTH (8 ),
.C_FIFO_DEPTH (1024 )
)
u1_sync_fifo
(
.rst (~rst_n ),
.clk (clk ),
.wr_en (fifo1_wenb ),
.din (fifo1_wdata),
.full ( ),
.rd_en (fifo1_renb ),
.dout (fifo1_rdata),
.empty ( ),
.data_count ( )
);
sync_fifo
#(
.C_FIFO_WIDTH (8 ),
.C_FIFO_DEPTH (1024 )
)
u2_sync_fifo
(
.rst (~rst_n ),
.clk (clk ),
.wr_en (fifo2_wenb ),
.din (fifo2_wdata),
.full ( ),
.rd_en (fifo2_renb ),
.dout (fifo2_rdata),
.empty ( ),
.data_count ( )
);
// Read data from fifo
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
{matrix_p11, matrix_p12, matrix_p13} <= 24'h0;
{matrix_p21, matrix_p22, matrix_p23} <= 24'h0;
{matrix_p31, matrix_p32, matrix_p33} <= 24'h0;
end
else
begin
{matrix_p11, matrix_p12, matrix_p13} <= {matrix_p12, matrix_p13, fifo2_rdata}; // 1st row input
{matrix_p21, matrix_p22, matrix_p23} <= {matrix_p22, matrix_p23, fifo1_rdata}; // 2nd row input
{matrix_p31, matrix_p32, matrix_p33} <= {matrix_p32, matrix_p33, per_img_gray}; // 3rd row input
end
end
reg [1:0] vsync;
reg [1:0] href;
reg [1:0] top_edge_flag;
reg [1:0] bottom_edge_flag;
reg [1:0] left_edge_flag;
reg [1:0] right_edge_flag;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
vsync <= 2'b0;
else
begin
if((per_img_href == 1'b1)&&(vcnt == 11'd1)&&(hcnt == 11'b0))
vsync[0] <= 1'b1;
else if(extend_last_row_cnt == DELAY_NUM + IMG_HDISP)
vsync[0] <= 1'b0;
else
vsync[0] <= vsync[0];
vsync[1] <= vsync[0];
end
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
href <= 2'b0;
top_edge_flag <= 2'b0;
bottom_edge_flag <= 2'b0;
left_edge_flag <= 2'b0;
right_edge_flag <= 2'b0;
end
else
begin
href[0] <= per_img_href & (vcnt > 11'b0) | extend_last_row_en;
href[1] <= href[0];
top_edge_flag[0] <= per_img_href & (vcnt == 11'd1);
top_edge_flag[1] <= top_edge_flag[0];
bottom_edge_flag[0] <= extend_last_row_en;
bottom_edge_flag[1] <= bottom_edge_flag[0];
left_edge_flag[0] <= per_img_href & (vcnt > 11'b0) & (hcnt == 11'b0) | (extend_last_row_cnt == DELAY_NUM + 1'b1);
left_edge_flag[1] <= left_edge_flag[0];
right_edge_flag[0] <= per_img_href & (vcnt > 11'b0) & (hcnt == IMG_HDISP - 1'b1) | (extend_last_row_cnt == DELAY_NUM + IMG_HDISP);
right_edge_flag[1] <= right_edge_flag[0];
end
end
assign matrix_img_vsync = vsync[1];
assign matrix_img_href = href[1];
assign matrix_top_edge_flag = top_edge_flag[1];
assign matrix_bottom_edge_flag = bottom_edge_flag[1];
assign matrix_left_edge_flag = left_edge_flag[1];
assign matrix_right_edge_flag = right_edge_flag[1];
endmodule
均值算法
module mean_filter_proc
#(
parameter [10:0] IMG_HDISP = 11’d640, // 640*480
parameter [10:0] IMG_VDISP = 11’d480
)
(
input wire clk ,
input wire rst_n ,
// Image data prepared to be processed
input wire per_img_vsync , // Prepared Image data vsync valid signal
input wire per_img_href , // Prepared Image data href vaild signal
input wire [7:0] per_img_gray , // Prepared Image brightness input
// Image data has been processed
output reg post_img_vsync , // processed Image data vsync valid signal
output reg post_img_href , // processed Image data href vaild signal
output reg [7:0] post_img_gray // processed Image brightness output
);
//----------------------------------------------------------------------
// Generate 8Bit 3X3 Matrix
wire matrix_img_vsync;
wire matrix_img_href;
wire matrix_top_edge_flag;
wire matrix_bottom_edge_flag;
wire matrix_left_edge_flag;
wire matrix_right_edge_flag;
wire [7:0] matrix_p11;
wire [7:0] matrix_p12;
wire [7:0] matrix_p13;
wire [7:0] matrix_p21;
wire [7:0] matrix_p22;
wire [7:0] matrix_p23;
wire [7:0] matrix_p31;
wire [7:0] matrix_p32;
wire [7:0] matrix_p33;
Matrix_Generate_3X3_8Bit
#(
.IMG_HDISP (IMG_HDISP ),
.IMG_VDISP (IMG_VDISP )
)
u_Matrix_Generate_3X3_8Bit
(
// global clock & reset
.clk (clk ),
.rst_n (rst_n ),
// Image data prepared to be processed
.per_img_vsync (per_img_vsync ), // Prepared Image data vsync valid signal
.per_img_href (per_img_href ), // Prepared Image data href vaild signal
.per_img_gray (per_img_gray ), // Prepared Image brightness input
// Image data has been processed
.matrix_img_vsync (matrix_img_vsync ), // processed Image data vsync valid signal
.matrix_img_href (matrix_img_href ), // processed Image data href vaild signal
.matrix_top_edge_flag (matrix_top_edge_flag ), // processed Image top edge
.matrix_bottom_edge_flag(matrix_bottom_edge_flag), // processed Image bottom edge
.matrix_left_edge_flag (matrix_left_edge_flag ), // processed Image left edge
.matrix_right_edge_flag (matrix_right_edge_flag ), // processed Image right edge
.matrix_p11 (matrix_p11 ), // 3X3 Matrix output
.matrix_p12 (matrix_p12 ),
.matrix_p13 (matrix_p13 ),
.matrix_p21 (matrix_p21 ),
.matrix_p22 (matrix_p22 ),
.matrix_p23 (matrix_p23 ),
.matrix_p31 (matrix_p31 ),
.matrix_p32 (matrix_p32 ),
.matrix_p33 (matrix_p33 )
);
//----------------------------------------------------------------------
// calc sum of [p11,p12,p13;p21,p22,p23;p31,p32,p33]
reg [ 9:0] data_sum1;
reg [ 9:0] data_sum2;
reg [ 9:0] data_sum3;
reg [11:0] data_sum;
always @(posedge clk)
begin
data_sum1 <= matrix_p11 + matrix_p12 + matrix_p13;
data_sum2 <= matrix_p21 + matrix_p22 + matrix_p23;
data_sum3 <= matrix_p31 + matrix_p32 + matrix_p33;
data_sum <= data_sum1 + data_sum2 + data_sum3;
end
//----------------------------------------------------------------------
// avg_data = round(data_sum/9.0) -> avg_data = round(data_sum*3641 >> 15)
reg [22:0] data_mult;
always @(posedge clk)
begin
data_mult <= data_sum * 12’d3641;
end
reg [7:0] avg_data;
always @(posedge clk)
begin
avg_data <= data_mult[22:15] + data_mult[14];
end
//----------------------------------------------------------------------
// lag 4 clocks signal sync
reg [3:0] matrix_img_vsync_r1;
reg [3:0] matrix_img_href_r1;
reg [3:0] matrix_edge_flag_r1;
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
matrix_img_vsync_r1 <= 4’b0;
matrix_img_href_r1 <= 4’b0;
matrix_edge_flag_r1 <= 4’b0;
end
else
begin
matrix_img_vsync_r1 <= {matrix_img_vsync_r1[2:0],matrix_img_vsync};
matrix_img_href_r1 <= {matrix_img_href_r1[2:0],matrix_img_href};
matrix_edge_flag_r1 <= {matrix_edge_flag_r1[2:0],matrix_top_edge_flag | matrix_bottom_edge_flag | matrix_left_edge_flag | matrix_right_edge_flag};
end
end
reg [7:0] matrix_p22_r1 [0:3];
always @(posedge clk)
begin
matrix_p22_r1[0] <= matrix_p22;
matrix_p22_r1[1] <= matrix_p22_r1[0];
matrix_p22_r1[2] <= matrix_p22_r1[1];
matrix_p22_r1[3] <= matrix_p22_r1[2];
end
//----------------------------------------------------------------------
// result output
always @(posedge clk)
begin
if(matrix_edge_flag_r1[3] == 1’b1)
post_img_gray <= matrix_p22_r1[3];
else
post_img_gray <= avg_data;
end
always @(posedge clk or negedge rst_n)
begin
if(!rst_n)
begin
post_img_vsync <= 1’b0;
post_img_href <= 1’b0;
end
else
begin
post_img_vsync <= matrix_img_vsync_r1[3];
post_img_href <= matrix_img_href_r1[3];
end
end
endmodule
3.参考资料
1.基于MATLAB与FPGA的图像处理教程 (韩彬)