OPENCV笔记 边缘检测

Sobel算子

sobel算子是图像边缘检测的最重要的算子之一,在机器学习、数字媒体、计算机视觉等领域起着重要作用。
Sobel算子包含两组3×3的滤波器,分别对水平及垂直方向上的边缘敏感。
G x = [ x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 ] = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ A (3) G_x= \left[\begin{matrix}x1 & x2 &x3 \\x4 & x5 & x6 \\x7 & x8 & x9\end{matrix}\right] =\left[\begin{matrix}-1 & 0 & 1 \\-2 &0 & 2 \\-1 & 0 & 1\end{matrix}\right] \tag{3}*A Gx= x1x4x7x2x5x8x3x6x9 = 121000121 A(3)
G y = [ x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 ] = [ − 1 − 2 − 1 0 0 0 1 2 1 ] ∗ A (3) G_y = \left[\begin{matrix}x1 & x2 &x3 \\x4 & x5 & x6 \\x7 & x8 & x9\end{matrix}\right] =\left[\begin{matrix}-1 & -2 & -1 \\0 &0 & 0 \\1 & 2 & 1\end{matrix}\right] \tag{3}*A Gy= x1x4x7x2x5x8x3x6x9 = 101202101 A(3)
Sobel算法的本质是让两个方向模板分别沿着x轴、y轴与图像做卷积,方向是从上到下和从左到右。将模板的中心和图像上的某个像素重合,并将该像素周围的点 与模板上对应的系数相乘,其中Gx及Gy分别代表经横向及纵向边缘检测的图像梯度值。
只算左右方向

import cv2
import numpy as np
img = cv2.imread('img.jpg')
#dst = cv2.Sobel(src,ddepth,dx,dy,ksize,scale, delta, borderType)
#前四个为必须项,其后为可选参数
#ddepth:图形的深度
#dx和dy分别表示水平和竖直方向
#ksize是Sobel算子的大小
#scale是缩放导数的比例常数,默认情况下没有伸缩系数;
#delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
#borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
img_sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
cv2.imshow('img_sobelx', img_sobelx)
cv2.waitKey(0)
cv2.destroyAllWindows()

原图于运行结果:

可以看到运行结果并不理想(理论上说,应该只在边界上有白点,且只有从黑到白有显示)

因为从黑到白为正数,从白到黑为负数,所有的负数被截断成0,所以要去绝对值。

import cv2
import numpy as np
img = cv2.imread('img.jpg')
img_sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
img_sobelx = cv2.convertScaleAbs(img_sobelx)
cv2.imshow('img_sobelx', img_sobelx)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
效果明显变好,边缘处既无错误判断,也能处理从白到黑的地方

只算上下方向

import cv2
import numpy as np
img = cv2.imread('img.jpg')
img_sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
img_sobely = cv2.convertScaleAbs(img_sobely)
cv2.imshow('img_sobely', img_sobely)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

两个方向的计算结果求和

import cv2
import numpy as np
img = cv2.imread('img.jpg')
img_sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
img_sobelx = cv2.convertScaleAbs(img_sobelx)
img_sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
img_sobely = cv2.convertScaleAbs(img_sobely)
img_sobel = cv2.addWeighted(img_sobely,0.5,img_sobely,0.5,0)
cv2.imshow('img_sobel',img_sobel)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
不建议直接计算两个方向,在融合的过程中会出现发散,效果不好

import cv2
import numpy as np
img = cv2.imread('img.jpg')
img_sobel = cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
img_sobel = cv2.convertScaleAbs(img_sobel)
cv2.imshow('img_sobel',img_sobel)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

Scharr算子

Scharr算子是对Sobel算子差异性的增强,因此两者之间的在检测图像边缘的原理和使用方式上相同。Scharr算子的边缘检测滤波的尺寸为3×3,因此也有称其为Scharr滤波器。可以通过将滤波器中的权重系数放大来增大像素值间的差异,Scharr算子就是采用的这种思想,其在X方向和Y方向的边缘检测算子:
G x = [ x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 ] = [ − 3 0 3 − 10 0 10 − 3 0 3 ] ∗ A (3) G_x= \left[\begin{matrix}x1 & x2 &x3 \\x4 & x5 & x6 \\x7 & x8 & x9\end{matrix}\right] =\left[\begin{matrix}-3 & 0 & 3 \\-10 &0 & 10 \\-3 & 0 & 3\end{matrix}\right] \tag{3}*A Gx= x1x4x7x2x5x8x3x6x9 = 31030003103 A(3)
G y = [ x 1 x 2 x 3 x 4 x 5 x 6 x 7 x 8 x 9 ] = [ − 3 − 10 − 3 0 0 0 3 10 3 ] ∗ A (3) G_y = \left[\begin{matrix}x1 & x2 &x3 \\x4 & x5 & x6 \\x7 & x8 & x9\end{matrix}\right] =\left[\begin{matrix}-3 & -10 & -3 \\0 &0 & 0 \\3 & 10 & 3\end{matrix}\right] \tag{3}*A Gy= x1x4x7x2x5x8x3x6x9 = 30310010303 A(3)

laplacian算子

Laplacian算子具有各方向同性的特点,能够对任意方向的边缘进行提取,具有无方向性的优点,因此使用Laplacian算子提取边缘不需要分别检测X方向的边缘和Y方向的边缘,只需要一次边缘检测即可。Laplacian算子是一种二阶导数算子,对噪声比较敏感,因此常需要配合高斯滤波一起使用。
G x = [ 0 1 0 1 − 4 1 0 1 0 ] (3) G_x=\left[\begin{matrix}0 & 1 & 0 \\1 & -4 & 1 \\0 & 1 & 0\end{matrix}\right] \tag{3} Gx= 010141010 (3)

import cv2
import numpy as np
img = cv2.imread('img.jpg')
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharry = cv2.convertScaleAbs(scharry)
scharr = cv2.addWeighted(scharrx, 0.5, scharry, 0.5, 0)

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

cv2.imshow('scharr',scharr)
cv2.imshow('laplacian',laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()
Scharr 算子的运行结果较好,Laplacian算子运行结果存在较大的噪声。

补充:关于参数ddepth的使用
首先来说CV_8U, CV_16U, CV_16S, CV_32F 以及 CV_64F,都是opencv定义的数据类型。
具体定义如下

#define CV_8S   1
#define CV_16U  2
#define CV_16S  3
#define CV_32S  4
#define CV_32F  5
#define CV_64F  6
#define CV_16F  7
#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))
 
#define CV_8SC1 CV_MAKETYPE(CV_8S,1)
#define CV_8SC2 CV_MAKETYPE(CV_8S,2)
#define CV_8SC3 CV_MAKETYPE(CV_8S,3)
#define CV_8SC4 CV_MAKETYPE(CV_8S,4)
#define CV_8SC(n) CV_MAKETYPE(CV_8S,(n))
 
#define CV_16UC1 CV_MAKETYPE(CV_16U,1)
#define CV_16UC2 CV_MAKETYPE(CV_16U,2)
#define CV_16UC3 CV_MAKETYPE(CV_16U,3)
#define CV_16UC4 CV_MAKETYPE(CV_16U,4)
#define CV_16UC(n) CV_MAKETYPE(CV_16U,(n))
 
#define CV_16SC1 CV_MAKETYPE(CV_16S,1)
#define CV_16SC2 CV_MAKETYPE(CV_16S,2)
#define CV_16SC3 CV_MAKETYPE(CV_16S,3)
#define CV_16SC4 CV_MAKETYPE(CV_16S,4)
#define CV_16SC(n) CV_MAKETYPE(CV_16S,(n))
 
#define CV_32SC1 CV_MAKETYPE(CV_32S,1)
#define CV_32SC2 CV_MAKETYPE(CV_32S,2)
#define CV_32SC3 CV_MAKETYPE(CV_32S,3)
#define CV_32SC4 CV_MAKETYPE(CV_32S,4)
#define CV_32SC(n) CV_MAKETYPE(CV_32S,(n))
 
#define CV_32FC1 CV_MAKETYPE(CV_32F,1)
#define CV_32FC2 CV_MAKETYPE(CV_32F,2)
#define CV_32FC3 CV_MAKETYPE(CV_32F,3)
#define CV_32FC4 CV_MAKETYPE(CV_32F,4)
#define CV_32FC(n) CV_MAKETYPE(CV_32F,(n))
 
#define CV_64FC1 CV_MAKETYPE(CV_64F,1)
#define CV_64FC2 CV_MAKETYPE(CV_64F,2)
#define CV_64FC3 CV_MAKETYPE(CV_64F,3)
#define CV_64FC4 CV_MAKETYPE(CV_64F,4)
#define CV_64FC(n) CV_MAKETYPE(CV_64F,(n))
 
#define CV_16FC1 CV_MAKETYPE(CV_16F,1)
#define CV_16FC2 CV_MAKETYPE(CV_16F,2)
#define CV_16FC3 CV_MAKETYPE(CV_16F,3)
#define CV_16FC4 CV_MAKETYPE(CV_16F,4)
#define CV_16FC(n) CV_MAKETYPE(CV_16F,(n))

具体含义
S = 有符号整型 U = 无符号整型 F = 浮点型
CV_8U : 8位无符号整数
CV_8S : 8位有符号整数
CV_16U : 16位无符号整数
CV_16S : 16位有符号整数
CV_32S : 32位有符号整数
CV_32F : 32位浮点数
CV_64F : 64位浮点数

Canny边缘检测

1、基本步骤

1)图像降噪。一般使用高斯滤波器,以平滑图像,滤除噪声。
高斯滤波器的模板系数,随着距离模板中心的增大而系数减小。
高斯滤波器相比于均值滤波器对图像个模糊程度较小

#高斯模糊的卷积核里的数值是高斯分布,相当于更重视中间的
aussian = cv2.GaussianBlur(noiseimage, (5, 5), 1 )

2)计算图像梯度。计算图像中每个像素点的梯度强度和大小。
因为梯度是灰度变化明显的地方,而边缘也是灰度变化明显的地方,所以计算图像梯度能够初步得到图像的边缘

3)非极大值抑制。应用非极大值抑制,以消除边缘检测带来的杂散效应。
非极大值抑制,简称为NMS算法。其思想是搜素局部最大值,抑制非极大值。目标检测的过程中在同一目标的位置上会产生大量的候选框,这些候选框相互之间可能会有重叠,此时我们需要利用非极大值抑制找到最佳的目标边界框,消除冗余的边界框

4)阈值筛选。应用双阈值检测来确定真实的和潜在的边缘,通过抑制孤立的弱边缘最终完成边缘检测
定义了两个参数,minval和maxval。
小于minval可认为不是边界,舍弃。
大于maxval则处理为边界。
大于minval,小于maxval,与边界相连就保留,否则舍弃。

使用opencv自带函数的运行代码:

import cv2
import numpy as np
img = cv2.imread('image1.png',cv2.IMREAD_GRAYSCALE )
v1 = cv2.Canny(img, 80, 150)
v2 = cv2.Canny(img, 50, 100)
cv2.imshow('init',img)
cv2.imshow('v1', v1)
cv2.imshow('v2', v2)
cv2.waitKey(0)
cv2.destroyAllWindows()

结果显示

使用不同的minval和maxval双阈值,能够得到不同的边缘效果。

自定义Canny边缘检测

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值