跳转至

边缘检测

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)