一、Canny边缘检测
Canny边缘检测的过程如下:
(1) 使用高斯滤波器进行滤波,平滑图像并滤除噪音,同时进行了像素点的归一化处理。
(2)计算图中每个像素点的梯度强度和方向
(3)应用非极大值抑制,以消除边缘检测带来的杂散效应。
(4)应用双阈值检测来确定其真实的和潜在的边缘
(5)通过抑制孤立的弱边缘最终完成边缘检测
1、使用高斯滤波器时,高斯核的大小是可变的,因此其对于边缘检测的效果也是变化的。滤波器的核越大,边缘信息对于噪声的敏感度就越低,但是边缘检测的定位错误也会随之增加,一般情况下选取5x5的卷积核。
2、高斯过滤完成后,就要计算图像像素点的梯度值以及其梯度方向,梯度方向总是与边缘垂直,通常取近似值为水平、垂直、对角线上的八个方向。
计算梯度的方法就是先使用Sobel算子计算出图像的水平以及垂直方向梯度,接着将两个梯度方向值进行反正切计算,得到方向角度。所以计算梯度时,最后每一个像素点都会得到两个值—梯度的幅度和角度。
3、非极大值抑制
通过这一步操作可以将边界更加细化,使得图像的边缘轮廓更加清晰,上一节使用sobel算子检测边缘时,最后得到的效果图边缘线很厚。
可以看这篇笔记的效果图:opencv-python图像处理 ----图像梯度、Sobel算子
非极大值抑制的做法就是遍历图像中的所有像素点,去除非边缘的点。逐一遍历像素点时,判断当前像素点是否是周围像素点中具有相同方向梯度的最大值,并根据判断结果决定是否抑制该点。抑制的含义也就是,将该点像素值清零。这样做可以很好的细化边界。
4、双阈值处理
到这里,图像内的强边缘已经在当前获取的边缘图像内。但是一些虚边缘可能也在边缘图像内。这些虚边缘若果是噪声产生的就必须将其剔除。双阈值顾名思义,会设置两个不阈值,一个是极大值阈值(maxVal),一个是极小值阈值(minVal)。根据当前检索的边缘像素梯度值与阈值关系判断其属性:
(1)若当前边缘像素梯度大于或等于maxVal,标记为强边缘
(2)介于maxVal与minVal之间,标记为需要保留的虚边缘
(3)小于minVal阈值,抑制该点像素值(置零)
二、使用opencv自带的Canny检测函数
介绍完上面的检测步骤发现不止一次使用了遍历整个像素点,因此对于大尺寸的图片其计算量应该是很大的。
代码如下:其实只有简单的一行
def Canny_f():
# 直接读取灰度图
img = cv.imread("car_red.jpg", cv.IMREAD_GRAYSCALE)
result = cv.Canny(img, 128, 200)
cv.imshow("hh", result)
cv.waitKey(0)
cv.destroyAllWindows()
效果图如下,对比之前使用sobel算子实现的边缘检测,边缘确实细化了很多。使用程序时,我们自定了其中的双阈值,因此对于这组参数我们可以由实验或者经验来获得最佳参数。
根据经验:双阈值较小时,能够捕捉到更多的边缘信息。
改变一些双阈值做对比:
def Canny_f():
img = cv.imread("car_red.jpg", cv.IMREAD_GRAYSCALE)
result1 = cv.Canny(img, 128, 200)
result2 = cv.Canny(img, 100, 150)
# 按水平方向拼接矩阵
result = np.hstack((result1, result2))
cv_show(result, "hh")
效果:
略微减小阈值,可以发现发现图像的边界细节更多了。某些情况下,我们需要更加清晰更加简单的边界,比如上图,我们需要最佳清晰边界的车体轮廓,那么就应该略微提高阈值,将多余的噪声边界过滤掉。