FPGA图像处理之均值滤波

1.均值滤波算法的理论

所有的滤波算法都是通过当前像素周边的像素,以一定的权重加权计算滤波后的结果。因此主要涉及两个变量:窗口内像素的权重值,以及窗口的大小。滤波的窗口有3x3、5x5、7x7、11x11等,窗口的尺度越大,相应的计算量越大,效果也越明显。
均值滤波可以简单的表示为在邻域窗3x3内,所有的像素权重相同,简单加权后求平均值,因此,图像中的噪声并没有被去除,只是被平均了而已。此外,均值滤波除了抑制噪声,也有平滑纹理的效果。如果窗口很大,也会产生模糊的效果。

2.均值滤波的FPGA实现

通过在图像上进行滑窗处理,可以获得以目标像素为中心的3x3窗口,从图像左上角开始,每次计算完当前像素后,再往右滑动一个像素,以新的窗口计算新的像素;当窗口滑动到行内最后一个像素并完成计算后,另起一行重新开始滑窗运算操作。
为了生成以目标像素为中心的3x3窗口,需要缓存3行像素,但在设计时只需要缓存两行像素,第三行像素实时输入即可。以FIFO方式对行像素进行缓存,并以菊花链的形式连接行缓存,即将当前行缓存的输出接到下一个行缓存的输入。
3x3窗口生成的模块

矩阵代码:

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的图像处理教程 (韩彬)

基于FPGA的中值滤波算法的设计与实现 摘 要 在图像的采集、传输和记录等过程中,由于受到多方面因素的影响,图像信号会不可避免地受到椒盐噪声的污染,这将会严重影响图像的后期分析和识别等处理,因此有必要用中值滤波器对图像的椒盐噪声进行滤波预处理。 实际应用中,对滤波器件不仅要求能够将图像中的椒盐噪声滤除,满足图像处理的实时性要求,而且还要求能够很好地保护图像细节,避免滤波图像变得模糊。针对传统的快速中值滤波算法在滤除图像椒盐噪声时存在图像细节模糊的缺陷,本文提出了一种基于FPGA的改进的快速中值滤波算法。该算法在中值滤波过程中,首先根据设定的阈值判断滤波窗口的中心像素点的是否为噪声点,若是噪声点,就利用快速中值滤波算法求出中值并替换中心点的原像素值,若不是噪声点,就不进行中值滤波处理。利用MATLAB软件对该算法进行仿真的结果表明,该算法具有良好的去噪和图像细节保持的能力。 在该算法FPGA实现过程中,充分利用FPGA硬件的并行性,并且采用流水线技术,提高了图像滤波的处理速度。FPGA硬件实现的结果表明,该算法与传统的快速滤波算法相比,不仅能够满足图像处理的实时性要求,而且还能在滤除图像椒盐噪声的同时,避免滤波图像变得模糊的缺陷,达到了保护原始图像细节的目的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值