数字图像处理与Python实现-边缘检测-高斯拉普拉斯算子(LoG)算子边缘检测

时间:2024-10-05 16:32:31

高斯拉普拉斯算子(LoG)算子边缘检测

  • 高斯拉普拉斯算子(LoG)算子边缘检测
    • 1. 前言
    • 2. 高斯拉普拉斯算子(LoG)算子描述
    • 3. 代码实现

1. 前言

在图像中,灰度或结构等信息的突变处称为边缘。边缘可以看作一个区域的结束,另一个区域的开始。利用边缘的特征,可以对图像进行分割。根据定义可以知道,利用各种算法检测到的边缘,并不代表目标的实际边缘。由于图像是二维的,而目标实物是三维的,从三维到二维的投影,已经造成了信息的丢失,再加上成像过程受光照、噪声的影响,使得有边缘的地方不一定被检测出来,而检测出来的边缘也不一定代表实际边缘。
图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈。因此,利用图像边缘的变化特性,通过微分算子可以将边缘检查出来,通常用一阶或二阶导数来检测边缘。一阶导数以最大值对应边缘位置,二阶导数以过零点为边缘位置。

2. 高斯拉普拉斯算子(LoG)算子描述

利用二阶导数的零交叉点来检测边缘点的算法对噪声非常敏感,因此在增强边缘前对图像降噪是十分必要的,高斯拉普拉斯(LoG)边检算子正是基于这种需要提出的。在20世纪70年代,Marr理论根据神经生理学实验得出了以下结论:物体的边界是将亮度图像与其解释连接起来的最重要线索,并且符合人类视觉特性。
高斯拉普拉斯算子(LoG)算子的数学推导如下:
Laplacian算子边缘检测的数学表达式:
▽ 2 f ( x , y ) = ∂ 2 f ∂ x 2 + ∂ 2 f ∂ y 2 (1) \triangledown^2f(x,y) = \frac{\partial^2 f}{\partial x^2} + \frac{\partial^2f}{\partial y^2} \tag{1} 2f(x,y)=x22f+y22f(1)
一维高斯函数如下:
G σ x = 1 2 π σ 2 e − x 2 2 σ 2 (2) G_{\sigma x} = \frac{1}{\sqrt{2\pi\sigma^2}}e^{-\frac{x^2}{2\sigma^2}} \tag{2} Gσx=2πσ2 1e2σ2x2(2)
二维高函数如下:
G σ ( x , y ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 (3) G_{\sigma(x,y)} = \frac{1}{2\pi\sigma^2}e^{-\frac{x^2 + y^2}{2\sigma^2}}\tag{3} Gσ(x,y)=2πσ21e2σ2x2+y2(3)
二维高斯函数的一阶偏导数为:
∂ G σ ( x , y ) ∂ x = ( − 1 2 π σ 4 ) x e − x 2 + y 2 2 σ 2 (4) \frac{\partial G_{\sigma(x,y)}}{\partial x} = (-\frac{1}{2\pi\sigma^4})xe^{-\frac{x^2 + y^2}{2\sigma^2}} \tag{4} xGσ(x,y)=(2πσ41)xe2σ2x2+y2(4)
∂ G σ ( x , y ) ∂ y = ( − 1 2 π σ 4 ) y e − x 2 + y 2 2 σ 2 (5) \frac{\partial G_{\sigma(x,y)}}{\partial y} = (-\frac{1}{2\pi\sigma^4})ye^{-\frac{x^2 + y^2}{2\sigma^2}} \tag{5} yGσ(x,y)=(2πσ41)ye2σ2x2+y2(5)
二维高斯函数的一阶梯度为:
▽ G σ ( x , y ) = ∣ ∂ G σ ( x , y ) ∂ x ∣ + ∣ ∂ G σ ( x , y ) ∂ y ∣ (6) \triangledown G_{\sigma(x,y)} = |\frac{\partial G_{\sigma(x,y)}}{\partial x}| + |\frac{\partial G_{\sigma(x,y)}}{\partial y}| \tag{6} Gσ(x,y)=xGσ(x,y)+yGσ(x,y)(6)

二维高斯函数的二阶偏导数为:
∂ 2 G σ ( x , y ) ∂ x 2 = ( − 1 2 π σ 4 ) ( 1 − x 2 σ 2 ) e − x 2 + y 2 2 σ 2 (7) \frac{\partial^2 G_{\sigma(x,y)}}{\partial x^2} = (-\frac{1}{2\pi\sigma^4})(1-\frac{x^2}{\sigma^2})e^{-\frac{x^2 + y^2}{2\sigma^2}} \tag{7} x22Gσ(x,y)=(2πσ41)(1σ2x2)e2σ2x2+y2(7)
∂ 2 G σ ( x , y ) ∂ y 2 = ( − 1 2 π σ 4 ) ( 1 − y 2 σ 2 ) e − x 2 + y 2 2 σ 2 (8) \frac{\partial^2 G_{\sigma(x,y)}}{\partial y^2} = (-\frac{1}{2\pi\sigma^4})(1-\frac{y^2}{\sigma^2})e^{-\frac{x^2 + y^2}{2\sigma^2}} \tag{8} y22Gσ(x,y)=(2πσ41)(1σ2y2)e2σ2x2+y2(8)
二维高斯函数的二阶梯度为:
▽ 2 G σ ( x , y ) = ∣ ∂ 2 G σ ( x , y ) ∂ x 2 ∣ + ∣ ∂ 2 G σ ( x , y ) ∂ y 2 ∣ (9) \triangledown^2 G_{\sigma(x,y)} = |\frac{\partial^2 G_{\sigma(x,y)}}{\partial x^2}| + |\frac{\partial^2 G_{\sigma(x,y)}}{\partial y^2}| \tag{9} 2Gσ(x,y)=x22Gσ(x,y)+y22Gσ(x,y)(9)

方向梯度(角度 θ \theta θ取弧度):
i → = x cos ⁡ θ + y sin ⁡ θ (10) \overrightarrow i = x\cos\theta + y \sin\theta \tag{10} i =xcosθ+ysinθ(10)
一维高斯函数梯度方向:
∂ G x ∂ i → = ∂ G x ∂ x cos ⁡ θ + ∂ G x ∂ y sin ⁡ θ (11) \frac{\partial G_x}{\partial \overrightarrow{i}} = \frac{\partial G_x}{\partial x}\cos\theta + \frac{\partial G_x}{\partial y}\sin\theta \tag{11} i Gx=xGxcosθ+yGxsinθ(11)
二维高斯函数梯度方向:
∂ 2 G σ ( x , y ) ∂ i → 2 = ∂ 2 G σ ( x , y ) ∂ x 2 cos ⁡ 2 θ + ∂ 2 G σ ( x , y ) ∂ y 2 sin ⁡ 2 θ + 2 ∂ 2 G σ ( x , y ) ∂ x ∂ y cos ⁡ θ sin ⁡ θ (12) \frac{\partial^2 G_{\sigma(x,y)}}{\partial \overrightarrow{i}^2} = \frac{\partial^2 G_{\sigma(x,y)}}{\partial x^2}\cos^2\theta + \frac{\partial^2 G_{\sigma(x,y)}}{\partial y^2}\sin^2\theta + 2\frac{\partial^2 G_{\sigma(x,y)}}{\partial x \partial y}\cos\theta\sin\theta \tag{12} i 22Gσ(x,y)=x22Gσ(x,y)cos2θ+y22Gσ(x,y)sin2θ+2xy2Gσ(x,y)cosθsinθ(12)

原图像与高斯核函数卷积后再做Laplace运算:
△ [ G σ ( x , y ) ∗ f ( x , y ) ] = [ △ G σ ( x , y ) ] ∗ f ( x , y ) (13) \triangle[G_{\sigma(x,y)} * f(x,y)] = [\triangle G_{\sigma(x,y)}] * f(x,y) \tag{13} [Gσ(x,y)f(x,y)]=[Gσ(x,y)]f(x,y)(13)
证明如下:
d d t 2 [ h ( t ) ∗ f ( t ) ] = d d t ∫ f ( τ ) h ( t − τ ) d τ = ∫ f ( τ ) d d t 2 h ( t − τ ) d τ = f ( t ) ∗ d d t 2 h ( t ) (14) ddt2[h(t)f(t)]=ddtf(τ)h(tτ)dτ=f(τ)ddt2h(tτ)dτ=f(t)ddt2h(t)

\tag{14} dt2d[h(t)f(t)]=dtdf(τ)h(tτ)dτ=f(τ)dt2dh(tτ)dτ=f(t)dt2dh(t)(14)
展开后得到,
L o G = △ G σ ( x , y ) = ∂ 2 G σ ( x , y ) ∂ x 2 + ∂ 2 G σ ( x , y ) ∂ y 2 = x 2 + y 2 − 2 σ 2 σ 4 e − x 2 + y 2 2 σ 2 (15) LoG = \triangle G_{\sigma(x,y)} = \frac{\partial^2 G_{\sigma(x,y)}}{\partial x^2} + \frac{\partial^2 G_{\sigma(x,y)}}{\partial y^2} = \frac{x^2 + y^2 - 2\sigma^2}{\sigma^4}e^{-\frac{x^2+y^2}{2\sigma^2}} \tag{15} LoG=Gσ(x,y)=x22Gσ(x,y)+y22Gσ(x,y)=σ4x2+y22σ2e2σ2x2+y2(15)
所以,
L o G ∗ f ( x , y ) = x 2 + y 2 − 2 σ 2 σ 4 [ G σ ( x , y ) ∗ f ( x , y ) ] (16) LoG * f(x,y) = \frac{x^2+y^2-2\sigma^2}{\sigma^4}[G_{\sigma(x,y)}*f(x,y)] \tag{16} LoGf(x,y)=σ4x2+y22σ2[Gσ(x,y)f(x,y)](16)
先对高斯核函数求取二阶导数,再与原图像进行卷积操作。由于高斯函数是圆对称的,因此LoG算子可以有效地实现极值点或局部极值区域的检测。

高斯函数、高斯函数的一阶导数、高斯函数的二阶导数分别如下图:
在这里插入图片描述在这里插入图片描述在这里插入图片描述
LoG算子特点是由于先进行了高斯滤波,因而可以一定程度上克服噪声的影响。它的局限性在于以下两个方面:

  • (1)可能产生假边缘(false edges);
  • (2)对一些曲线边缘(curved edges)的定位误差较大。

3. 代码实现

import numpy as np
import matplotlib.pyplot as plt
import scipy
from scipy.signal import convolve2d
import scipy.signal as sgn
import cv2

# 拉普拉斯边缘检查
# @thresh:阈值
# @useThresh:是否使用阈值过滤边缘检查结果
def lapace_edge(src,thresh=20,useThresh=False):
	# 检查图像是否为灰度图像
    assert(len(src.shape) == 2)
    # 拉普拉斯内核
    kernel = np.array([
        [0,1,0],
        [1,-4,1],
        [0,1,0]
    ])
   
    # 卷积运算
    #G = convolve2d(np.float32(src),kernel, boundary='symm', mode='same')
    G = convolve2d(np.float32(src),kernel, boundary='symm', mode='same')
    G = np.abs(G)
    # 按阈值提取
    if useThresh:
        idx = G >= thresh
        G[idx] = src[idx]
        G[~idx] = 0
    else:
        G = np.clip(G,0,255)
    return G.astype(np.uint8)

# 生成高斯卷积核
# 按参数生成高斯卷积核
def gaussian_kernel(size=5, sigma=1.0):
    x, y = np.mgrid[-(size//2):(size//2)+1, -(size//2):(size//2)+1]
    normal = 1 / (2 * np.pi * sigma**2)
    kernel = normal * np.exp(-((x**2 + y**2)/(2 * sigma**2)))
    return kernel

# 图像高斯模糊
def gaussian_blur(src,sigma,truncate=4.0):
    assert(len(src.shape) == 2)
    kernel = gaussian_kernel(sigma,truncate)
    blured = convolve2d(np.float32(src),kernel, boundary='symm', mode='same')
    return np.clip(blured,0,255).astype(np.uint8)

# Log算子边缘检测
def LoG_edge(src,sigma,truncate=4.0):
    blured = gaussian_blur(src,sigma,truncate)
    edged = lapace_edge(blured)
    return edged

def main():
    src = cv2.imread('resources/images/',0)
    dst = LoG_edge(src,2.2)
    # dst_thresh = lapace_edge(src,thresh=20,useThresh=True)
    # dst2 = (src,cv2.CV_8UC1,ksize=3)
    plt.figure()
    plt.subplot(1,2,1)
    plt.imshow(src,'gray')
    plt.title('Source Image')
    plt.xticks([])
    plt.yticks([])
    plt.subplot(1,2,2)
    plt.imshow(dst,'gray')
    plt.title('LoG Edge sigma=2.2')
    plt.xticks([])
    plt.yticks([])

    plt.show()

if __name__ == '__main__':
    main()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

程序运行结果:
在这里插入图片描述