一:sobel边缘检测的基本原理
在图像中,边缘是指临界的意思,一幅图像的临界表现为图像上亮度显著变化的地方。实现边缘检测有很多种不同的方法,其中sobel算子方法较好。sobel是一个梯度的计算,如下图所示,是x和y方向的3x3窗口的卷积
其实左图是计算在x方向的算子,Gx是图像数据与其进行卷积后的结果,也是个3x3的矩阵,然后窗口一直在滑动,实际的计算公式是下图
实际为了进一步简化计算,把算子进行简化,调整为如下图
二:程序设计
在网上看了许多别人的代码,感觉sobel的计算公式代码都不一样,这使我疑惑了好久,后来发现是为了方便编写代码,大家都把公式进行了简化,所以代码看起来不太一样,但实际上效果都是差不多的。本实验做了一个三行的图像缓存,这样可以轻松实现3x3的窗口,然后按照简化公式,采用绝对值的方式计算sobel。
always@(posedge pclk)
begin
x1 <= {2'b00,p11} + {2'b00,p31} + {1'b0,p21,1'b0};
x3 <= {2'b00,p13} + {2'b00,p33} + {1'b0,p23,1'b0};
y1 <= {2'b00,p11} + {2'b00,p13} + {1'b0,p12,1'b0};
y3 <= {2'b00,p31} + {2'b00,p33} + {1'b0,p32,1'b0};
end
always@(posedge pclk)
begin
abs_x <= (x1 > x3) ? x1 - x3 : x3 - x1;
abs_y <= (y1 > y3) ? y1 - y3 : y3 - y1;
abs_g <= abs_x + abs_y;
end
计算完成后,要进行简单的二值化处理,将sobel值与阈值对比,产生黑白的二值化图像
always@(posedge pclk)
begin
data_out <= (abs_g > threshold) ? 8'h00 : 8'hff;
end
完整代码如下
module sobel (
input rst,
input pclk,
input[7:0] threshold,
input ycbcr_hs,
input ycbcr_vs,
input ycbcr_de,
input[7:0] data_in,
output reg[7:0] data_out,
output sobel_hs,
output sobel_vs,
output sobel_de
);
reg [7:0] p11,p12,p13;
reg [7:0] p21,p22,p23;
reg [7:0] p31,p32,p33;
wire [7:0] p1,p2,p3;
reg [9:0] x1,x3;
reg [9:0] y1,y3;
reg [9:0] abs_x,abs_y;
reg [10:0] abs_g;
reg [8:0] hs_buf ;
reg [8:0] vs_buf ;
reg [8:0] de_buf ;
linebuffer_Wapper#
(
.no_of_lines(3),
.samples_per_line(1024),
.data_width(8)
)
linebuffer_Wapper_m0(
.ce (1'b1 ),
.wr_clk (pclk ),
.wr_en (ycbcr_de ),
.wr_rst (rst ),
.data_in (data_in),
.rd_en (ycbcr_de ),
.rd_clk (pclk ),
.rd_rst (rst ),
.data_out ({p3,p2,p1} )
);
always@(posedge pclk)
begin
p11 <= p1;
p21 <= p2;
p31 <= p3;
p12 <= p11;
p22 <= p21;
p32 <= p31;
p13 <= p12;
p23 <= p22;
p33 <= p32;
end
always@(posedge pclk)
begin
x1 <= {2'b00,p11} + {2'b00,p31} + {1'b0,p21,1'b0};
x3 <= {2'b00,p13} + {2'b00,p33} + {1'b0,p23,1'b0};
y1 <= {2'b00,p11} + {2'b00,p13} + {1'b0,p12,1'b0};
y3 <= {2'b00,p31} + {2'b00,p33} + {1'b0,p32,1'b0};
end
always@(posedge pclk)
begin
abs_x <= (x1 > x3) ? x1 - x3 : x3 - x1;
abs_y <= (y1 > y3) ? y1 - y3 : y3 - y1;
abs_g <= abs_x + abs_y;
end
always@(posedge pclk)
begin
data_out <= (abs_g > threshold) ? 8'h00 : 8'hff;
end
//hs vs de delay 9 clock
always@(posedge pclk or posedge rst)
begin
if (rst)
begin
hs_buf <= 9'd0 ;
vs_buf <= 9'd0 ;
de_buf <= 9'd0 ;
end
else
begin
hs_buf <= {hs_buf[7:0], ycbcr_hs} ;
vs_buf <= {vs_buf[7:0], ycbcr_vs} ;
de_buf <= {de_buf[7:0], ycbcr_de} ;
end
end
assign sobel_hs = hs_buf[8] ;
assign sobel_vs = vs_buf[8] ;
assign sobel_de = de_buf[8] ;
endmodule