基于FPGA的图像的非线性滤波:中值滤波

在图像预处理中,最基础也最重要的处理方法是图像滤波与增强。图像滤波可以很好地消除测量成像或者环境带来的随机噪声、高斯噪声和椒盐噪声等。图像增强可以增强图像细节,提高图像对比度。

滤波器的种类有很多种。按照输出和输入之间是否有唯一且确定的传递函数,我们可以把滤波器分为线性滤波器和非线性滤波器两种。

非线性滤波器在通常情况下没有特定的转移函数。一类比较重要的非线性滤波就是统计排序滤波器,如中值滤波、最大/最小值滤波等。

中值滤波对于某些类型的随机噪声具有非常理想的降噪能力,对于线性平滑滤波而言,在处理像素邻域之内的噪声点时,噪声的存在总会或多或少影响该点的像素值的计算(高斯平滑影响的程度与噪声点到中心点的距离成正比),但在中值滤波中噪声点则常常直接被忽略掉的;而且与线性平滑滤波器相比,中值滤波在降噪同时引起的模糊效应较低,进行中值滤波不仅可以去除孤点噪声,而且可以保持图像的边缘特性,不会使图像产生显著的模糊,比较适合于实验中的人脸图像。中值滤波的一种典型应用是消除椒盐噪声(即黑白噪声)。
  一、理论分析

中值滤波方法是:对待处理的当前像素,选择一个3x3、5x5 或其他模板,该模板为其邻近的若千个像素组成,对模板的像素由小到大进行排序,再用模板的中值来替代原像素的值。3x3 模板下的排序算法如图所示:
 基于FPGA的图像的非线性滤波:中值滤波_第1张图片二、MATLAB实现

clc;
clear all;
close all;

RGB = imread('flower.bmp');               %读取图片
imgn = imnoise(RGB,'salt & pepper',0.05); %椒盐密度0.05
gray = im2double(rgb2gray(imgn));         %灰度图

[ROW,COL, DIM] = size(gray);              %得到图像行列数
%--------------------------------------------------------------------------
%                        Mean Filter 均值滤波
%--------------------------------------------------------------------------
Mean_Img = zeros(ROW,COL);
for r = 2:1:ROW-1
    for c = 2:1:COL-1
        Mean_Img(r,c) = (gray(r-1, c-1) + gray(r-1, c) + gray(r-1, c+1) + gray(r, c-1) + gray(r, c) + gray(r, c+1) + gray(r+1, c-1) + gray(r+1, c) + gray(r+1, c+1)) / 9;
    end
end
%--------------------------------------------------------------------------
%                        Median Filter 中值滤波
%--------------------------------------------------------------------------
Median_Img = zeros(ROW,COL);
for r = 2:ROW-1
    for c = 2:COL-1
        median3x3 =[gray(r-1,c-1)    gray(r-1,c) gray(r-1,c+1)
                    gray(r,c-1)      gray(r,c)      gray(r,c+1)
                    gray(r+1,c-1)      gray(r+1,c) gray(r+1,c+1)];
        sort1 = sort(median3x3, 2, 'descend');
        sort2 = sort([sort1(1), sort1(4), sort1(7)], 'descend');
        sort3 = sort([sort1(2), sort1(5), sort1(8)], 'descend');
        sort4 = sort([sort1(3), sort1(6), sort1(9)], 'descend');
        mid_num = sort([sort2(3), sort3(2), sort4(1)], 'descend');
        Median_Img(r,c) = mid_num(2);
    end
end
%--------------------------------------------------------------------------
%                           Show Image
%--------------------------------------------------------------------------
subplot(2,2,1); imshow(imgn);       title('椒盐噪声');
subplot(2,2,2); imshow(gray);       title('灰度图');
subplot(2,2,3); imshow(Mean_Img);   title('均值滤波');
subplot(2,2,4); imshow(Median_Img); title('中值滤波');

% 由实验可知:
% 1、椒盐噪声就是黑白噪声,均值滤波对椒盐噪声基本无作用。
% 2、中值滤波对椒盐噪声的处理非常好。

当我们使用3x3窗口后获取领域中的9个像素,就需要对9个像素值进行排序,为了提高排序效率,排序算法思想如下所示。

(1)对窗内的每行像素按降序排序,得到最大值、中间值和最小值。
  (2)把三行的最小值即第三列相比较,取其中的最大值。
  (3)把三行的最大值即第- -列相比较,取其中的最小值。
  (4)把三行的中间值即第二列相比较,再取一次中间值。
  (5)把前面的到的三个值再做一次排序,获得的中值即该窗口的中值。

MATLAB代码中采用了 sort 排序函数,该函数使用方法如下所示:

sort(A)若A可以使矩阵或行列向量,默认都是对A进行升序排列。
sort (A)是默认的升序,而sort (A,' descend' )是降序排序。
sort(A)若A是矩阵,默认对A的各列进行升序排列
sort (A, dim)
dim=1时相当于sort (A)
dim=2时表示对矩阵A中的各行元素升序排列
sort(A,dim, ’descend' )则对矩阵的每行进行降序排列

点击运行,得到如下结果:
 结果可以看出:均值滤波对椒盐噪声无效,中值滤波则过滤了绝大部分椒盐噪声,如果还不够可以再用一次中值滤波,达到满意效果。
三、FPGA实现

1、形成3x3矩阵

这个在前面的博客花了3篇来解释,就不多说了,我把3x3矩阵的代码用一个专门的 .v 文件写好,这里直接调用即可。输入是灰度数据,即 YCbCr格式中的 8bit Y分量,输出是矩阵数据。

//==========================================================================
//==    matrix_3x3_8bit,生成3x3矩阵,输入和使能需对齐,耗费1clk
//==========================================================================
//--------------------------------------------------- 矩阵顺序
//        {matrix_11, matrix_12, matrix_13}
//        {matrix_21, matrix_22, matrix_23}
//        {matrix_31, matrix_32, matrix_33}
//--------------------------------------------------- 模块例化
matrix_3x3_8bit
#(
    .COL                    (480                    ),
    .ROW                    (272                    )
)
u_matrix_3x3_8bit
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .din_vld                (Y_de                   ),
    .din                    (Y_data                 ),
    .matrix_11              (matrix_11              ),
    .matrix_12              (matrix_12              ),
    .matrix_13              (matrix_13              ),
    .matrix_21              (matrix_21              ),
    .matrix_22              (matrix_22              ),
    .matrix_23              (matrix_23              ),
    .matrix_31              (matrix_31              ),
    .matrix_32              (matrix_32              ),
    .matrix_33              (matrix_33              )
);

2、sort排序

MATLAB有sort函数,FPGA里可没有,我们得自己写一个,由于要用到多次,因此用一个.v文件来写,用的时候调用即可。sort代码如下所示:

module sort
//========================< 端口 >==========================================
(
//system --------------------------------------------
input   wire                clk                     ,
input   wire                rst_n                   ,
//input ---------------------------------------------
input   wire    [7:0]       data1                   ,
input   wire    [7:0]       data2                   ,
input   wire    [7:0]       data3                   ,
//output --------------------------------------------
output  reg     [7:0]       max_data                , //最大值
output  reg     [7:0]       mid_data                , //中间值
output  reg     [7:0]       min_data                  //最小值
);
//==========================================================================
//==    最大值
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        max_data <= 8'd0;
    else if(data1 >= data2 && data1 >= data3)
        max_data <= data1;
    else if(data2 >= data1 && data2 >= data3)
        max_data <= data2;
    else if(data3 >= data1 && data3 >= data2)
        max_data <= data3;
end
//==========================================================================
//==    中间值
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        mid_data <= 8'd0;
    else if((data2 >= data1 && data1 >= data3) || (data3 >= data1 && data1 >= data2))
        mid_data <= data1;
    else if((data1 >= data2 && data2 >= data3) || (data3 >= data2 && data2 >= data1))
        mid_data <= data2;
    else if((data1 >= data3 && data3 >= data2) || (data1 >= data3 && data3 >= data2))
        mid_data <= data3;
end
//==========================================================================
//==    最小值
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        min_data <= 8'd0;
    else if(data3 >= data1 && data2 >= data1)
        min_data <= data1;
    else if(data3 >= data2 && data1 >= data2)
        min_data <= data2;
    else if(data1 >= data3 && data2 >= data3)
        min_data <= data3;
end



endmodule

3、调用sort,完成中值滤波

调用上面写好的 sort 就行了,注意一下整个的逻辑,消耗了3个时钟周期。

(1)对窗内的每行像素按降序排序,得到最大值、中间值和最小值。
  (2)把三行的最小值即第三列相比较,取其中的最大值。
  (3)把三行的最大值即第- -列相比较,取其中的最小值。
  (4)把三行的中间值即第二列相比较,再取一次中间值。
  (5)把前面的到的三个值再做一次排序,获得的中值即该窗口的中值。

第1个周期实现(1),第2个周期实现(2)(3)(4),第3个周期实现(5)。

//==========================================================================
//==    中值滤波,耗费3clk
//==========================================================================
//每行像素降序排列,clk1
//---------------------------------------------------
//第1行
sort u1
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (matrix_11              ), 
    .data2                  (matrix_12              ), 
    .data3                  (matrix_13              ),
    .max_data               (max_data1              ),
    .mid_data               (mid_data1              ),
    .min_data               (min_data1              )
);

//第2行
sort u2
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (matrix_21              ),
    .data2                  (matrix_22              ),
    .data3                  (matrix_23              ),
    .max_data               (max_data2              ),
    .mid_data               (mid_data2              ),
    .min_data               (min_data2              )
);

//第3行
sort u3
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (matrix_31              ),
    .data2                  (matrix_32              ),
    .data3                  (matrix_33              ),
    .max_data               (max_data3              ),
    .mid_data               (mid_data3              ),
    .min_data               (min_data3              )
);

//三行的最小值取最大值
//三行的中间值取中间值
//三行的最大值取最小值,clk2
//---------------------------------------------------
//min-max
sort u4
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (min_data1              ),
    .data2                  (min_data2              ),
    .data3                  (min_data3              ),
    .max_data               (min_max_data           ),
    .mid_data               (                       ),
    .min_data               (                       )
);

//mid-mid
sort u5
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (mid_data1              ),
    .data2                  (mid_data2              ),
    .data3                  (mid_data3              ),
    .max_data               (                       ),
    .mid_data               (mid_mid_data           ),
    .min_data               (                       )
);

//max-min
sort u6
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (max_data1              ), 
    .data2                  (max_data2              ), 
    .data3                  (max_data3              ),
    .max_data               (                       ),
    .mid_data               (                       ),
    .min_data               (max_min_data           )
);

//前面的三个值再取中间值,clk3
//---------------------------------------------------
sort u7
(
    .clk                    (clk                    ),
    .rst_n                  (rst_n                  ),
    .data1                  (max_min_data           ),
    .data2                  (mid_mid_data           ), 
    .data3                  (min_max_data           ),
    .max_data               (                       ),
    .mid_data               (median_data            ),
    .min_data               (                       )
);

4、信号同步

形成3x3矩阵耗费1clk,中值滤波耗费3clk,因此行场和使能信号都需要延迟4拍。

//==========================================================================
//==    信号同步
//==========================================================================
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        Y_de_r    <= 4'b0;
        Y_hsync_r <= 4'b0;
        Y_vsync_r <= 4'b0;
    end
    else begin  
        Y_de_r    <= {Y_de_r[2:0],    Y_de};
        Y_hsync_r <= {Y_hsync_r[2:0], Y_hsync};
        Y_vsync_r <= {Y_vsync_r[2:0], Y_vsync};
    end
end

assign median_de    = Y_de_r[3];
assign median_hsync = Y_hsync_r[3];
assign median_vsync = Y_vsync_r[3];

四、上板验证

同样取一张含有椒盐噪声的图片来看现象。

原图:
基于FPGA的图像的非线性滤波:中值滤波_第2张图片中值滤波后:
基于FPGA的图像的非线性滤波:中值滤波_第3张图片 从实验结果看出,椒盐噪声都被过滤了,实验成功。

你可能感兴趣的:(fpga,fpga开发,图像处理,计算机视觉)