1.卷积核
在数字图像处理中的各种边沿检测、滤波、腐蚀膨胀等操作都离不开卷积核的生成。下面介绍如何生成各种3X3的卷积核。为后面的数字图像操作打下基础。
由于图像经过卷积操作后会减少两行两列,因此在生成卷积核的时候一般会对图像进行填充,填充的方式有加0,加1和复制边界三种方法。本文将会构建一个边沿复制的的卷积核模块,一个边沿填充0或者1的卷积核模块和一个边沿不填充的卷积核模块
2.边沿填充模式卷积核生成
2.1 边沿复制的卷积代码
首先生成一个FWFT的FIFO模块,然后编写下面的卷积核模块
module matrix #(parameter COL = 1920 ,parameter ROW = 1080 ,parameter PADDING = 0
)(input wire clk ,input wire rst_n ,input wire [7:0] data ,input wire data_de ,output wire matrix_de ,output reg [7:0] matrix11 ,output reg [7:0] matrix12 ,output reg [7:0] matrix13 ,output reg [7:0] matrix21 ,output reg [7:0] matrix22 ,output reg [7:0] matrix23 ,output reg [7:0] matrix31 ,output reg [7:0] matrix32 ,output reg [7:0] matrix33
);reg [2:0] data_de_r ;
reg [7:0] data_r1 ;
reg [7:0] data_r2 ;reg [15:0] col_cnt ;
reg [15:0] row_cnt ; reg data_valid ;
reg [10:0] data_valid_r;
reg fake_data_valid;wire [7:0] row1_data ;
wire [7:0] row2_data ;
reg [7:0] row3_data ;always @(posedge clk )begindata_de_r <= {data_de_r[1:0],data_de};data_valid_r <= {data_valid_r[9:0],data_valid};data_r1 <= data ;data_r2 <= data_r1 ;
end
wire pos_data_de;
assign pos_data_de = {data_de_r[0],data_de} == 2'b01;always @(posedge clk or negedge rst_n)beginif(rst_n == 0)begincol_cnt <= 0;endelse if(col_cnt == COL + 1)begincol_cnt <= 0;endelse if(data_valid || fake_data_valid)begincol_cnt <= col_cnt + 1;end
endalways @(posedge clk or negedge rst_n)beginif(rst_n == 0)beginrow_cnt <= 0;endelse if(col_cnt == COL + 1 && row_cnt == ROW )beginrow_cnt <= 0;endelse if(col_cnt == COL + 1)beginrow_cnt <= row_cnt + 1;end
endalways @(posedge clk or negedge rst_n) beginif (rst_n == 0) begin // resetfake_data_valid <= 0;endelse if (data_valid_r[4] == 0 && row_cnt == ROW && col_cnt <= COL ) beginfake_data_valid <= 1;endelse beginfake_data_valid <= 0;end
endalways @(posedge clk or negedge rst_n)beginif(rst_n == 0)beginrow3_data <= 0;endelse if(col_cnt == 0 && pos_data_de)beginrow3_data <= data ;endelse if(col_cnt == COL && data_de_r[1])beginrow3_data <= row3_data;endelse beginrow3_data <= data_r1;end
endalways@(posedge clk or negedge rst_n)beginif(rst_n == 0)begindata_valid <= 0;endelse if(data_de || data_de_r[1])begindata_valid <= 1'b1;endelse begindata_valid <= 1'b0;end
endwire rd_en ; fifo_matrix_buf u1_fifo_matrix_buf (.rst (!rst_n ), .wr_clk (clk ), .rd_clk (clk ), .din (row2_data ), .wr_en (data_valid ), .rd_en (rd_en ), .dout (row1_data ), .full ( ), .empty ( )
);fifo_matrix_buf u2_fifo_matrix_buf (.rst (!rst_n ), .wr_clk (clk ), .rd_clk (clk ), .din (row3_data ), .wr_en (data_valid ), .rd_en (rd_en ), .dout (row2_data ), .full ( ), .empty ( )
);assign rd_en = (row_cnt > 0 & (data_valid | fake_data_valid) )? 1'b1 : 1'b0;always @(posedge clk or negedge rst_n)beginif(rst_n == 0)begin{matrix11,matrix12,matrix13} <= 24'd0;{matrix21,matrix22,matrix23} <= 24'd0;{matrix31,matrix32,matrix33} <= 24'd0;endelse if(rd_en)beginif(row_cnt == 1)begin{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row2_data};{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};end else if (row_cnt == ROW) begin{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row2_data}; endelse begin{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};end endendreg [3:0] rd_en_r;
always @(posedge clk)beginrd_en_r <= {rd_en_r[2:0],rd_en};
endassign matrix_de = rd_en_r[2] & rd_en_r[0] ;endmodule
2.2 边沿填充的卷积核仿真代码
`timescale 1ns / 1psmodule img_gen
#(parameter ACTIVE_IW = 1920 ,parameter ACTIVE_IH = 1080 ,parameter TOTAL_IW = 2200 ,parameter TOTAL_IH = 1100 ,parameter H_START = 100 ,parameter V_START = 4
)(input wire clk ,input wire rst_n ,output reg vs ,output reg de ,output wire [7:0] data
);reg [15:0] hcnt ;
reg [15:0] vcnt ;reg h_de ;
reg v_de ;reg index_de ;
reg [31:0] index ;always @(posedge clk or negedge rst_n)if(!rst_n)hcnt <= 'd0;else if(hcnt == TOTAL_IW - 1)hcnt <= 'd0;else hcnt <= hcnt + 1'b1;always @(posedge clk or negedge rst_n)if(!rst_n)vcnt <= 'd0;else if(hcnt == TOTAL_IW - 1 && vcnt == TOTAL_IH - 1)vcnt <= 'd0;else if(hcnt == TOTAL_IW - 1)vcnt <= vcnt + 1'b1;else vcnt <= vcnt;always @(posedge clk or negedge rst_n)if(!rst_n)vs <= 'd0;else if(vcnt>=2)vs <= 1'b1;else vs <= 1'b0;always @(posedge clk or negedge rst_n)if(!rst_n)h_de <= 'd0;else if(hcnt >= H_START && hcnt < H_START + ACTIVE_IW)h_de <= 1'b1;else h_de <= 1'b0;always @(posedge clk or negedge rst_n)if(!rst_n)v_de <= 'd0;else if(vcnt >= V_START && vcnt < V_START + ACTIVE_IH)v_de <= 1'b1;else v_de <= 1'b0;always @(posedge clk or negedge rst_n)if(!rst_n)index_de <= 'd0;else if(h_de == 1'b1 && v_de == 1'b1)index_de <= 1'b1;else index_de <= 1'b0;always @(posedge clk or negedge rst_n)if(!rst_n)index <= 'd0;else if(index == ACTIVE_IW * ACTIVE_IH-1)index <= 0;else if(index_de == 1'b1)index <= index + 1;else index <= index;always @(posedge clk or negedge rst_n)if(!rst_n)de <= 'd0;else de <= index_de;
assign data = index;
endmodule
`timescale 1ns / 1psmodule tb_matrix();reg clk ;
reg rst_n ;wire [7:0] data ;
wire de ;wire vs ;wire [7:0] matrix11;
wire [7:0] matrix12;
wire [7:0] matrix13;
wire [7:0] matrix21;
wire [7:0] matrix22;
wire [7:0] matrix23;
wire [7:0] matrix31;
wire [7:0] matrix32;
wire [7:0] matrix33; always #5 clk <= ~clk;
initial beginclk <= 0;rst_n = 0;#2000rst_n = 1;
endimg_gen
#(.ACTIVE_IW (5 ),.ACTIVE_IH (5 ),.TOTAL_IW (11 ),.TOTAL_IH (11 ),.H_START (4 ),.V_START (4 )
)u_img_gen(.clk (clk ),.rst_n (rst_n ),.vs (vs ),.de (de ),.data (data )
);matrix #(.COL(5),.ROW(5)
)u_matrix(.clk (clk ),.rst_n (rst_n ),.data (data ),.data_de (de ),.matrix11 (matrix11 ),.matrix12 (matrix12 ),.matrix13 (matrix13 ),.matrix21 (matrix21 ),.matrix22 (matrix22 ),.matrix23 (matrix23 ),.matrix31 (matrix31 ),.matrix32 (matrix32 ),.matrix33 (matrix33 )
);reg vs_r ;always @(posedge clk)if(rst_n == 0)vs_r <= 1'b0;else vs_r <= vs;always @(posedge clk)if(~vs&&vs_r)$stop;
endmodule
2.3 边沿填充的卷积核仿真波形
边沿复制后的数据为
仿真波形为:
可以看到3X3卷积模板生成无误。
后面将边沿填充0和1以及无填充的三种方式一起讲解。