边缘检测是是特征提取中的一个研究领域,它能边缘检测出数字图像中亮度变化明显的点,减少数据量,并剔除不相关的信息,最终保留图像重要的结构属性。常见的常用的边缘检测模板有Laplacian算子、Roberts算子、Sobel算子等。本文介绍Sobel算子。同时,Sobel 边缘检测通常带有方向性,可以只检测竖直边缘或垂直边缘或都检测
1、Sobel 提供了x水平和y垂直两个方向的滤波模板。
采用上面模板对原图像A进行卷积,其中 Gx 为水平横向灰度值,Gy为垂直纵向灰度值
2、由Gx和Gy,计算该点的灰度值,公式如下:
由于公式涉及到开方运算,我们可调用IP核,也可对公式进行近似简化,以提高运算效率:
梯度方向的计算:
3、设置阈值,小于阈值的G认为是边缘点。
sobel边缘检测算法可在SIFT特征提取中使用。因为SIFT提取的特征点中含有边缘点,存在边缘响应的问题(不稳定的边缘点),我们即可在设置阈值,将不稳点边缘点剔除。
设置阈值:120;
clc;
clear all;
close all;
RGB = imread('flower.bmp'); %读取图片
gray = double(rgb2gray(RGB)); %灰度图
[ROW,COL, DIM] = size(gray); %得到图像行列数
value = 120; %阈值设置
Sobel_img = zeros(ROW,COL);
for r = 2:ROW-1
for c = 2:COL-1
Gx = gray(r-1,c+1) + 2*gray(r,c+1) + gray(r+1,c+1) - gray(r-1,c-1) - 2*gray(r,c-1) - gray(r+1,c-1);
Gy = gray(r-1,c-1) + 2*gray(r-1,c) + gray(r-1,c+1) - gray(r+1,c-1) - 2*gray(r+1,c) - gray(r+1,c+1);
G = abs(Gx) + abs(Gy);
%G = sqrt(Gx^2 + Gy^2);
if(G > value)
Sobel_img(r,c)=0;
else
Sobel_img(r,c)=255;
end
end
end
subplot(2,2,1); imshow(RGB); title('原图');
subplot(2,2,2); imshow(gray/256);title('原图');
subplot(2,2,3); imshow(Sobel_img);title('Sobel');
imwrite(gray/256,'灰度图.bmp');
imwrite(Sobel_img,'sobel.bmp');
同高斯滤波,由于sobel边缘检测仍是33卷积运算,因此我们要生成33窗口。
流水并行处理:
第一级流水线并行:计算Gx模板左右列乘积和,计算Gy模板上下行乘积和
第二级流水并行:计算|Gx|和|Gy|——注意正负数的处理
第三级流水线:计算绝对值之和,得到最终的|G| = |Gx| + |Gy|
组合逻辑:阈值比较
verilog代码如下:
module sobel(
input clk,
input rst_n,
input [7:0] value,
input iValid,
input [7:0] sobel_11,sobel_12,sobel_13, //生成的3*3窗口数据
input [7:0] sobel_21,sobel_22,sobel_23,
input [7:0] sobel_31,sobel_32,sobel_33,
output sobel_de ,//de同步信号
output wire [7:0] sobel_data // 高斯卷积:加权平均后的值
);
reg [2:0] de_shift1 ;
reg [9:0] Gx1, Gx2 ,Gy1 ,Gy2 ,Gx,Gy;
reg [10:0] G;
reg [7:0] sodel;
//---------------------------------------------------
// sobel三级流水线
//---------------------------------------------------
//clk1,计算Gx模板左右列乘积和,计算Gy模板上下行乘积和
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
Gx1 <= 1'b0;
Gx2 <= 1'b0;
Gy1 <= 1'b0;
Gy2 <= 1'b0;
end
else begin
Gx1 <= sobel_11 + (sobel_21 << 1) + sobel_31 ;
Gx2 <= sobel_13 + (sobel_23 << 1) + sobel_33 ;
Gy1 <= sobel_11 + (sobel_12 << 1) + sobel_13 ;
Gy2 <= sobel_31 + (sobel_32 << 1) + sobel_33 ;
end
//clk2,计算 |Gx|和|Gy|,正负号的处理要注意
always @ (posedge clk or negedge rst_n)
if(!rst_n) begin
Gx <= 1'b0;
Gy <= 1'b0;
end
else begin
Gx = (Gx1 > Gx2) ? (Gx1 - Gx2) : (Gx2 - Gx1) ;
Gy = (Gy1 > Gy2) ? (Gy1 - Gy2) : (Gy2 - Gy1) ;
end
// clk3,计算|Gx|+|Gy|
always @(posedge clk or negedge rst_n) begin
if(!rst_n) begin
G <= 1'd0;
end
else begin
G <= Gx + Gy ;
end
end
// 阈值比较
always @(*)
if(G > value)
sodel <= 8'b0;
else
sodel <= 8'd255;
assign sobel_data = sodel;
// 打拍做同步
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
de_shift1 <= 3'b0;
end
else begin
de_shift1 <= {de_shift1[1:0], iValid};
end
end
assign sobel_de = de_shift1[2];
endmodule
阈值设为120
// 实例化
sobel_top sobel_top(
.clk (clk),
.rst_n (rst_n),
.iValid (iValid),
.iData (gray),
.value (8'd120),
.oValid (oValid),
.oData (oData)
);