边缘检测
Canny边缘检测¶
Canny边缘检测方法常被誉为边缘检测的最优方法:
import cv2
import numpy as np
img = cv2.imread('handwriting.jpg', 0)
edges = cv2.Canny(img, 30, 70) # canny边缘检测
cv2.imshow('canny', np.hstack((img, edges)))
cv2.waitKey(0)
cv2.Canny()
进行边缘检测,参数2、3表示最低、高阈值,下面来解释下具体原理。
Canny边缘提取的具体步骤如下:
1,使用5×5高斯滤波消除噪声:
边缘检测本身属于锐化操作,对噪点比较敏感,所以需要进行平滑处理。 $$ K=\frac{1}{256}\left[ \begin{matrix} 1 & 4 & 6 & 4 & 1 \newline 4 & 16 & 24 & 16 & 4 \newline 6 & 24 & 36 & 24 & 6 \newline 4 & 16 & 24 & 16 & 4 \newline 1 & 4 & 6 & 4 & 1 \end{matrix} \right] $$ 2,计算图像梯度的方向:
首先使用Sobel算子计算两个方向上的梯度G_x和$ G_y $,然后算出梯度的方向: $$ \theta=\arctan(\frac{G_y}{G_x}) $$ 保留这四个方向的梯度:0°/45°/90°/135°,有什么用呢?我们接着看。
3,过滤非最大值:
在高斯滤波过程中,边缘有可能被放大了。这个步骤使用一个规则来过滤不是边缘的点,使边缘的宽度尽可能为1个像素点:如果一个像素点属于边缘,那么这个像素点在梯度方向上的梯度值是最大的。否则不是边缘,将灰度值设为0。
4,滞后阈值:
一般情况下,使用一个阀值来检测边缘,但是这样做未免太武断了。如果能够使用启发式的方法确定一个上阀值和下阀值,位于下阀值之上的都可以作为边缘,这样就可能提高准确度。
它设置两个阀值(threshold),分别为maxVal和minVal。其中大于maxVal的都被检测为边缘,而低于minval的都被检测为非边缘。对于中间的像素点,如果与确定为边缘的像素点邻接,则判定为边缘;否则为非边缘。
Canny推荐的高低阈值比在2:1到3:1之间。
先阈值分割后检测¶
其实很多情况下,阈值分割后再检测边缘,效果会更好:
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
edges = cv2.Canny(thresh, 30, 70)
cv2.imshow('canny', np.hstack((img, thresh, edges)))
cv2.waitKey(0)