边缘检测
文章目录
0.简介
边缘是图像强度函数快速变化的地方,为了检测边缘,我们需要检测图像中的不连续性,可以使用导数来检测不连续性。
1.学习目标
- 掌握Sobel边缘检测的原理
- 掌握Canny边缘检测的原理
2.算法理论介绍
2.1Sobel算子
索贝尔算子(Sobeloperator)
主要用作边缘检测,在技术上,它是一离散性差分算子,用来运算图像亮度函数的灰度之近似值。在图像的任何一点使用此算子,将会产生对应的灰度矢量或是其法矢量。
该算子包含两组3*3的矩阵。分别为横向及纵向,将之于图像作平面卷积,即可分别得出横向及纵向的高度差分近似值。如果以 A A A代表原始图像, G x Gx Gx及 G y Gy Gy分别代表经横向及纵向边缘检测的图像灰度值,其公式如下:
G x = [ − 1 0 + 1 − 2 0 + 2 − 1 0 + 1 ] ∗ A and G y = [ + 1 + 2 + 1 0 0 0 − 1 − 2 − 1 ] ∗ A \mathbf{G}_{\mathbf{x}}=\left[\begin{array}{ccc} -1 & 0 & +1 \\ -2 & 0 & +2 \\ -1 & 0 & +1 \end{array}\right] * \mathbf{A} \quad \text { and } \quad \mathbf{G}_{\mathbf{y}}=\left[\begin{array}{ccc} +1 & +2 & +1 \\ 0 & 0 & 0 \\ -1 & -2 & -1 \end{array}\right] * \mathbf{A} Gx=⎣⎡−1−2−1000+1+2+1⎦⎤∗A and Gy=⎣⎡+10−1+20−2+10−1⎦⎤∗A
具体的计算结果:
G x = ( − 1 ) ∗ f ( x − 1 , y − 1 ) + 0 ∗ f ( x , y − 1 ) + 1 ∗ f ( x + 1 , y − 1 ) + ( − 2 ) ∗ f ( x − 1 , y ) + 0 ∗ f ( x , y ) + 2 ∗ f ( x + 1 , y ) + ( − 1 ) ∗ f ( x − 1 , y + 1 ) + 0 ∗ f ( x , y + 1 ) + 1 ∗ f ( x + 1 , y + 1 ) = [ f ( x + 1 , y − 1 ) + 2 x f ( x + 1 , y ) + f ( x + 1 , y + 1 ) ] − [ f ( x − 1 , y − 1 ) + 2 x f ( x − 1 , y ) + f ( x − 1 , y + 1 ) ] \begin{aligned} G x &=(-1)^{*} f(x-1, y-1)+0^{*} f(x, y-1)+1^{*} f(x+1, y-1) \\ &+(-2)^{*} f(x-1, y)+0^{*} f(x, y)+2^{*} f(x+1, y) \\ &+(-1)^{*} f(x-1, y+1)+0^{*} f(x, y+1)+1^{*} f(x+1, y+1) \\ &=\left[f(x+1, y-1)+2^{x} f(x+1, y)+f(x+1, y+1)\right]-\left[f(x-1, y-1)+2^{x} f(x-1, y)+f(x-1, y+1)\right] \end{aligned} Gx=(−1)∗f(x−1,y−1)+0∗f(x,y−1)+1∗f(x+1,y−1)+(−2)∗f(x−1,y)+0∗f(x,y)+2∗f(x+1,y)+(−1)∗f(x−1,y+1)+0∗f(x,y+1)+1∗f(x+1,y+1)=[f(x+1,y−1)+2xf(x+1,y)+f(x+1,y+1)]−[f(x−1,y−1)+2xf(x−1,y)+f(x−1,y+1)]G y = 1 ∗ f ( x − 1 , y − 1 ) + 2 ∗ f ( x , y − 1 ) + 1 ∗ f ( x + 1 , y − 1 ) + 0 ∗ f ( x − 1 , y ) + 0 ∗ f ( x , y ) + 0 ∗ f ( x + 1 , y ) + ( − 1 ) ∗ f ( x − 1 , y + 1 ) + ( − 2 ) ∗ f ( x , y + 1 ) + ( − 1 ) ∗ f ( x + 1 , y + 1 ) = [ f ( x − 1 , y − 1 ) + 2 f ( x , y − 1 ) + f ( x + 1 , y − 1 ) ] − [ f ( x − 1 , y + 1 ) + 2 x f ( x , y + 1 ) + f ( x + 1 , y + 1 ) ] \begin{aligned} G y=& 1^{*} f(x-1, y-1)+2^{*} f(x, y-1)+1^{*} f(x+1, y-1) \\ &+0^{*} f(x-1, y) +0^{*} f(x, y)+0^{*} f(x+1, y) \\ &+(-1)^{*} f(x-1, y+1)+(-2)^{*} f(x, y+1)+(-1)^{*} f(x+1, y+1) \\ &=[f(x-1, y-1)+2 f(x, y-1)+f(x+1, y-1)]-\left[f(x-1, y+1)+2^{x} f(x, y+1)+f(x+1, y+1)\right] \end{aligned} Gy=1∗f(x−1,y−1)+2∗f(x,y−1)+1∗f(x+1,y−1)+0∗f(x−1,y)+0∗f(x,y)+0∗f(x+1,y)+(−1)∗f(x−1,y+1)+(−2)∗f(x,y+1)+(−1)∗f(x+1,y+1)=[f(x−1,y−1)+2f(x,y−1)+f(x+1,y−1)]−[f(x−1,y+1)+2xf(x,y+1)+f(x+1,y+1)]
其中 f ( a , b ) f(a,b) f(a,b)表示图像 ( a , b ) (a,b) (a,b)点的灰度值
图像中的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
G = G x 2 + G y 2 \mathbf{G}=\sqrt{\mathbf{G}_{\mathbf{x}}^{2}+\mathbf{G}_{\mathbf{y}}^{2}} G=Gx2+Gy2
通常,为了提高效率使用不开平方的近似值:
∣ G ∣ = ∣ G x ∣ + ∣ G y ∣ |G|=|G x|+|G y| ∣G∣=∣Gx∣+∣Gy∣
如果梯度G大于某一阈值,则认为该点(x,y)为边缘点S o b e l Sobel Sobel-算子根据像素点上下、左右邻点灰度加权差,在边缘处达到极值这一现象检测边缘。对噪声具有平滑作用,提供较为精确的边缘方向信息,边缘定位精度不够高。当对精度要求不是很高时,是一种较为常用的边缘检测方法
2.2Canny边缘检测
Canny边缘检测于1986年由JOHN CANNY首次在论文《A Computational Approach to Edge Detection》中提出,就此拉开了Canny边缘检测算法的序幕。
Canny边缘检测是从不同视觉对象中提取有用的结构信息并大大减少要处理的数据量的一种技术,目前已广泛应用于各种计算机视觉系统。Canny发现,在不同视觉系统上对边缘检测的要求较为类似,因此,可以实现一种具有广泛应用意义的边缘检测技术。边缘检测的一般标准包括:
- 以低的错误率检测边缘,也即意味着需要尽可能准确的捕获图像中尽可能多的边缘。
- 检测到的边缘应精确定位在真实边缘的中心。
- 图像中给定的边缘应只被标记一次,并且在可能的情况下,图像的噪声不应产生假的边缘。
为了满足这些要求,Canny使用了变分法。Canny检测器中的最优函数使用四个指数项的和来描述,它可以由高斯函数的一阶导数来近似。
在目前常用的边缘检测方法中,Canny边缘检测算法是具有严格定义的,可以提供良好可靠检测的方法之一。由于它具有满足边缘检测的三个标准和实现过程简单的优势,成为边缘检测最流行的算法之一。
完成一个Canny边缘检测算法可以分为以下四步:
高斯滤波 目的 1.高斯滤波 去噪声降低错误率 2.计算梯度幅值和方向 估计每一点处的边缘强度与方向 3.非极大值抑制(NMS) 对Sobel、Prewitt等算子的结果进一步细化 4应用双阈值(Double-Threshold)检测 确定真实的和可能的边缘
2.2.1高斯滤波
边缘检测结果容易受到图像噪声的影响,图片中一些噪声会大大影像边缘检测。因此为了使图像平滑,可以用高斯滤波器内核与图像进行卷积。 此步骤将使图像稍微平滑,以减少边缘检测器上明显噪声的影响。
大小为
(
2
k
+
1
)
×
(
2
k
+
1
)
(2k+1)×(2k+1)
(2k+1)×(2k+1)的高斯滤波器核的方程式为:
H
i
j
=
1
2
π
σ
2
exp
(
−
(
i
−
(
k
+
1
)
)
2
+
(
j
−
(
k
+
1
)
)
2
2
σ
2
)
;
1
≤
i
,
j
≤
(
2
k
+
1
)
H_{i j}=\frac{1}{2 \pi \sigma^{2}} \exp \left(-\frac{(i-(k+1))^{2}+(j-(k+1))^{2}}{2 \sigma^{2}}\right) ; 1 \leq i, j \leq(2 k+1)
Hij=2πσ21exp(−2σ2(i−(k+1))2+(j−(k+1))2);1≤i,j≤(2k+1)
2.2.2计算梯度强度和方向
进行高斯滤波后,图像中的边缘可以指向各个方向,接下来使用四个算子来检测图像中的水平、垂直和对角边缘。边缘检测的算子(如Roberts,Prewitt,Sobel等)返回水平
G
x
Gx
Gx 和垂直
G
y
Gy
Gy 方向的一阶导数值,由此便可以确定像素点的梯度
G
G
G和和方向
θ
\theta
θ
G
=
G
x
2
+
G
y
2
θ
=
arctan
(
G
y
/
G
x
)
\begin{aligned} &\mathbf{G}=\sqrt{\mathbf{G}_{x}^{2}+\mathbf{G}_{y}^{2}}\\ &\theta=\arctan \left(\mathbf{G}_{y} / \mathbf{G}_{x}\right) \end{aligned}
G=Gx2+Gy2θ=arctan(Gy/Gx)
其中
G
G
G 为梯度强度,
θ
\theta
θ 表示梯度方向,
a
r
c
t
a
n
arctan
arctan 为反切函数,通过上式我们可以得到一个梯度矩阵
G
G
G 和方向矩阵
θ
\theta
θ
2.2.3非极大值抑制(NMS)
在每一点上,邻域中心与沿着其对应的梯度方向的两个像素相比,若中心像素为最大值,则保留,否则中心置0,这样可以抑制非极大值,保留局部梯度最大的点,以得到细化的边缘。
对图像进行梯度计算后,仅仅基于梯度值提取的边缘仍然很模糊。对边缘有且应当只有一个准确的响应。而非极大值抑制则可以帮助将局部最大值之外的所有梯度值抑制为0。非极大值抑制是一种边缘稀疏技术,非极大值抑制的作用在于“瘦”边。直观上地看,对第二步得到的图片,边缘由粗变细了。
2.2.4用双阈值算法检测和连接边缘
双阈值法非常简单,我们假设两类边缘:经过非极大值抑制之后的边缘点中,梯度值超过TH的称为强边缘,梯度值小于TH大于TL的称为弱边缘,梯度小于TL的不是边缘。
可以肯定的是,强边缘必然是边缘点,因此必须将T1设置的足够高,以要求像素点的梯度值足够大(变化足够剧烈),而弱边缘可能是边缘,也可能是噪声,如何判断呢?当弱边缘的周围8邻域有强边缘点存在时,就将该弱边缘点变成强边缘点,以此来实现对强边缘的补充。实际中人们发现T1:T2=2:1的比例效果比较好,其中T1可以人为指定,也可以设计算法来自适应的指定,比如定义梯度直方图的前30%的分界线为T1。检查8邻域的方法叫边缘滞后跟踪,连接边缘的办法还有区域生长法等等。
3.基于opencv的实现
3.1函数原型
3.1.1 Sobel
void Sobel ( InputArray src, //输入图
OutputArray dst, //输出图
int ddepth, //输出图像的深度
int dx, //x方向上的差分阶数。
int dy, //y方向上的差分阶数。
int ksize=3, //表示Sobel核的大小;必须取1,3,5或7,默认大小为3
double scale=1, //计算导数值时可选的缩放因子,默认值是1,
double delta=0, //表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
int borderType=BORDER_DEFAULT ); //边界模式
3.2实现示例(c++)
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
Mat dstIamge, grad_x, grad_y, abs_grad_x, abs_grad_y;
Mat srcIamge = imread("C:/Users/Administrator/Desktop/opencv/test1.jpg");
imshow("原始图", srcIamge);
cvtColor(srcIamge, srcIamge, COLOR_RGB2GRAY);
//求 X方向梯度
Sobel(srcIamge, grad_x, CV_16S, 1, 0, 3, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);//使用线性变换转换输入数组元素成8位无符号整型
imshow("X方向Sobel", abs_grad_x);
//求Y方向梯度
Sobel(srcIamge, grad_y, CV_16S, 0, 1, 3, 1, 1, BORDER_DEFAULT);
convertScaleAbs(grad_y, abs_grad_y);
imshow("Y方向Sobel", abs_grad_y);
//合并梯度(近似)
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dstIamge);
imshow("整体方向Sobel", dstIamge);
waitKey(0);
return 0;
}
3.3进阶实现(根据原理自己实现)【未完成】
4.参考
ddWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dstIamge);
imshow(“整体方向Sobel”, dstIamge);
waitKey(0);
return 0;
}
### 3.3进阶实现(根据原理自己实现)【未完成】
## 4.参考
1. [sobel算子原理与实现](https://blog.youkuaiyun.com/qq_29540745/article/details/51918004?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2https://blog.youkuaiyun.com/qq_29540745/article/details/51918004?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-2)