Canny算法简解

Canny理论:

1、首先用高斯模糊过滤掉噪声

2、然后用 Sobel 过滤器确定图像边缘的强度和方向

Gx是指梯度在x方向上的突变,也就是垂直边缘

Gy是指梯度在y方向上的突变,也就是水平边缘

根据以上公式可以求出梯度及方向。

3、对sobel的输出使用非极大抑制来观察每个检测边缘的强度和方向,选出局部最大像素,从而把最强的边缘绘制成连续的、一个像素宽的细线。Canny算子中的非极大值抑制是沿着梯度方向进行的,即是否为梯度方向上的极值点;而在角点检测等场景下说的非极大值抑制,则是检测中心点处的值是否是某一个邻域内的最大值,是,则保留,否则去除,这种情况下的非极大值抑制比较简单。

(a.) canny算子中非最大抑制(Non-maximum suppression)是回答这样一个问题: “当前的梯度值在梯度方向上是一个局部最大值吗?” 所以,要把当前位置的梯度值与梯度方向上两侧的梯度值进行比较. 
(b.) 梯度方向垂直于边缘方向, 这一点不要误解.

要进行非极大值抑制,就首先要确定像素点C的灰度值在其8值邻域内是否为最大。图1中蓝色的线条方向为C点的梯度方向,这样就可以确定其局部的最大值肯定分布在这条线上,也即出了C点外,梯度方向的交点dTmp1和dTmp2这两个点的值也可能会是局部最大值。因此,判断C点灰度与这两个点灰度大小即可判断C点是否为其邻域内的局部最大灰度点。如果经过判断,C点灰度值小于这两个点中的任一个,那就说明C点不是局部极大值,那么则可以排除C点为边缘。这就是非极大值抑制的工作原理。

因为算完梯度后边缘很粗,作者论文中假设边缘都是单个像素,因此在每个边缘的垂直方向(即梯度方向)保留最大值。

要得到dTmp1和dTmp2就需要对该两个点两端的已知灰度进行线性插值,也即根据图1中的g1和g2对dTmp1进行插值,根据g3和g4对dTmp2进行插值,这要用到其梯度方向,这是上文Canny算法中要求解梯度方向矩阵Thita的原因。

4、最后 用滞后阀值来分离最佳边缘。滞后阀值是双阀值化操作,以某图一像素宽的横切面为例,这里的曲线代表边缘强度,峰值指的是十分强的边缘。使用滞后阀值时 我们要确定一个高阀值 以便允许这些强边缘通过,再设置一个低阀值,任何低于该阀值的边缘即为弱边缘 会被舍弃。但位于高低阀值之间的边缘只有当其与另一个强边缘相连时 才会得到保留。这样Canny 就删除了弱边缘、消除了噪声,还将关联最强的那些边缘分离了出来,而这些边缘恰恰最可能是物体边界的一部分。高阈值和低阈值的比率应为2:1,3:1 。

 

代码实现:

import numpy as np
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
image = cv2.imread('3.png')
image_copy = np.copy(image)
image_copy = cv2.cvtColor(image_copy,cv2.COLOR_BGR2RGB)
plt.imshow(image_copy)

gray = cv2.cvtColor(image_copy,cv2.COLOR_RGB2GRAY)
plt.imshow(gray,cmap='gray')

lower =120
upper =240
edge = cv2.Canny(gray,lower,upper)
plt.imshow(edge,cmap='gray')

wide = cv2.Canny(gray,30,100)
tight = cv2.Canny(gray,180,240)
f,(ax1,ax2) = plt.subplots(1,2,figsize=(20,10))
ax1.set_title('wide')
ax1.imshow(wide,cmap='gray')
ax2.set_title('tight')
ax2.imshow(tight,cmap='gray')

原文地址:https://www.cnblogs.com/roscangjie/p/10830562.html