您的当前位置:首页正文

FPGA丨高斯滤波算法实现

2024-11-08 来源:个人技术集锦

参考:小梅哥的《FPGA系统设计与验证实战指南》

一、算法介绍

高斯滤波是一种线性平滑滤波,适用于消除高斯噪声,广泛应用于图像处理的减噪过程。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。高斯滤波的具体操作是:用一个模板(或称卷积、掩模)扫描图像中的每一个像素,用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值。

高斯滤波后图像被平滑的程度取决于标准差。它的输出是临域像素的加权平均,同时离中心越近的像素权重越高。因此,相对于均值滤波(mean filter)它的平滑效果更柔和,而且边缘保留的也更好。

高斯滤波被用作为平滑滤波器的本质原因是因为它是一个低通滤波器,而且大部份基于卷积平滑滤波器都是低通滤波器。

GAUSS 滤波算法克服了边界效应,因而滤波后的图像较好。

高斯滤波算法实现步骤:

用模板确定的邻域内像素的加权平均灰度值去替代模板中心像素点的值:

二、程序设计

关于如何形成3*3的像素矩阵,参考另一篇文章:

module  gaussian_filter_3x3(
	 input clk, //pixel clk
	 input rst_n,
	 
	 input [15:0]data_in, //16 bit 灰度 pixel 
	 input data_in_en,
	 
	 output reg [15:0] data_out,
	 output reg data_out_en
);
//------------------------------------
// 三行像素缓存
//----------------------------------- 
wire [15:0] line0;
wire [15:0] line1;
wire [15:0] line2;
//-----------------------------------------
// 3x3 像素矩阵中的像素点
//-----------------------------------------
reg [15:0] line0_data0;
reg [15:0] line0_data1;
reg [15:0] line0_data2;
reg [15:0] line1_data0;
reg [15:0] line1_data1;
reg [15:0] line1_data2;
reg [15:0] line2_data0;
reg [15:0] line2_data1;
reg [15:0] line2_data2;

wire   mat_flag; 
reg    mat_flag_1; 
reg    mat_flag_2; 
reg    mat_flag_3; 
reg    mat_flag_4; 


always @(posedge clk)begin
        mat_flag_1          <=          mat_flag;      
        mat_flag_2          <=          mat_flag_1;      
        mat_flag_3          <=          mat_flag_2;      
        mat_flag_4          <=          mat_flag_3; 
end


//---------------------------------------------
// 获取3*3的图像矩阵
//---------------------------------------------
matrix_3x3 matrix_3x3_inst(
    .clk (clk),
    .rst_n(rst_n),
    .din (data_in),
    .valid_in(data_in_en),
    .dout(),
    .dout_r0(line0),
    .dout_r1(line1),
    .dout_r2(line2),
    .mat_flag(mat_flag)
);
//--------------------------------------------------
// Form an image matrix of three multiplied by three
//--------------------------------------------------
always @(posedge clk or negedge rst_n) begin
 if(!rst_n) begin
	 line0_data0 <= 16'b0;
	 line0_data1 <= 16'b0;
	 line0_data2 <= 16'b0;
	 
	 line1_data0 <= 16'b0;
	 line1_data1 <= 16'b0;
	 line1_data2 <= 16'b0;
	 
	 line2_data0 <= 16'b0;
	 line2_data1 <= 16'b0;
	 line2_data2 <= 16'b0;
 end
 else if(data_in_en) begin //像素有效信号
	 line0_data0 <= line0;
	 line0_data1 <= line0_data0;
	 line0_data2 <= line0_data1;
	 
	 line1_data0 <= line1;
	 line1_data1 <= line1_data0;
	 line1_data2 <= line1_data1;
	 
	 line2_data0 <= line2;
	 line2_data1 <= line2_data0;
	 line2_data2 <= line2_data1; 
 end
end

//--------------------------------------------------------------------------
// 计算最终结果
//--------------------------------------------------------------------------
always @(posedge clk or negedge rst_n) begin
 if(!rst_n)
 	data_out <= 16'b0;
 else if(data_in_en)
 	data_out <= (line0_data0 + line0_data1*2 + line0_data2 + line1_data0*2 + 
 line1_data1*4 +line1_data2*2 + line2_data0 + line2_data1*2 + line2_data2)>>4;
 else ;
end

always @(posedge clk or negedge rst_n)
    if(rst_n == 1'b0)
        data_out_en  <= 1'b0;
    else if(mat_flag_3 == 1'b1 && mat_flag_4 == 1'b1) 
        data_out_en  <= 1'b1;
    else
        data_out_en  <= 1'b0;

endmodule

三、仿真

`timescale 1ns/1ps

`define CLK_PERIOD 20//50MHZ

module tb ();
reg clk;
reg [15:0] din;
reg rst_n;
reg valid_in;
//wires
wire [15:0] data_out;
wire data_out_en;

gaussian_filter_3x3  u_gaussian_filter_3x3 (
    .clk                     ( clk                 ),
    .rst_n                   ( rst_n               ),
    .data_in                 ( din      [15:0] ),
    .data_in_en              ( valid_in          ),

    .data_out                ( data_out     [15:0] ),
    .data_out_en             ( data_out_en         )
);
initial begin
    clk = 0;
    rst_n = 0;
    valid_in = 0;
    #(`CLK_PERIOD * 10);
    rst_n=1;
    #(`CLK_PERIOD*10);
    valid_in = 1;
    #(`CLK_PERIOD*480*5);
    valid_in = 0;
    #(`CLK_PERIOD*20);
    $stop;
end

always #(`CLK_PERIOD/2) clk = ~clk;

always @ (posedge clk or negedge rst_n)begin
    if(!rst_n)
        din <= 0;
    else if(din == 479)
        din <= 0;
    else if (valid_in == 1'b1)
        din <= din + 1'b1;
end

endmodule

需要注意的是:

上述代码的输入图像数据默认是灰度图像的数据,数据位宽为16。关于如何得到灰度图,可以参考另一篇文章:

显示全文