1.卷积核
在数字图像处理中的各种边沿检测、滤波、腐蚀膨胀等操作都离不开卷积核的生成。下面介绍如何生成各种3X3的卷积核。为后面的数字图像操作打下基础。
由于图像经过卷积操作后会减少两行两列,因此在生成卷积核的时候一般会对图像进行填充,填充的方式有加0,加1和复制边界三种方法。本文将会构建一个边沿复制的的卷积核模块,一个边沿填充0或者1的卷积核模块和一个边沿不填充的卷积核模块
2.边沿填充模式卷积核生成
2.1 具有边沿填充的卷积代码
首先生成一个FWFT的FIFO模块,然后编写下面的卷积核模块
module padding_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 ,
input wire [1:0] padding ,
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 [1: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 [4: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 )begin
data_de_r <= {data_de_r[1:0],data_de};
data_valid_r <= {data_valid_r[3:0],data_valid};
data_r1 <= data ;
end
wire pos_data_de;
assign pos_data_de = {data_de_r[0],data_de} == 2'b01;
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
col_cnt <= 0;
end
else if(col_cnt == COL + 1)begin
col_cnt <= 0;
end
else if(data_valid || fake_data_valid)begin
col_cnt <= col_cnt + 1;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
row_cnt <= 0;
end
else if(col_cnt == COL + 1 && row_cnt == ROW )begin
row_cnt <= 0;
end
else if(col_cnt == COL + 1)begin
row_cnt <= row_cnt + 1;
end
end
always @(posedge clk or negedge rst_n) begin
if (rst_n == 0) begin
fake_data_valid <= 0;
end
else if (data_valid_r[4] == 0 && row_cnt == ROW && col_cnt <= COL ) begin
fake_data_valid <= 1;
end
else begin
fake_data_valid <= 0;
end
end
always @(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
row3_data <= 0;
end
else if(col_cnt == 0 && pos_data_de && padding == 0)begin
row3_data <= 0 ;
end
else if(col_cnt == 0 && pos_data_de && padding == 1)begin
row3_data <= 8'hFF ;
end
else if(col_cnt == 0 && pos_data_de)begin
row3_data <= data ;
end
else if(col_cnt == COL && data_de_r[1] && padding == 0)begin
row3_data <= 0;
end
else if(col_cnt == COL && data_de_r[1] && padding == 1)begin
row3_data <= 8'hFF;
end
else if(col_cnt == COL && data_de_r[1])begin
row3_data <= row3_data;
end
else begin
row3_data <= data_r1;
end
end
always@(posedge clk or negedge rst_n)begin
if(rst_n == 0)begin
data_valid <= 0;
end
else if(data_de || data_de_r[1])begin
data_valid <= 1'b1;
end
else begin
data_valid <= 1'b0;
end
end
wire 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)begin
if(rst_n == 0)begin
{matrix11,matrix12,matrix13} <= 24'd0;
{matrix21,matrix22,matrix23} <= 24'd0;
{matrix31,matrix32,matrix33} <= 24'd0;
end
else if(rd_en)begin
if(row_cnt == 1)begin
if (padding == 0) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13, 0};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
if (padding == 1) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13, 8'hFF};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
else begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row2_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
end
else if (row_cnt == ROW) begin
if (padding == 0) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33, 0};
end
else if(padding == 1) begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33, 8'hff};
end
else begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row2_data};
end
end
else begin
{matrix11,matrix12,matrix13} <= {matrix12,matrix13,row1_data};
{matrix21,matrix22,matrix23} <= {matrix22,matrix23,row2_data};
{matrix31,matrix32,matrix33} <= {matrix32,matrix33,row3_data};
end
end
end
reg [3:0] rd_en_r;
always @(posedge clk)begin
rd_en_r <= {rd_en_r[2:0],rd_en};
end
assign matrix_de = rd_en_r[2] & rd_en_r[0] ;
endmodule
2.2 边沿填充的卷积核仿真代码
`timescale 1ns / 1ps
module 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 / 1ps
module 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 begin
clk <= 0;
rst_n = 0;
#2000
rst_n = 1;
end
img_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卷积模板生成无误。
无边沿填充的卷积核只需要将martex