一、Canny边缘检测步骤
1): 使用高斯滤波,平滑图片、消除噪声
2): 计算图像中每个像素点的梯度强度(大小)和方向
3): 应用非极大值抑制,以消除边缘检测带来的杂散响应(在多个框中选择较准确的框)
4): 应用双阈值检测来确定真实的和潜在的边缘
5): 通过抑制孤立的弱边缘最终完成边缘检测
二、Canny边缘检测中的非极大值抑制
Canny边缘检测中的非极大值抑制中要做的就是判断某一个像素点在其梯度方向上与临界两点进行比较看其梯度强度是否最大,最大则保留,反之则抑制。
如上图所示(其中c、g1、g2等皆为像素点),假设向左上方向为梯度方向。与边界有dTmp1,dTmp2两个交点,如若要看c点是否为极大值点则就需要与dTmp1,dTmp2两点进行比较,但是这两个交点并不是实际的像素点,所以其梯度值无法直接计算,所以这里就需要引入一个线性插值法来解决这个问题。
线性插值法:如图dTmp1点为例,虽然其不为像素点,无法直接计算其梯度强度,但是dTmp1点是在g1与g2点中间,所以可以利用g1与g2两像素点的梯度强度(M)和一个比例系数(w)来近似估计dTmp1的梯度强度:M(dTmp1) = w*M(g2) + (1-w)*M(g1)。
其中w = distance(dTmp1 , g2) / distance(g1 , g2) (即dTmp1和g2之间的距离比上g1和g2的距离),这样便可以得到dTmp1的梯度强度,同理也可以得到dTmp2的梯度强度,这样的话便可以通过比较dTmp1、dTmp2、c三点的梯度强度来对c点进行非极大值抑制,当c点梯度强度小于dTmp1 or dTmp2中任一点时则对c点进行抑制。
三、Canny边缘检测中的双阈值检测
如图所示,双阈值检测就是自己设定两个值:maxVal、minVal。
(1)当像素点的梯度强度值大于maxVal时便把此像素点认为是边界点并且保留
(2)当像素点梯度强度值小于minVal时便认为是边缘内侧的点,直接舍去。
(3)若梯度强度值处于二者中间则看此像素点是否和边界点相连,如果是相连的话则将此点作为边界点保留,反之则将此点视为边界内点舍弃。
这样便可以把边界的像素点保留,而把其他的像素点给舍弃。
三、Canny边缘检测代码以及效果图展示
import numpy as np
import cv2
# canny边缘检测的步骤
# 1): 使用高斯滤波,平滑图片、消除噪声
# 2): 计算图像中每个像素点的梯度强度(大小)和方向
# 3): 应用非极大值抑制,以消除边缘检测带来的杂散响应(在多个框中选择较准确的框)
# 4): 应用双阈值检测来确定真实的和潜在的边缘
# 5): 通过抑制孤立的弱边缘最终完成边缘检测
img = cv2.imread('6.png' , cv2.IMREAD_GRAYSCALE) # 读取灰度图像
v1 = cv2.Canny(img , 80 , 150) # 80是低阈值,150是高阈值
v2 = cv2.Canny(img , 50 , 100) # 50是低阈值,100是高阈值
res = np.hstack((img , v1 , v2)) # 将原图像和几种算法得到的图像横向拼接起来
cv2.imshow("res" , res)
cv2.waitKey(0)
cv2.destroyAllWindows()
其中6.png是文件中的图片,可根据自己文件夹中的图片名字自行更改。以下是代码实现的效果展示(左 -> 右:原图(灰度图)、min80 max150、min50 max100):