fpga图像处理之均值滤波

均值滤波的原理是使用一个3x3的卷积核,从左到右依次划窗,每划过9个数据对9个数据求一次均值,原9个数据使用这一个均值代替。由于是3x3卷积,所以一个1280x720的图像经过卷积核后,会缩减到1278x718,需要对均值滤波的图像进行填充,将其恢复原来的size.

 在fpga中实现均值滤波至关重要的一点是构建出一个3x3的矩阵,这里需要用到两个fifo

理解上述的思维很重要,上一行-当前行-下一行   ,本人自己抽象了下,如下图所示,这样理解就好了。当第三行数据全部到来时,3x3矩阵会构建如图二所示,1、2、3会按照上一行-当前行-下一行的方式呈现,因为当第三行的第一个数据到来时,第一个数据会直接输出用于矩阵构建,同时也会存入fifo1,由于存进去了一个数,所以fifo1需要同步读出一个数,也就是第2行数据的第一列数据,同时读出的这个数据也需要同时用于构建3x3矩阵和存入fifo0,同理fifo0也需要同步读出一个数据,但是这个数据后续无须再存,当第三行数据完全存入fifo1时,3x3矩阵就构建完成。此时右图二的数据应当为1、2、3。此时fifo0和fifo1中的数据应当为2、3行数据。此时的划窗也整好划过一整行。当第4行数据到来时就完成划窗选择123行到选中234行。

 

module Median_filtering #(
    parameter WEIGHT  = 1280 ,
    parameter HEIGHT  = 720  
)(
    input  wire         sclk          ,
    input  wire         reset         ,
    input  wire         valid_i       ,
    input  wire  [23:0] data_i        ,
    output wire         valid_o       ,
    output wire  [23:0] data_o
);
 
parameter C_0  = 114 ;//  1/9*1024


reg      [9:0]      row_cnt          ;
reg      [10:0]     col_cnt          ;

reg                 wr_en_0          ;
reg      [23:0]     wr_data_0        ;
reg                 rd_en_0          ;
wire      [23:0]    rd_data_0        ;

reg                 wr_en_1          ;
reg      [23:0]     wr_data_1        ;
reg                 rd_en_1          ;
wire      [23:0]    rd_data_1        ;

//3x3矩阵
reg      [23:0]     conv0_0          ;
reg      [23:0]     conv0_1          ;
reg      [23:0]     conv0_2          ;
reg      [23:0]     conv1_0          ;
reg      [23:0]     conv1_1          ;
reg      [23:0]     conv1_2          ;
reg      [23:0]     conv2_0          ;
reg      [23:0]     conv2_1          ;
reg      [23:0]     conv2_2          ;

//求和信号
reg      [9:0]     mid_conv0        ;
reg      [9:0]     mid_conv1        ;
reg      [9:0]     mid_conv2        ;
reg      [11:0]     sum_conv         ;
//求均值信号
reg      [18:0]     mean_conv        ;

//计算打拍信号
reg                 reg_flag         ;
reg                 sum_flag_0       ;
reg                 sum_flag_1       ;
reg                 sum_flag_2       ;
reg                 mean_flag        ;

reg      [23:0]     reg_flag_data     ;
// reg      [23:0]     sum_flag_0_data     ;
// reg      [23:0]     sum_flag_1_data     ;
// reg      [23:0]     sum_flag_2_data     ;
// reg      [23:0]     mean_flag_data     ;


wire                full             ;
wire                empty;
wire                wr_rst_busy      ;
wire                rd_rst_busy      ;

wire     [23:0]     reg_data_i       ;
wire                reg_valid_i      ;

reg     [23:0]     reg_data_i_1       ;
reg                reg_valid_i_1      ;

reg     [23:0]     reg_data_i_2       ;
reg                reg_valid_i_2      ;

reg     [23:0]     reg_data_i_3       ;
reg                reg_valid_i_3      ;


wire                last_valid_o     ;
wire     [23:0]     last_data_o      ;

reg      [19:0]     last_cnt         ;

image_rgb2gray u_image_rgb2gray (
    .clk                     ( sclk               ),
    .reset                   ( reset              ),
    .valid_i                 ( valid_i            ),
    .img_data_i              ( data_i             ),
    .valid_o                 ( reg_valid_i        ),
    .img_data_o              ( reg_data_i         )
);

//列计数器
always @(posedge sclk or posedge reset) begin
    if(reset==1'b1)
       col_cnt  <=   'd0             ;
    else if(reg_valid_i==1'b1&&col_cnt==WEIGHT-1)
       col_cnt  <=   'd0             ;
    else if(reg_valid_i==1'b1)
       col_cnt  <=  col_cnt+1'b1     ;
end

//行计数器
always @(posedge sclk or posedge reset) begin
    if(reset==1'b1)
      row_cnt  <=   'd0              ;
    else if(reg_valid_i==1'b1&&row_cnt==HEIGHT-1&&col_cnt==WEIGHT-1)
      row_cnt  <=   'd0              ;
    else if(reg_valid_i==1'b1&&col_cnt==WEIGHT-1)
      row_cnt  <=   row_cnt +1'b1    ;   
end

//读使能信号打拍
always @(*) begin
    if(reset==1'b1)begin 
       wr_en_0  <= 0    ;
       wr_en_1  <= 0    ;
    end
    else if(row_cnt==0&&reg_valid_i==1'b1)begin
       wr_en_0  <= 1    ;
       wr_en_1  <= 0    ;
    end
    else if(row_cnt>0&&reg_valid_i==1'b1)begin
       wr_en_0  <= 1    ;
       wr_en_1  <= 1    ;
    end   
    else begin
       wr_en_0  <= 0    ;
       wr_en_1  <= 0    ;
    end
end

//写使能信号打拍
always @(*) begin
    if(reset==1'b1)begin
       wr_data_0   <=  'd0         ;
       wr_data_1   <=  'd0         ;
    end
    else if(row_cnt==0&&reg_valid_i==1'b1)begin
       wr_data_0   <=  reg_data_i  ;
       wr_data_1   <=  'd0         ;
    end    
    else if(row_cnt>0&&reg_valid_i==1'b1)begin
       wr_data_0   <=  reg_data_i  ;
       wr_data_1   <=  rd_data_0   ;
    end
    else if(row_cnt==HEIGHT-1&&reg_valid_i==1'b1)begin
       wr_data_0   <=  'd0         ;
       wr_data_1   <=  'd0         ;
    end
end

//读使能信号打拍
always @(*) begin
    if(reset==1'b1)begin 
       rd_en_0  <= 0    ;
       rd_en_1  <= 0    ;
    end
    else if(row_cnt==1&&reg_valid_i==1'b1)begin
       rd_en_0  <= 1    ;
       rd_en_1  <= 0    ;
    end  
    else if(row_cnt>=2&&reg_valid_i==1'b1)begin
       rd_en_0  <= 1    ;
       rd_en_1  <= 1    ;
    end 
    else begin
       rd_en_0  <= 0    ;
       rd_en_1  <= 0    ;
    end
end

//3x3矩阵构建完成标志信号
always@(posedge sclk or posedge reset)
    if(reset==1'b1)
       sum_flag_0<=0;
    else if(row_cnt>=2&&reg_valid_i==1'b1&&col_cnt>=2)
       sum_flag_0<=1;
    else
       sum_flag_0<=0;

//信号打拍,构建3x3矩阵    
always @(posedge sclk or posedge reset) begin
    if(reset==1'b1)begin
       conv0_0   <=  'd0           ;
       conv0_1   <=  'd0           ;
       conv0_2   <=  'd0           ;
       conv1_0   <=  'd0           ;
       conv1_1   <=  'd0           ;
       conv1_2   <=  'd0           ;
       conv2_0   <=  'd0           ;
       conv2_1   <=  'd0           ;
       conv2_2   <=  'd0           ;
       reg_flag  <=  'd0           ;
       reg_flag_data<='d0          ;
    end
    else if(reg_valid_i)begin
       conv0_0   <=  reg_data_i    ;
       conv0_1   <=  conv0_0       ;
       conv0_2   <=  conv0_1       ;
       conv1_0   <=  rd_data_0     ;
       conv1_1   <=  conv1_0       ;
       conv1_2   <=  conv1_1       ;
       conv2_0   <=  rd_data_1     ;
       conv2_1   <=  conv2_0       ;
       conv2_2   <=  conv2_1       ;
       reg_flag  <=  reg_valid_i   ;
       reg_flag_data<=reg_data_i   ;
    end
    else begin
       conv0_0   <=  conv0_0       ;    
       conv0_1   <=  conv0_1       ;
       conv0_2   <=  conv0_2       ;
       conv1_0   <=  conv1_0       ;
       conv1_1   <=  conv1_1       ;
       conv1_2   <=  conv1_2       ;
       conv2_0   <=  conv2_0       ;
       conv2_1   <=  conv2_1       ;
       conv2_2   <=  conv2_2       ;
       reg_flag  <=  0             ;
       reg_flag_data<=reg_flag_data;
    end
end

//原始信号打拍,后面用于填零
always@(posedge sclk or posedge reset) begin
    if(reset)begin
      reg_valid_i_1<=1'b0;
      reg_valid_i_2<=1'b0;
      reg_valid_i_3<=1'b0;
      reg_data_i_1 <='d0;
      reg_data_i_2 <='d0;
      reg_data_i_3 <='d0;
    end
    else if(reg_flag)begin
      reg_valid_i_1<=1'b1;
      reg_valid_i_2<=reg_valid_i_1;
      reg_valid_i_3<=reg_valid_i_2;
      reg_data_i_1 <=reg_flag_data;
      reg_data_i_2 <=reg_data_i_1;
      reg_data_i_3 <=reg_data_i_2;
    end
    else begin
      reg_valid_i_1<=1'b0;
      reg_valid_i_2<=reg_valid_i_1;
      reg_valid_i_3<=reg_valid_i_2;
      reg_data_i_1 <=reg_data_i_1;
      reg_data_i_2 <=reg_data_i_1;
      reg_data_i_3 <=reg_data_i_2;  
    end   
end


always @(posedge sclk or posedge reset) begin
      if(reset==1'b1)begin
        mid_conv0  <=    'd0                     ;
        mid_conv1  <=    'd0                     ;
        mid_conv2  <=    'd0                     ;
        sum_flag_1 <=    1'b0                    ;
      end
      else if(sum_flag_0)begin
        mid_conv0  <=  conv0_0[7:0]+conv0_1[7:0]+conv0_2[7:0]   ;
        mid_conv1  <=  conv1_0[7:0]+conv1_1[7:0]+conv1_2[7:0]   ;
        mid_conv2  <=  conv2_0[7:0]+conv2_1[7:0]+conv2_2[7:0]   ;
        sum_flag_1 <=  1'b1                      ;
      end
      else begin
        mid_conv0  <=  mid_conv0                 ;
        mid_conv1  <=  mid_conv1                 ;
        mid_conv2  <=  mid_conv2                 ;
        sum_flag_1 <=  1'b0                      ;
      end
end

always @(posedge sclk or posedge reset) begin
     if(reset==1'b1)begin
        sum_conv   <=  'd0                         ;
        sum_flag_2 <=   0                          ;
     end
     else if(sum_flag_1) begin
        sum_conv   <= mid_conv0+mid_conv1+mid_conv2;
        sum_flag_2 <=   1'b1                       ;
     end
     else begin
        sum_conv   <= sum_conv                     ;
        sum_flag_2 <=   1'b0                       ;
     end    
end

always @(posedge sclk or posedge reset) begin
    if(reset==1'b1)begin
      mean_conv  <= 'd0                            ;
      mean_flag  <=  1'b0                          ;
    end
    else if(sum_flag_2)begin
      mean_conv  <= sum_conv*114                   ;
      mean_flag  <=  1'b1                          ;
    end
    else begin
      mean_conv  <= mean_conv                      ;
      mean_flag  <=  1'b0                          ;
    end  
end
    
assign  last_valid_o  =  mean_flag                      ;
assign  last_data_o   =  mean_conv[18]?'hffffff: {mean_conv[17:10],mean_conv[17:10],mean_conv[17:10]};
   

always @(posedge sclk or posedge reset) begin
    if(reset)
      last_cnt<='d0;
    else if(last_cnt==921600)
      last_cnt<='d0;
    else if(last_valid_o)
      last_cnt<=last_cnt+1'b1; 
end



move_cnter #(
    .COL ( 1280 ),
    .ROW ( 720  ),
    .DW  ( 24   ))
 u_move_cnter (
    .sclk                    ( sclk              ),
    .reset                   ( reset            ),
    .raw_de                  (reg_valid_i_3      ) ,
    .raw_data                (reg_data_i_3       ) ,
    .i_de                    ( last_valid_o      ),
    .i_data                  ( last_data_o       ),
    .o_de                    ( valid_o           ),
    .o_data                  ( data_o            )
);



fifo_generator_0 fifo_generator_0 (
  .rst        (   reset         )      ,                      // input wire rst
  .wr_clk     (   sclk          )      ,                      // input wire wr_clk
  .rd_clk     (   sclk          )      ,                      // input wire rd_clk
  .din        (   wr_data_0     )      ,                      // input wire [127 : 0] din
  .wr_en      (   wr_en_0       )      ,                      // input wire wr_en
  .rd_en      (   rd_en_0       )      ,                      // input wire rd_en
  .dout       (   rd_data_0     )      ,                      // output wire [15 : 0] dout
  .full       (   full          )      ,                      // output wire full
  .empty      (   empty         )      ,                      // output wire empty
  .wr_rst_busy(wr_rst_busy),
  .rd_rst_busy(rd_rst_busy)                                   // output wire rd_rst_busy
); 

fifo_generator_0 fifo_generator_1 (
  .rst        ( reset           )      ,                      // input wire rst
  .wr_clk     ( sclk            )      ,                      // input wire wr_clk
  .rd_clk     ( sclk            )      ,                      // input wire rd_clk
  .din        ( wr_data_1       )      ,                      // input wire [127 : 0] din
  .wr_en      ( wr_en_1         )      ,                      // input wire wr_en
  .rd_en      ( rd_en_1         )      ,                      // input wire rd_en
  .dout       ( rd_data_1       )      ,                      // output wire [15 : 0] dout
  .full       (                 )      ,                      // output wire full
  .empty      (                 )      ,                      // output wire empty
  .wr_rst_busy(                 )      ,                      // output wire wr_rst_busy
  .rd_rst_busy(                 )                             // output wire rd_rst_busy
); 

endmodule

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值