边缘检测

边缘检测算法一般基于图像强度的一阶和二阶导数进行计算,这些导数通常对噪声很敏感,因此在检测前一般会对图像进行平滑去噪,参见图像降噪图像滤波

Sobel 算子

Sobel算子,通过计算图像的一阶倒数进行图像边缘检测。

检测步骤:

  1. 假定输入图像矩阵为 I I I,卷积核大小为 3 × 3 3 \times 3 3×3,分别计算图像的水平一阶导数 G x Gx Gx 和垂直一阶导数 G y Gy Gy
    G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ I G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] ∗ I \quad G_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \\ \end{bmatrix} * I \qquad G_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \\ \end{bmatrix} * I Gx=121000121IGy=101202101I

  2. 对输出 G x Gx Gx G y Gy Gy梯度强度合并为图像梯度 G G G
    G = G x 2 + G y 2 \quad G = \sqrt{G_{x}^2 + G_{y}^2 } \qquad G=Gx2+Gy2
    Sobel 算子计算时,简化为:
    G = ∣ G x ∣ + ∣ G y ∣ \qquad G = |G_x| + |G_y| G=Gx+Gy

函数原型:

def Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)

参数:

  • src:需要处理的原图像

  • ddepth:输出图像的深度

  • dx:x 方向上的差分阶数

  • dy:y方向上的差分阶数

  • dst:返回边缘图像

  • ksize: 默认值3,表示Sobel核的大小;必须取1,3,5或7。

  • scale:计算导数值时可选的缩放因子,默认值是1,没有应用缩放

  • delta:表示在结果存入目标图之前可选的delta值,有默认值0。

  • borderType:边界模式,默认值为BORDER_DEFAULT

返回:检测出的边缘图像

dx 和 dy 表示阶数,一般取 0 或 1,但不超过 2

Scharr 卷积核

当卷积核大小为 3x3 时,使用 sobel 卷积核来计算并不是很精确,此时常用 Scharr 卷积核来代替,如下:

G x = [ − 3 0 3 − 10 0 10 − 3 0 3 ] G y = [ − 3 − 10 − 3 0 0 0 3 10 3 ] \quad G_x = \begin{bmatrix} -3 & 0 & 3 \\ -10 & 0 & 10 \\ -3 & 0 & 3 \\ \end{bmatrix}\qquad G_y = \begin{bmatrix} -3 & -10 & -3 \\ 0 & 0 & 0 \\ 3 & 10 & 3 \\ \end{bmatrix} Gx=31030003103Gy=30310010303

而 Sharr 函数,本质上就是令 ksize = 3 且使用 Scharr 卷积核的 Sobel 函数。

函数原型:

def Scharr(src, ddepth, dx, dy, dst=None, scale=None, delta=None, borderType=None)

参数:

  • src:需要处理的原图像

  • ddepth:输出图像的深度

  • dx:x 方向上的差分阶数

  • dy:y方向上的差分阶数

  • dst:返回边缘图像

  • scale:计算导数值时可选的缩放因子,默认值是1,没有应用缩放

  • delta:表示在结果存入目标图之前可选的delta值,有默认值0。

  • borderType:边界模式,默认值为BORDER_DEFAULT

返回:检测出的边缘图像

Laplace 算子

Sobel 算子和Laplace算子都可以进行边缘检测,不同之处在于,前者求一阶导,后者求二阶导。

Laplace算子的计算方式如下:
L a p l a c e ( f ) = ∂ 2 f ∂ x 2 + ∂ 2 f ∂ y 2 \quad Laplace(f) = \frac{\partial^2f}{\partial x^2} + \frac{\partial^2f}{\partial y^2} Laplace(f)=x22f+y22f

表示为离散形式:

L a p l a c e ( f ) = f ( x + 1 , y ) + f ( x − 1 , y ) + f ( x , y + 1 ) + f ( x , y − 1 ) − 4 f ( x , y ) \quad Laplace(f) = f(x+1, y) + f(x-1, y) + f(x, y+1) + f(x, y-1) - 4f(x, y) Laplace(f)=f(x+1,y)+f(x1,y)+f(x,y+1)+f(x,y1)4f(x,y)

而当ksize=1时,Laplacian 函数采用以下 3 × 3 3 \times 3 3×3的卷积核:

[ 0 1 0 1 − 4 1 0 1 0 ] \quad \begin{bmatrix} 0 & 1 & 0 \\ 1 & -4 & 1 \\ 0 & 1 & 0\\ \end{bmatrix}\qquad 010141010

函数原型:

def Laplacian(src, ddepth, dst=None, ksize=None, scale=None, delta=None, borderType=None)

参数:

  • src:需要处理的原图像,单通道8位灰度图

  • ddept:目标图像的深度

  • dst:输出的边缘图

  • ksize:用于计算二阶导数的卷积核大小,必须为正奇数,默认值1

  • scale:计算拉普拉斯值的时候可选的比例因子,默认值1

  • delta:表示在结果存入目标图之前可选的delta值,默认值0

  • borderType:边界模式,默认值为BORDER_DEFAULT

返回:检测出的边缘图像

Canny 边缘检测

检测步骤:

  1. 对平滑后的图像使用Sobel算子计算水平方向和竖直方向的一阶导数 G x Gx Gx G y Gy Gy
    G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] \quad G_x = \begin{bmatrix} -1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \\ \end{bmatrix} \qquad G_y = \begin{bmatrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \\ \end{bmatrix} Gx=121000121Gy=101202101
    根据Gx、Gy梯度图计算整体的梯度强度和角度方向:
    G = G x 2 + G y 2 θ = arctan ⁡ ( G y G x ) \quad G = \sqrt{G_{x}^2 + G_{y}^2 } \qquad \theta = \arctan(\dfrac{ G_y }{ G_x }) G=Gx2+Gy2 θ=arctan(GxGy)
    角度方向近似为四个可能值,即: 0, 45, 90, 135

  2. 对图像的梯度强度进行非极大抑制,只有候选边缘点被保留,其余的点被移除,细化图像边缘。

  3. 使用两个滞后阀值minVal和maxVal检测和连接边缘。灰度梯度高于maxVal的候选点被认为是边界点,低于minVal的候选点会被抛弃。介于两者之间的候选点,如果与边界点相连,就认为它也是边界点,如果不是就抛弃。

  4. 通过抑制孤立的弱边缘最终完成边缘检测。

函数原型:

def Canny(image, threshold1, threshold2, edges=None, apertureSize=None, L2gradient=None)

参数:

  • image:原图像,单通道8位灰度图

  • threshold1:第一个滞后阈值

  • threshold2:第二个滞后阈值

  • edges:返回边缘图像

  • apertureSize:Sobel算子的卷积核大小

  • L2gradient:默认值false,如果为真,则使用更精确的L2范数进行计算(即两个方向的倒数的平方和再开放),否则使用L1范数(直接将两个方向导数的绝对值相加)。

返回:检测出的边缘图像

检测效果对比

卷积核 k s i z e = 3 ksize = 3 ksize=3时:

卷积核 k s i z e = 5 ksize = 5 ksize=5时:

import cv2

def edge_detect(x):
    threshold = cv2.getTrackbarPos('threshold', 'edgeDetect')
    kSize = cv2.getTrackbarPos('kSize', 'edgeDetect')

    if kSize % 2 == 0 or kSize < 3:
        return

    canny = cv2.Canny(blur, threshold, threshold * 3, apertureSize=kSize)

    sobel_x = cv2.Sobel(blur, -1, 1, 0, None, kSize)
    sobel_y = cv2.Sobel(blur, -1, 0, 1, None, kSize)
    sobel_x = cv2.convertScaleAbs(sobel_x)
    sobel_y = cv2.convertScaleAbs(sobel_y)
    sobel = cv2.addWeighted(sobel_x, 1, sobel_y, 1, 0)

    laplacian = cv2.Laplacian(blur, -1, None, kSize)
    laplacian = cv2.convertScaleAbs(laplacian)

    scharr_x = cv2.Scharr(blur, -1, 1, 0)
    scharr_y = cv2.Sobel(blur, -1, 0, 1)
    scharr_x = cv2.convertScaleAbs(scharr_x)
    scharr_y = cv2.convertScaleAbs(scharr_y)
    scharr = cv2.addWeighted(scharr_x, 1, scharr_y, 1, 0)

    cv2.imshow('canny', canny)
    cv2.imshow('sobel', sobel)
    cv2.imshow('laplacian', laplacian)
    cv2.imshow('scharr', scharr)


threshold = 42
kSize = 3

img = cv2.imread("./91_frame.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)

cv2.namedWindow('edgeDetect')
cv2.imshow('edgeDetect', img)
cv2.createTrackbar('threshold', 'edgeDetect', threshold, 100, edge_detect)
cv2.createTrackbar('kSize', 'edgeDetect', kSize, 7, edge_detect)

edge_detect(0)
if cv2.waitKey(0) == 27:
    cv2.destroyAllWindows()
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值