opencv Canny边缘检测(c++)
说明
Canny 边缘检测算法是 John F. Canny 于1986年开发出来的一个多级边缘检测算法,也被很多人认为是边缘检测的最优算法。
Canny原理
-
降噪
由于边缘检测容易受到图像中噪声的影响,因此第一步是使用5x5高斯滤波器消除图像中的噪声。 -
计算梯度值和梯度方向
通过点乘一个sobel或其它算子得到不同方向的梯度值 G x , G_x , Gx, G y G_y Gy。
综合梯度通过以下公式计算梯度值和梯度方向:
E d g e _ G r a d i e n t ( G ) = G x 2 + G y 2 A n g l e ( θ ) = tan − 1 ( G y G x ) Edge\_Gradient \; (G) = \sqrt{G_x^2 + G_y^2} \\ Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg) Edge_Gradient(G)=Gx2+Gy2Angle(θ)=tan−1(GxGy) -
非极大值抑制
在高斯滤波过程中,边缘有可能被放大了。这个步骤使用一个规则来过滤不是边缘的点,使边缘的宽度尽可能为1个像素点:如果一个像素点属于边缘,那么这个像素点在梯度方向上的梯度值是最大的。否则不是边缘,将灰度值设为0。 -
使用上下阀值来检测边缘
该阶段确定哪些边缘全部是真正的边缘,哪些不是。为此,我们需要两个阈值minVal和maxVal。强度梯度大于maxVal的任何边缘必定是边缘,而小于minVal的那些边缘必定是非边缘,因此将其丢弃。介于这两个阈值之间的对象根据其连通性被分类为边缘或非边缘。如果将它们连接到“边缘”像素,则将它们视为边缘的一部分。否则,它们也将被丢弃。见下图:

边缘A在maxVal之上,因此被视为“确定边缘”。尽管边C低于maxVal,但它连接到边A,因此也被视为有效边,我们得到了完整的曲线。但是边缘B尽管在minVal之上并且与边缘C处于同一区域,但是它没有连接到任何“确保边缘”,因此被丢弃。因此,非常重要的一点是我们必须相应地选择minVal和maxVal以获得正确的结果。
Canny()
CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false );
@param image // 8位输入图像。
@param边缘 //输出边缘图; 单通道8位图像,其大小与image相同。
@param threshold1 //下阈值minVal。
@param threshold2 //上阈值maxVal。
@param holeSize //Sobel运算符的范围大小。
@param L2gradient //一个标志,指示是否应使用更准确的
L
2
L_2
L2 norm
=
(
d
I
/
d
x
)
2
+
(
d
I
/
d
y
)
2
=\sqrt{(dI/dx)^2 + (dI/dy)^2}
=(dI/dx)2+(dI/dy)2来计算图像梯度幅度(L2gradient = true),或者使用默认值
L
1
L_1
L1 norm
=
∣
d
I
/
d
x
∣
+
∣
d
I
/
d
y
∣
=|dI/dx|+|dI/dy|
=∣dI/dx∣+∣dI/dy∣就已经足够(L2gradient = false)。
DEMO
int main() {
cv::namedWindow("src", 0);
cv::namedWindow("dst", 0);
cv::Mat src = cv::imread("./img/test1.jpg", 1);
cv::Mat dst;
//cv::cvtColor(src, src, cv::COLOR_BGR2GRAY);
cv::Canny(src, dst, 100, 300);
cv::imshow("src", src);
cv::imshow("dst", dst);
cv::waitKey(0);
cv::imwrite("./img/dst.jpg", dst);
cv::imwrite("./img/src.jpg", src);
}
效果
原图:

结果:

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐


所有评论(0)