OpenCV3-Python边缘检测详细介绍
OpenCV提供许多边缘检测滤波函数,包括Laplacian()、Sobel()以及Scharr(),这些滤波函数都会将非边缘区域转为黑色,将边缘区域转为白色或其它饱和颜色,但是这些函数很容易将噪声识别为边缘。缓解这个问题的方法就是边缘检测之前,对图像进行模糊处理。
OpenCV提供了很多模糊滤波函数,包括blur()(简单算术平均)、medianBlur()(中值滤波)以及GaussianBlur()(高斯滤波)等。尽管边缘检测滤波函数和模糊滤波函数的参数由很多,但总会有一个ksize参数,它是一个奇数,表示滤波核的宽和高(以像素为单位)。
(1) 中值滤波器:
中值滤波对消除椒盐噪声非常有效,能够克服线性滤波器带来的图像细节模糊等弊端,能够有效保护图像边缘信息,是非常经典的平滑噪声处理方法。在光学测量条纹图像的香味分析处理方法中有特殊作用,但在条纹中心分析方法中作用不大。
(2) Laplacian边缘检测函数
dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])
前两个是必须的参数:
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
其后是可选的参数:
dst不用解释了;
ksize是算子的大小,必须为1、3、5、7。默认为1。
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
应用举例:
main.py 内容:
def strokeEdges(src,blurKsize=7, edgeKsize=5): if blurKsize >= 3: #中值滤波 blurredSrc = cv2.medianBlur(src, blurKsize) #转换为彩色图像转换为灰度图像 graySrc = cv2.cvtColor(blurredSrc, cv2.COLOR_BGR2GRAY) else: graySrc = cv2.cvtColor(src, cv2.COLOR_BGR2GRAY) #Laplacian边缘检测函数 cv2.Laplacian(graySrc, cv2.CV_8U, graySrc, ksize = edgeKsize) #在得到Laplacian()函数的结果后,需要将其转换成黑色边缘和白色背景的图像。然后 #将其归一化(使像素值在0-1之间),并乘以源图像以便将边缘变黑。 normalizedInverseAlpha = (1.0/255)*(255-graySrc) #拆分通道为单通道,获取各个通道的灰度值 channels = cv2.split(src) for channel in channels: channel[:] = channel * normalizedInverseAlpha #合并单通道为多通道 dst = cv2.merge(channels) return graySrc,dst img = cv2.imread("./00.png") lapsrc,result = strokeEdges(img) cv2.imshow("img",img) cv2.imshow("lapsrc",lapsrc) cv2.imshow("result",result) cv2.waitKey() cv2.destroyAllWindows()
运行结果:
(3) 定制内核做卷积
OpenCV预定义的许多滤波器(滤波函数)都会使用核。核即是一组权重,它决定如何通过邻近像素点来计算新的像素点。核也称为卷积矩阵,它对一个区域的像素做调和(mix up)或卷积运算。
通常基于核的滤波器(滤波函数)被称为卷积滤波器(滤波函数),卷积矩阵是一个二维数组,有奇数行、奇数列,中心元素对应于感兴趣的像素。
如:
kernel = numpy.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]])
感兴趣的像素权重为9,其邻近像素权重为-1。对于感兴趣的像素来说,新像素值是用当前像素值乘以9.然后减去8个邻近像素值。
应用举例:
filters.py 内容:
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Sat Apr 7 22:58:11 2018 @author: lu """ import cv2 import numpy #一般的卷积滤波器 class VConvolutionFilter(object): def __init__(self, kernel): self._kernel = kernel def apply(self, src): dst = cv2.filter2D(src, -1, self._kernel) return dst #特定锐化滤波器,权重和为1 class SharpenFilter(VConvolutionFilter): def __init__(self): kernel = numpy.array([[-1, -1, -1], [-1, 9, -1], [-1, -1, -1]]) VConvolutionFilter.__init__(self, kernel) #边缘检测核,把边缘转化为白色,非边缘转为黑色,权重和为0 class FindEdgesFilter(VConvolutionFilter): def __init__(self): kernel = numpy.array([[-1, -1, -1], [-1, 8, -1], [-1, -1, -1]]) VConvolutionFilter.__init__(self, kernel) #模拟滤波器,通常权重应该为1,而且邻近像素权重为正 class BlurFilter(VConvolutionFilter): def __init__(self): kernel = numpy.array([[0.04, 0.04, 0.04, 0.04, 0.04], [0.04, 0.04, 0.04, 0.04, 0.04], [0.04, 0.04, 0.04, 0.04, 0.04], [0.04, 0.04, 0.04, 0.04, 0.04], [0.04, 0.04, 0.04, 0.04, 0.04]]) VConvolutionFilter.__init__(self, kernel) #同时具有模糊(正的权重)和锐化(负的权重),产生一种脊状或浮雕的效果 class EmbossFilter(VConvolutionFilter): def __init__(self): kernel = numpy.array([[-2, -1, 0], [-1, 1, 1], [ 0, 1, 2]]) VConvolutionFilter.__init__(self, kernel)
main.py 内容:
import matplotlib.pyplot as plt import cv2 import filters #读取图像 img = cv2.imread("./00.png") #特定锐化滤波器 filt = filters.SharpenFilter() result1 = filt.apply(img) #边缘检测滤波器 filt = filters.FindEdgesFilter() result2 = filt.apply(img) #模拟滤波器 filt = filters.BlurFilter() result3 = filt.apply(img) #模糊+锐化滤波器 filt = filters.EmbossFilter() result4 = filt.apply(img) plt.figure(figsize=(10,10)) #参数figsize设置画布大小 plt.subplot(221) plt.title('SharpenFilter') plt.imshow(result1) plt.subplot(222) plt.title('FindEdgesFilter') plt.imshow(result2) plt.subplot(223) plt.title('BlurFilter') plt.imshow(result3) plt.subplot(224) plt.title('EmbossFilter') plt.imshow(result4) plt.show()
运行结果:
(4) Canny边缘检测
OpenCV中提供了非常方便的边缘检测函数Canny,直接调用即可,近一步详细介绍访问这里。
cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient ]]])
必要参数:
第一个参数是需要处理的原图像,该图像必须为单通道的灰度图;
第三个参数是阈值2,一般用来检测图像中明显的边缘,但一般会出现断断续续的状况,需要结合调整第二个参数阈值1来将一些间断的边缘连接起来。
应用举例:
main.py 内容:
img = cv2.imread("./00.png",0) result = cv2.Canny(img, 200, 300) cv2.imshow("Original",img) cv2.imshow("Canny",result) cv2.waitKey() cv2.destroyAllWindows()
运行结果:
参考: