图像处理边缘检测算法————sobel算法
一、了解边缘检测
边缘检测的目的是标识数字图像中亮度变化明显的点。图像边缘检测大幅度地减少了数据量,并且剔除了可以认为不相关的信息,保留了图像重要的结构属性。常用的边缘检测模板有Laplacian算子、Roberts算子、Sobel算子、log(Laplacian-Gauss)算子、Kirsch算子和Prewitt算子等。
Sobel算子是常用的边缘检测模板,算法比较简单,实际应用中效率比 canny 边缘检测效率要高,但是边缘不如 Canny 检测的准确.
边缘检测效果:

二、边缘检测原理
Sobel 边缘检测提供了x水平和y垂直两个方向的滤波模板
,可以只检测竖直边缘或垂直边缘或都检测。

实现步骤:
1.采用上面的模板对原图像A 进行卷积。得到 Gx 为水平横向梯度幅值,Gy为垂直方向梯度幅值。(梯度:灰度值的变化情况,梯度幅值相当于2个相邻像素灰度值之间的差异。)

2. 由横向灰度值 Gx 和纵向灰度值 Gy,计算该点的灰度值:

FPGA是不擅长做平方和开根运算的,可以采用近似计算方法:

梯度方向的计算:

3. 设置一个阈值 threshold,对数据进行比较然后输出二值图像
三、模块设计

四、verilog代码实现
端口定义:
module sobel ( input clk, //pixel clk input reset_p, input [7:0] data_in, input data_in_valid, input data_in_hs, input data_in_vs, input [7:0] threshold, output reg data_out, output reg data_out_valid, output reg data_out_hs, output reg data_out_vs );
首先产生3*3的模板:
reg [DATA_WIDTH-1:0] row0_col0; reg [DATA_WIDTH-1:0] row0_col1; reg [DATA_WIDTH-1:0] row0_col2; reg [DATA_WIDTH-1:0] row1_col0; reg [DATA_WIDTH-1:0] row1_col1; reg [DATA_WIDTH-1:0] row1_col2; reg [DATA_WIDTH-1:0] row2_col0; reg [DATA_WIDTH-1:0] row2_col1; reg [DATA_WIDTH-1:0] row2_col2;
调用IP核,存储两行数据
//line data wire [DATA_WIDTH-1:0] line0_data; wire [DATA_WIDTH-1:0] line1_data; wire [DATA_WIDTH-1:0] line2_data;
//3xline data shift_register_2taps #( .DATA_WIDTH ( DATA_WIDTH ) )shift_register_2taps( .clk (clk ), .shiftin (data_in ), .shiftin_valid (data_in_valid ), .shiftout ( ), .taps0x (line0_data ), .taps1x (line1_data ) ); assign line2_data = data_in;
3*3模板的9个数:
//----------------------------------------------------
// matrix 3x3 data
// row0_col0 row0_col1 row0_col2
// row1_col0 row1_col1 row1_col2
// row2_col0 row2_col1 row2_col2
//----------------------------------------------------
always @(posedge clk or posedge reset_p) begin
if(reset_p) begin
row0_col0 <= 'd0;
row0_col1 <= 'd0;
row0_col2 <= 'd0;
row1_col0 <= 'd0;
row1_col1 <= 'd0;
row1_col2 <= 'd0;
row2_col0 <= 'd0;
row2_col1 <= 'd0;
row2_col2 <= 'd0;
end
else if(data_in_hs && data_in_vs)
if(data_in_valid) begin
row0_col2 <= line0_data;
row0_col1 <= row0_col2;
row0_col0 <= row0_col1;
row1_col2 <= line1_data;
row1_col1 <= row1_col2;
row1_col0 <= row1_col1;
row2_col2 <= line2_data;
row2_col1 <= row2_col2;
row2_col0 <= row2_col1;
end
else begin
row0_col2 <= row0_col2;
row0_col1 <= row0_col1;
row0_col0 <= row0_col0;
row1_col2 <= row1_col2;
row1_col1 <= row1_col1;
row1_col0 <= row1_col0;
row2_col2 <= row2_col2;
row2_col1 <= row2_col1;
row2_col0 <= row2_col0;
end
else begin
row0_col0 <= 'd0;
row0_col1 <= 'd0;
row0_col2 <= 'd0;
row1_col0 <= 'd0;
row1_col1 <= 'd0;
row1_col2 <= 'd0;
row2_col0 <= 'd0;
row2_col1 <= 'd0;
row2_col2 <= 'd0;
end
end
对输入的行场同步信号打拍,方便将图像处理后的信号打拍输出
// reg data_in_valid_dly1; reg data_in_valid_dly2; reg data_in_hs_dly1; reg data_in_hs_dly2; reg data_in_vs_dly1; reg data_in_vs_dly2;
always @(posedge clk) begin data_in_valid_dly1 <= data_in_valid; data_in_valid_dly2 <= data_in_valid_dly1; data_in_hs_dly1 <= data_in_hs; data_in_hs_dly2 <= data_in_hs_dly1; data_in_vs_dly1 <= data_in_vs; data_in_vs_dly2 <= data_in_vs_dly1; end
计算 Gx 为水平横向梯度幅值(左右两列求和),Gy为垂直方向梯度幅值(上下两行求和)的绝对值,因此先判断 Gx和Gy为正的情况,正负数的绝对值去绝对值的结果不一样。
wire Gx_is_positive; wire Gy_is_positive;
//---------------------------------------------------- // mask x mask y //[-1,0,1] [ 1, 2, 1] //[-2,0,2] [ 0, 0, 0] //[-1,0,1] [-1,-2,-1] //---------------------------------------------------- assign Gx_is_positive = (row0_col2 + row1_col2*2 + row2_col2) >= (row0_col0 + row1_col0*2 + row2_col0); assign Gy_is_positive = (row0_col0 + row0_col1*2 + row0_col2) >= (row2_col0 + row2_col1*2 + row2_col2);
求Gx、Gy的绝对值:
always @(posedge clk or posedge reset_p) begin
if(reset_p)
Gx_absolute <= 'd0;
else if(data_in_valid_dly1) begin
if(Gx_is_positive)
Gx_absolute <= (row0_col2 + row1_col2*2 + row2_col2) - (row0_col0 + row1_col0*2 + row2_col0);
else
Gx_absolute <= (row0_col0 + row1_col0*2 + row2_col0) - (row0_col2 + row1_col2*2 + row2_col2);
end
end
always @(posedge clk or posedge reset_p) begin
if(reset_p)
Gy_absolute <= 'd0;
else if(data_in_valid_dly1) begin
if(Gy_is_positive)
Gy_absolute <= (row0_col0 + row0_col1*2 + row0_col2) - (row2_col0 + row2_col1*2 + row2_col2);
else
Gy_absolute <= (row2_col0 + row2_col1*2 + row2_col2) - (row0_col0 + row0_col1*2 + row0_col2);
end
end
将Gx、Gy的绝对值相加,但是需要设置一个阈值 threshold,对数据进行比较然后输出二值图像:
//----------------------------------------------------
//result
//----------------------------------------------------
always @(posedge clk or posedge reset_p) begin
if(reset_p)
data_out <= 1'b0;
else if(data_in_valid_dly2) begin
data_out threshold) ? 1'b0 : 1'b1;
end
end
将图像经过灰度处理后,再进行sobel算法提取边缘,FPGA效果实现如下:




非原创,学习过程记录,摘自小梅哥学习文档。
本文来自网络,不代表协通编程立场,如若转载,请注明出处:https://net2asp.com/3bc3642221.html
