zoukankan      html  css  js  c++  java
  • FPGA实现图像的非线性滤波:中值滤波

      在图像预处理中,最基础也最重要的处理方法是图像滤波与增强。图像滤波可以很好地消除测量成像或者环境带来的随机噪声、高斯噪声和椒盐噪声等。图像增强可以增强图像细节,提高图像对比度。
      滤波器的种类有很多种。按照输出和输入之间是否有唯一且确定的传递函数,我们可以把滤波器分为线性滤波器和非线性滤波器两种。

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

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

    一、理论分析

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

    二、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代码如下所示:

     1 module sort
     2 //========================< 端口 >==========================================
     3 (
     4 //system --------------------------------------------
     5 input   wire                clk                     ,
     6 input   wire                rst_n                   ,
     7 //input ---------------------------------------------
     8 input   wire    [7:0]       data1                   ,
     9 input   wire    [7:0]       data2                   ,
    10 input   wire    [7:0]       data3                   ,
    11 //output --------------------------------------------
    12 output  reg     [7:0]       max_data                , //最大值
    13 output  reg     [7:0]       mid_data                , //中间值
    14 output  reg     [7:0]       min_data                  //最小值
    15 );
    16 //==========================================================================
    17 //==    最大值
    18 //==========================================================================
    19 always @(posedge clk or negedge rst_n) begin
    20     if(!rst_n)
    21         max_data <= 8'd0;
    22     else if(data1 >= data2 && data1 >= data3) 
    23         max_data <= data1;
    24     else if(data2 >= data1 && data2 >= data3)
    25         max_data <= data2;
    26     else if(data3 >= data1 && data3 >= data2)
    27         max_data <= data3;
    28 end
    29 //==========================================================================
    30 //==    中间值
    31 //==========================================================================
    32 always @(posedge clk or negedge rst_n) begin
    33     if(!rst_n)
    34         mid_data <= 8'd0;
    35     else if((data2 >= data1 && data1 >= data3) || (data3 >= data1 && data1 >= data2))
    36         mid_data <= data1;
    37     else if((data1 >= data2 && data2 >= data3) || (data3 >= data2 && data2 >= data1))
    38         mid_data <= data2;
    39     else if((data1 >= data3 && data3 >= data2) || (data1 >= data3 && data3 >= data2))
    40         mid_data <= data3;
    41 end
    42 //==========================================================================
    43 //==    最小值
    44 //==========================================================================
    45 always @(posedge clk or negedge rst_n) begin
    46     if(!rst_n)
    47         min_data <= 8'd0;
    48     else if(data3 >= data2 && data2 >= data1)
    49         min_data <= data1;
    50     else if(data3 >= data1 && data1 >= data2)
    51         min_data <= data2;
    52     else if(data1 >= data2 && data2 >= data3)
    53         min_data <= data3;
    54 end
    55 
    56 
    57 
    58 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];

    四、上板验证

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

      原图:

      中值滤波后:

      从实验结果看出,椒盐噪声都被过滤了,实验成功。

      我的板子坏了,出现一些不该有的横条,如果是好的板子则没有这些鬼东西。

    参考资料:

    [1] OpenS Lee:FPGA开源工作室(公众号)

    [2] CrazyBingo:基于VIP_Board Mini的FPGA视频图像算法(HDL-VIP)开发教程-V1.6 

    [3] NingHechuan:FPGA图像处理教程

  • 相关阅读:
    日期 根据所选日期 获取 之后N天的日期
    错误退出登录
    挂载路由导航守卫 router
    缓存 ssessionStorage&localStorage
    vue项目 第三方图标库阿里图库
    码云新建仓库 以及本地上传
    sql的四种连接-左外连接、右外连接、内连接、全连接
    C#中常用修饰符
    接口的隐式和显式实现
    C#break、continue、return、goto
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/12551388.html
Copyright © 2011-2022 走看看