欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

图像处理之边缘检测

程序员文章站 2022-03-29 22:47:59
...

边缘检测步骤

①滤波:边缘检测算法主要是基于图像强度的一阶和二阶导数,但导数的计算对噪声很敏感,因此必须使用滤波器来改善与噪声有关的边缘检测器的性能。需要指出,大多数滤波器在降低噪声的同时也导致了边缘强度的损失,因此,增强边缘和降低噪声之间需要折中。
②增强:增强边缘的基础是确定图像各点邻域强度的变化值。增强算法可以将邻域(或局部)强度值有显著变化的点突显出来。边缘增强一般是通过计算梯度幅值来完成的。
③检测:在图像中有许多点的梯度幅值比较大,而这些点在特定的应用领域中并不都是边缘,所以应该用某种方法来确定哪些点是边缘点。最简单的边缘检测判据是梯度幅值阈值判据。
④定位:如果某一应用场合要求确定边缘位置,则边缘的位置可在子像素分辨率上来估计,边缘的方位也可以被估计出来。在边缘检测算法中,前三个步骤用得十分普遍。这是因为大多数场合下,仅仅需要边缘检测器指出边缘出现在图像某一像素点的附近,而没有必要指出边缘的精确位置或方向。

边缘检测基础知识

边缘模型

图像处理之边缘检测

一阶导数和二阶导数

作用
  • 一阶导数通常在图像中产生较粗的边缘;
  • 二阶导数对精细细线,如细线、孤立点和噪声有较强的响应;
  • 二阶导数在灰度斜坡和灰度台阶过渡出会产生双边响应;
  • 二阶导数的符号可以用于确定边缘的过渡是从亮到暗还是从暗到亮

图像处理之边缘检测
并且我们可以得出结论:一阶导数的幅度可用于检测图像中的某个点是否存在一个边缘,二阶导数可以用于确定一个边缘像素位于该边缘的暗的一侧还是亮的一侧。

那么这是理想情况下的图片边缘,如果图片有噪声的话,其边缘函数则为
图像处理之边缘检测
微弱的可见噪声对检测边缘所用的两个关键导数的严重影响的这一事实,是我们应记住的一个重要问题。特别地,在类似于我们刚刚讨论的水平的噪声很可能存在的应用中,使用导数之前的图像平滑处理是应该认真考虑的问题。

计算一阶导数

许多边缘检测操作都是基于亮度的一阶导数——这样就得到了原始数据亮度的梯度。使用这个信息我们能够在图像的亮度梯度中搜寻峰值。如果 I(x) 表示点 x 的亮度,I′(x) 表示点 x 的一阶导数(亮度梯度),这样我们就会发现:
图像处理之边缘检测
对于更高性能的图像处理来说,一阶导数能够通过带有掩码的原始数据(1维)卷积计算得到。
图像处理之边缘检测

计算二阶导数

其它一些边缘检测操作是基于亮度的二阶导数。这实质上是亮度梯度的变化率。在理想的连续变化情况下,在二阶导数中检测过零点将得到梯度中的局部最大值。另一方面,二阶导数中的峰值检测是边线检测,只要图像操作使用一个合适的尺度表示。如上所述,边线是双重边缘,这样我们就可以在边线的一边看到一个亮度梯度,而在另一边看到相反的梯度。这样如果图像中有边线出现的话我们就能在亮度梯度上看到非常大的变化。为了找到这些边线,我们可以在图像亮度的二阶导数中寻找过零点。如果 I(x) 表示点 x 的亮度,I′′(x) 表示点 x 亮度的二阶导数,那么:
图像处理之边缘检测
同样许多算法也使用卷积掩码快速处理图像数据:
图像处理之边缘检测

边缘检测算子

一阶::Roberts Cross算子,Prewitt算子,Sobel算子, Kirsch算子,罗盘算子;
二阶: Marr-Hildreth,在梯度方向的二阶导数过零点,Canny算子,Laplacian算子。

Roberts算子

图像处理之边缘检测

Prewitt算子

图像处理之边缘检测

Sobel算子

图像处理之边缘检测
检测对角边缘的Prewitt和Sobel模板
图像处理之边缘检测
图像处理之边缘检测

空间滤波器

平滑滤波器用于模糊处理和降低噪声。模糊处理经常用于预处理任务中,例如在目标提取之前去除图像中的一些琐碎细节。

平滑空间滤波器

平滑线性滤波器
滑线性空间滤波器的输出(响应)是包含在滤波器过滤核中像素的简单平均值,也成为均值滤波。
这种处理的结果降低了图像灰度的“尖锐”变化。
图像处理之边缘检测
图像处理之边缘检测

import cv2
import numpy as np

img = cv2.imread('images/cat.jpg')
cv2.imshow('images',img)
"""
blur—图像均值平滑滤波
函数原型:blur(src, ksize, dst=None, anchor=None, borderType=None)
src:图像矩阵
ksize:滤波窗口尺寸
"""
res = cv2.blur(img, (3, 3))
cv2.imshow('res', res)
"""
GaussianBlur—图像高斯平滑滤波
函数原型:GaussianBlur(src, ksize, sigmaX, dst=None, sigmaY=None, borderType=None)
src:图像矩阵
ksize:滤波窗口尺寸
sigmaX:标准差

"""
res2 = cv2.GaussianBlur(img,(3,3),0)
cv2.imshow('res2', res2)
cv2.waitKey()

图像处理之边缘检测
非线性滤波器
这种滤波器的响应一滤波器过滤核中像素的排序为基础,然后使用统计排序的结果决定代替中心像素的值。这一类最知名的滤波器是中值滤波器,正如其名,它是将像素领域内灰度的中值代替该像素的值。中值滤波器对处理脉冲噪声非常有效。

import cv2
import numpy as np

img = cv2.imread('images/lena_1.jpg')
cv2.imshow('img', img)
"""
medianBlur—图像中值滤波
函数原型:medianBlur(src, ksize, dst=None)
src:图像矩阵
ksize:滤波窗口尺寸

"""
res = cv2.medianBlur(img, 5)
cv2.imshow('res', res)
cv2.waitKey()

图像处理之边缘检测

锐化空间滤波器

使用二阶微分进行图像锐化——拉普拉斯算子
图像处理之边缘检测
由于拉普拉斯是一种微分算子,因此其应用强调的是图像中灰度的突变,并不强调灰度级缓慢变化的区域。将原图像和拉普拉斯图像叠加在一起的简单方法,可以复原背景特性并保持拉普拉斯锐化处理的效果。

如果所使用的定义具有负的中心系数,那么必须将原图像减去拉普拉斯变换后的图像而不是加上它,从而得到锐化的结果

import cv2
import numpy as np
img = cv2.imread('images/lena.jpg')
cv2.imshow('img',img)
kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]], np.float32)
#kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
dst = cv2.filter2D(img, -1, kernel=kernel)
cv2.imshow('res',dst)
cv2.waitKey(0)

图像处理之边缘检测
使用一阶微分对(非线性)图像锐化——梯度
图像处理之边缘检测

# coding=utf-8
import cv2


img = cv2.imread("images/lena.jpg")
cv2.imshow('img',img)
"""
Sobel函数
Sobel(src, ddepth, dx, dy, dst=None, ksize=None, scale=None, delta=None, borderType=None)
前四个是必须的参数:
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
第三和第四:dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为012。
其后是可选的参数
"""
x = cv2.Sobel(img, -1, 0, 1)
cv2.imshow('res',x)
cv2.waitKey(0)

图像处理之边缘检测

成熟先进的边缘检测技术

Marr-Hildreth边缘检测器

图像处理之边缘检测
图像处理之边缘检测
Marr-Hildreth算法小结

用一个G(x,y)取样得到的nxn的高斯高斯低通滤波器对输入图像滤波。

-计算由第一步得到的图像的拉普拉斯
-找到步骤2所有图像的零交叉
-零交叉是Marr-Hildreth边缘检测方法的关键特征,实现简单,并且通常能给出好的结果。

import numpy as np
import matplotlib.pyplot as plt
import cv2

def edgesMarrHildreth(img, sigma):
    """
        finds the edges using MarrHildreth edge detection method...
        :param im : input image
        :param sigma : sigma is the std-deviation and refers to the spread of gaussian
        :return:
        a binary edge image...
    """
    size = int(2 * (np.ceil(3 * sigma)) + 1)

    x, y = np.meshgrid(np.arange(-size / 2 + 1, size / 2 + 1), np.arange(-size / 2 + 1, size / 2 + 1))

    normal = 1 / (2.0 * np.pi * sigma ** 2)

    kernel = ((x ** 2 + y ** 2 - (2.0 * sigma ** 2)) / sigma ** 4) * np.exp(
        -(x ** 2 + y ** 2) / (2.0 * sigma ** 2)) / normal  # LoG filter

    kern_size = kernel.shape[0]
    log = np.zeros_like(img, dtype=float)

    # applying filter
    for i in range(img.shape[0] - (kern_size - 1)):
        for j in range(img.shape[1] - (kern_size - 1)):
            window = img[i:i + kern_size, j:j + kern_size] * kernel
            log[i, j] = np.sum(window)

    log = log.astype(np.int64, copy=False)

    zero_crossing = np.zeros_like(log)

    # computing zero crossing
    for i in range(log.shape[0] - (kern_size - 1)):
        for j in range(log.shape[1] - (kern_size - 1)):
            if log[i][j] == 0:
                if (log[i][j - 1] < 0 and log[i][j + 1] > 0) or (log[i][j - 1] < 0 and log[i][j + 1] < 0) or (
                        log[i - 1][j] < 0 and log[i + 1][j] > 0) or (log[i - 1][j] > 0 and log[i + 1][j] < 0):
                    zero_crossing[i][j] = 255
            if log[i][j] < 0:
                if (log[i][j - 1] > 0) or (log[i][j + 1] > 0) or (log[i - 1][j] > 0) or (log[i + 1][j] > 0):
                    zero_crossing[i][j] = 255

                # plotting images
    fig = plt.figure()
    a = fig.add_subplot(1, 2, 1)
    imgplot = plt.imshow(log, cmap='gray')
    a.set_title('Laplacian of Gaussian')
    a = fig.add_subplot(1, 2, 2)
    imgplot = plt.imshow(zero_crossing, cmap='gray')
    string = 'Zero Crossing sigma = '
    string += (str(sigma))
    a.set_title(string)
    plt.show()

    return zero_crossing

img = cv2.imread('images/17.jpg',0)
img = edgesMarrHildreth(img,4)

图像处理之边缘检测

坎尼边缘检测Canny

Canny目标
-低错误率。所有边缘都应被找到,并且应该没有伪相应,也就是检测到的边缘必须尽可能是真是的边缘
-边缘点应被很好的定位。已定位边缘必须尽可能接近真实边缘。也就是由检测器标记为边缘的点和真实边缘的中心之间的距离应该最小
-单一的边缘点响应。对于真实的边缘点,检测器仅应返回一个点。也就是真是边缘周围的局部最大数应该是最小的。这意味着在仅存一个单一边缘点到额位置,检测器不应指出多个边缘像素。
Canny算法步骤
1、用一个高斯滤波器平滑输入图像
图像处理之边缘检测
2、计算梯度幅度图像和角度图像
图像处理之边缘检测
3、对梯度幅度图像应用非最大抑制
图像处理之边缘检测
4、用双阈值处理和连接分析来检测并连接边缘(这相对Marr-Hildreth优化了边缘的连接使得检测的边缘更加完整)
图像处理之边缘检测

# coding=utf-8
import cv2
import numpy as np

img = cv2.imread("images/17.jpg", 0)
cv2.imshow('img',img)
img = cv2.GaussianBlur(img, (3, 3), 0)
canny = cv2.Canny(img, 50, 150)

cv2.imshow('Canny', canny)
cv2.waitKey(0)
cv2.destroyAllWindows()

图像处理之边缘检测
可以看到,Canny算法明显提取边缘的效果要优于Marr-Hildreth算法,对边缘的连接也做的更好。

相关标签: 边缘检测