一、为什么要使用算子模板
图像处理中,我们经常需要对采集到的图像进行滤波操作,进行滤波操作我们需要用一个滑动模板,在整幅图像中进行滑窗处理。普通的滑窗有3x3、5x5、7x7等形式。本文主要讲述一种简单的3x3模板的概念以及如何用Verilog实现。
二、3x3模板的原理
图一
如图一所示,我们把这个表格想象成一个10x10的图片,每一个小方块就是一个像素点。当选择简单的3x3模板进行处理时,如图二所示。
图二
图中蓝色的部分就是我们所使用的3x3滑动窗口,对整幅图片进行滑窗操作。同时我们也看到了,当我们需要处理边界信息的时候,我们的简单滑窗是无法进行运算的,这也是简单滑窗操作的一个缺点,想要改进这个缺点,我们需要对边界进行填充处理,填充处理的方法有很多,我们本期主要介绍滑窗模板的使用,这里对边界填充问题就不做过多的说明了。
三、Verilog实现
在实际的图像处理中,一般都会通过FIFO进行图像数据的缓存。使用3x3模板,我们至少需要两个深度大于图像行个数的FIFO,通过首尾相连的方式来缓存两行数据。等到第三行来的时候,同时输出三行数据。但这里需要注意,在3x3模板模板中,第二个FIFO缓存的是第一行数据,第一个FIFO缓存的是第二行的数据。
话不多说上代码,
`timescale 1ns / 1ps
`define TEMPLATE_3X3
module image_template
(
input wire i_clk,
input wire i_rst_n,
input wire i_en,
input wire [7:0] i_data,
output reg o_en,
`ifdef TEMPLATE_3X3
output reg [7:0] o_temp_11,
output reg [7:0] o_temp_12,
output reg [7:0] o_temp_13,
output reg [7:0] o_temp_21,
output reg [7:0] o_temp_22,
output reg [7:0] o_temp_23,
output reg [7:0] o_temp_31,
output reg [7:0] o_temp_32,
output reg [7:0] o_temp_33
`endif
);
parameter H_ACTIVE = 1280;
parameter V_ACTIVE = 720;
reg [10:0] h_cnt;
reg [10:0] v_cnt;
wire [7:0] fifo_1_in;
wire fifo_1_wr_en;
wire fifo_1_rd_en;
wire [7:0] fifo_1_out;
wire [7:0] fifo_2_in;
wire fifo_2_wr_en;
wire fifo_2_rd_en;
wire [7:0] fifo_2_out;
always@(posedge i_clk or negedge i_rst_n)
begin
if(!i_rst_n)
begin
h_cnt <= 11'd0;
end
else if(i_en)
begin
if(h_cnt == H_ACTIVE - 1'b1)
h_cnt <= 11'd0;
else
h_cnt <= h_cnt + 11'd1;
end
end
always@(posedge i_clk or negedge i_rst_n)
begin
if(!i_rst_n)
begin
v_cnt <= 11'd0;
end
else if(h_cnt == H_ACTIVE - 1'b1)
begin
if(v_cnt == V_ACTIVE - 1'b1)
v_cnt <= 11'd0;
else
v_cnt <= v_cnt + 11'd1;
end
end
assign fifo_1_in = i_data;
assign fifo_1_wr_en = (v_cnt < V_ACTIVE - 1) ? i_en : 1'b0;
assign fifo_1_rd_en = (v_cnt > 0) ? i_en : 1'b0;
assign fifo_2_in = fifo_1_out;
assign fifo_2_wr_en = fifo_1_rd_en;
assign fifo_2_rd_en = (v_cnt > 1) ? i_en : 1'b0;
fifo_generator_0 u_fifo_1(
.clk (i_clk ),
.srst (!i_rst_n ),
.din (fifo_1_in ),
.wr_en (fifo_1_wr_en ),
.rd_en (fifo_1_rd_en ),
.dout (fifo_1_out ),
.full ( ),
.empty ( ),
.data_count ( )
);
fifo_generator_0 u_fifo_2(
.clk (i_clk ),
.srst (!i_rst_n ),
.din (fifo_2_in ),
.wr_en (fifo_2_wr_en ),
.rd_en (fifo_2_rd_en ),
.dout (fifo_2_out ),
.full ( ),
.empty ( ),
.data_count ( )
);
`ifdef TEMPLATE_3X3
always@(posedge i_clk or negedge i_rst_n)
begin
if(!i_rst_n)
begin
o_temp_11 <= 8'd0;
o_temp_12 <= 8'd0;
o_temp_13 <= 8'd0;
o_temp_21 <= 8'd0;
o_temp_22 <= 8'd0;
o_temp_23 <= 8'd0;
o_temp_31 <= 8'd0;
o_temp_32 <= 8'd0;
o_temp_33 <= 8'd0;
end
else
begin
o_temp_11 <= o_temp_12;
o_temp_12 <= o_temp_13;
o_temp_13 <= fifo_2_out;
o_temp_21 <= o_temp_22;
o_temp_22 <= o_temp_23;
o_temp_23 <= fifo_1_out;
o_temp_31 <= o_temp_32;
o_temp_32 <= o_temp_33;
o_temp_33 <= i_data;
end
end
always@(posedge i_clk or negedge i_rst_n)
begin
if(!i_rst_n)
begin
o_en <= 1'b0;
end
else if((v_cnt > 1)&&(h_cnt > 1))
begin
o_en <= i_en;
end
else
begin
o_en <= 1'b0;
end
end
`endif
endmodule
仿真结果