OpenCV与Python之图像边缘检测

目录

1. Sobel算子

2. Scharr算子

3.  Laplacian算子

4. Canny算子


1. Sobel算子

对于Sobel原理,此处不进行介绍,百度一搜很仔细,但我们需要知道Sobel的是一阶微分算子,也就是图像的一阶导数,根据导数的定义,变化越明显的地方,梯度也大,自然也就对应了图像的边缘。

Sobel的核分为了x方向和y方向两个:

Gx = [[-1,0,1],[-2,0,2],[-1,0,1]]

Gy = [[-1,-2,-1],[0,0,0],[1,2,1]]

分别检测x,y方向的梯度

命令:dst = cv2.Sobel(img, ddepth, dx, dy, [ksize])

img为原始灰度图像;ddepth为图像深度,也就是图像的位数,灰度图一般是uint8,如果ddepth = -1,意味着输出图像的深度与输入一致;dx表示x方向;dy表示y方向;两者一般配合使用,如果是(1,0)表示求x方向梯度,如果是(0,1)表示y方向的梯度;最后ksize表示核的大小,一般为默认参数

img = cv2.imread('images/sobel.bmp', cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img, -1, 1, 0)
sobely = cv2.Sobel(img, -1, 0, 1)

我们看一下原始图像和x,y方向的梯度情况:

OpenCV与Python之图像边缘检测_第1张图片

我们可以发现,x,y方向的边缘检测都有问题,只有一般被检测出来了,这是因为我们选择ddepth参数的问题,我们选择-1,让Sobel输出图像的深度和输入保持一致,也就是也为uint8,这就有一个问题了uint8的范围是0到255,但比如在x方向时,图像左边是白色(255),右边是黑色(0),用Sobel算子就是右边减去左边,这样便得到了一个负值梯度,而uint8保存不了负值,做截断处理,所以一半边缘就没有被检测出来,为了处理这种情况,我们应将ddepth参数改为cv2.CV_64F,即将输出图像的深度改为64位的浮点数,然后使用cv2.convertScaleAbs,将负值取绝对值,如果不使用还是只能得到一半的边缘,因为负值还是会被截断

如果我们想要得到整幅图的梯度情况,我们可以使用cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)函数,将两个方向的梯度带权重相加,都取0.5的权重表示两者权重一样

注意:得到整幅图的梯度时,不能简单的将dx,dy设成(1,1),这样得到的结果是不正确的

sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx, 0.5, sobely, 0.5, 0)

结果: 

OpenCV与Python之图像边缘检测_第2张图片

 

2. Scharr算子

与Sobel算子完全一致,只是卷积核里面的权重不一样了,Scharr算子的核是:

Gx = [[-3,0,3],[-10,0,10],[-3,0,3]]

Gy = [[-3,-10,-3],[0,0,0],[3,10,3]]

 命令:dst = cv2.Scharr(img, ddepth, dx, dy)

满足条件:dx >= 0 && dy >= 0 && dx + dy == 1

等价于:dst = cv2.Sobel(img, ddepth, dx, dy, -1)

scharrx = cv2.Scharr(img, cv2.CV_64F, 1, 0)
scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)

结果与Sobel算子的比较:(左为Sobel,右为Scharr)

OpenCV与Python之图像边缘检测_第3张图片

 

3.  Laplacian算子

拉普拉斯算子是二阶微分算子,边缘是过零点,容易受到噪声的干扰

它与Sobel算子和Scharr算子不同的是,它只有一个卷积核,这个核代表和x和y两个方向的梯度

Gxy = [[0,1,0],[1,-4,1],[0,1,0]]

命令:dst = cv2.Laplacian(img, ddepth)

laplacian = cv2.Laplacian(img, cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)

结果:

OpenCV与Python之图像边缘检测_第4张图片

OpenCV与Python之图像边缘检测_第5张图片

Laplacian算子一般不单独使用,可以实现马尔(Marr)算子,先做一个高斯平滑,再做Laplacian算子,最后检测过零点

 

4. Canny算子

原理:先对原始图像做高斯平滑,然后用Sobel算子做x,y方向的梯度检测,然后做非极大值抑制,也就是在一个领域内,同一个梯度方向上,保留梯度最大的那个,而抑制其他梯度,最后做一个双阈值检测,将小于小阈值的梯度去除,将大于大阈值的梯度保留,两者之间的判断它与已有边界的连续性,如果连续就保留,否则去除

命令:dst = cv2.Canny(img, threshold1, threshold2)

Canny算子是双阈值,所以需要指定两个阈值,阈值越小,边缘越丰富。

canny = cv2.Canny(img, 50, 100)

结果:(阈值分别是100-200;70-150;50-100)

OpenCV与Python之图像边缘检测_第6张图片

 

你可能感兴趣的:(opencv与python)