1. 概述
1.1 边缘检测的目的
边缘检测是图像处理与计算机视觉中的重要技术之一,目的是检测识别出数字图像中亮度变化剧烈的像素点构成的集合。
1.2 锐度
锐度的提高会使图像像素在不增加的基础上造成提高清晰度的假象。
提高锐度(也就是锐化)就是把边缘的对比度提高。
图像锐化处理的目的是为了使图像的边缘、轮廓以及图像的细节变得清晰。
图像锐化的方法分为高通滤波和空域微分法。
1.3 边缘检测分类
边缘检测算子是利用图像边缘的突变性质来检测边缘的,通常情况下将边缘检测分为以下三个类型:
- 一阶微分为基础的边缘检测,通过计算图像的梯度值来检测图像边缘,如Sobel算子、Prewitt算子、Roberts算子及差分边缘检测;
- 二阶微分为基础的边缘检测,通过寻求二阶导数中的过零点来检测边缘,如拉普拉斯算子、高斯拉普拉斯算子、Canny算子边缘检测;
- 混合一阶与二阶微分为基础的边缘检测,综合利用一阶微分与二阶微分特征,如Mar_Hildreth边缘检测算子。
2. 边缘检测研究的历史现状
目前仍然存在的问题:一是没有一种普遍使用的检测算法;二是没有一个好的通用的检测评价标准。
边缘检测的研究有几个明显的趋势:
- 对原有算法的不断改进;
- 新方法、新概念的引入和多种方法的有效综合利用;
- 交互式检测研究的深入。如对医学图像的分析。
- 对特殊图像的边缘检测的研究越来越得到重视。对计算机断层扫描(CT)、核磁共振、共聚焦激光扫描显微镜图像等特殊图像的边缘检测技术的研究;
- 对图像边缘检测评价的研究和对评价系数的研究越来越得到关注。
3. 边缘定义及类型概念
边缘是指图像周围像素灰度有阶跃变化或屋顶状变化的像素集合。
边缘具有方向和幅度两个特征,沿边缘走向,像素值变化比较平缓,垂直于边缘走向,像素值变化比较剧烈,可能呈现阶跃状,也可能呈现斜坡状。
边缘可以分为两种,一种是阶跃性边缘,两边的像素灰度值有着明显的不同;另一种为屋顶状边缘,位于灰度值从增加到减少的变化转折点。对于阶跃性边缘,二阶方向导数在边缘处成零交叉,对于屋顶状边缘,二阶方向导数在边缘处取极值。
在图(a)中,对灰度值剖面的一阶导数在图像由暗变明的位置处有一个向上的阶跃,在其他位置为零。这表明可用一阶导数的幅度值来检测边缘的存在,幅度峰值一般对应边缘位置。对灰度值剖面的二阶导数在一阶导数的阶跃上升区有一个向上的脉冲,在一阶导数阶跃下降区有一个向下的脉冲。在这两个阶跃之间有一个过零点,它的位置正对应原始图像中边缘的位置,所以可用二阶导数过零点检测边缘位置,而二阶导数在过零点附近的符号确定边缘像素在图像边缘的暗区或明区。
4. 梯度的概念
梯度是函数变化的一种度量,一幅图像可以看作是图像强度连续函数的取样点序列。
梯度是一阶导数的二维等效式,定义为矢量:
有两个重要的性质与梯度有关:
- 矢量 的方向就是函数
- 增大时的最大变化率方向; 梯度的幅值由下面公式给出:
对于数字图像,最简单的梯度近似表达式为:
5. 图像边缘检测的应用
生物医学工程方面的应用:
CT技术;医用显微图像的处理分析,比如红细胞/白细胞分类检测、染色体边缘分析、癌细胞特征识别等都要用到边缘的判别。
此外,在X光肺部图像增强、超声波图像边缘检测、心电图分析、立体定向仿射治疗等医学诊断方面,都广泛地应用了图像边缘分析处理技术。
6. 边缘检测方法的不足
Roberts算子:简单直观,对具有陡峭的低噪声图像的响应最好,但边缘检测图里有伪边缘;
Sobel算子和Prewitt算子:能检测更多的边缘,但也存在伪边缘且检测出来的边缘线比较粗,放大了噪声;
拉普拉斯算子和改进的拉普拉斯算子:利用二阶差分来进行检测,但是受噪声的影响比较大,且会丢失一些边缘,有一些边缘不够连续,对噪声敏感且不能获得边缘方向等信息。
7. 边缘检测的基本思想
边缘检测的基本思想就是利用边缘增强算子对边缘检测突出的边缘进行检测,然后定义图像中的边缘强度,通过设置阈值强度来提取边缘点。
最理想的边缘检测应该就是能够正确解决边缘有无真假和定位的。
介绍一些术语:
- 边缘点:图像中灰度显著变化的点。
- 边缘段:边缘点坐标及方向的总和,边缘的方向可以是梯度角。
- 轮廓:边缘列表,或者是一条边缘列表的曲线模型。
- 边缘检测器:从图像抽取边缘(边缘点或边线段)集合的算法。
- 边缘连接:从无序边缘形成有序边缘表的过程。
- 边缘跟踪:一个用来确定轮廓图像(滤波后的图像)的搜索过程。
要做好边缘检测,初步准备条件如下:
- 清楚待检测的图像特性变化的形式,使用适应这种变化的检测方法。
- 当需要提取更多空间范围内的变化特征时,需要考虑多种算子的综合应用。
- 要考虑噪声的影响,通过滤波器将噪声进行滤除。
- 可以考虑各种方法的结合。
- 在正确的图像边缘检测的基础上,要考虑定位精确的问题。
8. 图像边缘检测的步骤
边缘检测检测分为彩色图像边缘检测和灰度图像边缘检测两种。如果输入的是彩色图像p(x , y),就可以利用公式对彩色图像进行灰度图像处理:p(x , y) = 0.3R + 0.59G + 0.11B。
图像边缘检测主要包括以下五个步骤:
(1) 图像获取:先进行图像的获取,再根据相应的条件转化为灰度图像,进而进行分析。
(2) 图像滤波:必须使用滤波器来改善与噪声有关的边缘检测器的性能。
(3) 图像增强:增强边缘的基础是确定图像各点邻域强度的变化值。
(4) 图像检测:最简单的边缘检测判据是梯度幅值阈值判据。
(5) 图像定位:图像边缘定位是对边缘图像处理后得到单像素的二值边缘图像,常使用的技术是阈值法和零交叉法。
一般来说对检测出的边缘有以下几个要求:
- 边缘的定位精度要高;
- 检测的响应最最好是单像素的;
- 对不同尺度的边缘都能够较好地响应并尽可能减少漏检;
- 边缘检测对噪声不敏感;
- 检测灵敏度受边缘的方向影响小。
9. 经典图像边缘检测算法
边缘检测的实质是采用某种算法来提取出图像中对象与背景间的交界线。
经典的边缘检测方法是对原始图像中像素的某个邻域来构造边缘检测算子,其过程如下图所示:
9.1 Roberts算子
Roberts算子又称为交叉微分算法,是基于交叉差分的梯度算法,通过局部差分计算检测边缘线条。
常用来处理具有陡峭的低噪声图像,当图像边缘接近于正45度或负45度时,该算法处理效果更理想。
其缺点是对边缘的定位不太准确,提取的边缘线条较粗。
Roberts算子的模板分为水平方向和垂直方向,如下如:
实现Roberts算子主要通过OpenCV中的filter2D函数来完成。这个函数的主要功能是通过卷积核实现对图像的卷积运算,声明如下:
def filter2D(src, ddepth, kernel, dst = None, anchor = None, delta = None, borderType = None)
- src:输入图像;
- ddepth:表示目标图像所需的深度;
- kernel:表示卷积核。
代码实例:Roberts算子边缘检测
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread('test.jpg', cv.COLOR_BGR2GRAY)
# cv.COLOR_BGR2GRAY将BGR图像转换为灰度图像
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Roberts算子的两个卷积核kernelx和kernely,分别用于检测水平和垂直方向的边缘。
kernelx = np.array([[-1, 0], [0, 1]], dtype=int)
kernely = np.array([[0, -1], [1, 0]], dtype=int)
# 使用cv.filter2D函数对灰度图像进行卷积操作,得到水平和垂直方向的梯度图像。
x = cv.filter2D(grayImage, cv.CV_16S, kernelx)
y = cv.filter2D(grayImage, cv.CV_16S, kernely)
# 将卷积后的图像数据转换为绝对值,并转换为uint8类型,以便于显示。
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
# 将两个方向的梯度图像融合,得到最终的Roberts算子边缘检测图像。
Roberts = cv.addWeighted(absX, 0.5, absY, 0.5, 0)
# 显示图形
titles = ['src', 'Roberts operator']
images = [rgb_img, Roberts]
for i in range(2):
# 使用matplotlib的subplot和imshow函数显示原始图像和Roberts算子处理后的图像
plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
代码效果图:
9.2 Sobel算子边缘检测
Sobel算子(索贝尔算子)利用像素上、下、左、右邻域的灰度加权算法,根据在边缘点处达到极值这一原理进行边缘检测。
该方法不但产生较好的检测效果,而且对噪声具有平滑作用,可以提供较为精确的边缘方向信息。缺点是Sobel算子并没有将图像的主题和背景严格区分开。
使用Sobel边缘检测算子提取图像边缘的过程大致可以分为以下三个步骤:
- 提取x方向的边缘,x方向一阶Sobel边缘检测算子如下图1所示;
- 提取y方向的边缘,y方向一阶Sobel边缘检测算子如下图2所示;
- 综合两个方向的边缘信息得到整幅图像的边缘。
图1 图2
由两个方向的边缘得到整体的边缘由两种计算方式:一种是求取两幅图像对应像素的像素值的绝对值之和;另一种是求取两幅图像对应像素的像素值的平方和的二次方根。如下:
总梯度:
简化梯度:
OpenCV提供了对图像提取Sobel边缘的Sobel函数,该函数声明如下:
Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) → dst
- src:表示待提取边缘的图像;
- dst:表示输出图像,与输入图像src具有相同的尺寸和通道数,数据类型由第三个参数ddepth表示输出图像的数量类型;
- dx:表示x方向的差分阶数;
- dy:表示y方向的差分阶数;
- ksize:表示Sobel边缘算子的尺寸,必须是1、3、5、或者7;
- scale:表示对导数计算结果进行缩放的缩放因子,默认系数为1,不进行缩放;
- dekta:表示偏值,在计算结果中加上偏值;
- borderType:表示像素外推法选择标志,默认参数为BORDER_DEFAULT,表示不包含边界值倒序填充。
当对精度要求不是很高时,Sobel算子是一种常用的边缘检测方法。
代码实例:Sobel算子边缘检测
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread('test.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 使用cv.Sobel函数计算图像的水平和垂直方向的梯度
# cv.CV_16S指定数据类型为16位有符号整数。
x = cv.Sobel(grayImage, cv.CV_16S, 1, 0)
y = cv.Sobel(grayImage, cv.CV_16S, 0, 1)
# 将计算得到的梯度图像转换为绝对值,并转换为uint8类型,以便显示。
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
# 将水平和垂直方向的梯度图像融合,得到最终的Sobel算子边缘检测图像。
Sobel = cv.addWeighted(absX, 0.5, absY, 0.5, 0)
# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = ['原始图像', 'Sobel 算子']
images = [rgb_img, Sobel]
for i in range(2):
plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
代码效果图:
9.3 Prewitt算子边缘检测
Prewitt边缘算子是一种边缘样板算子。由理想的边缘算子图像构成,依次用边缘样板去检测图像,与被检测区域最为相似的样板给出最大值,用这个最大值作为算子的输出。
Prewitt算子和Sobel差不多,利用像素点上下、左右邻点灰度差,在边缘处达到极值检测边缘。其对噪声具有平滑作用,定位精度不够高。
相比Roberts算子,Prewitt算子对噪声有抑制作用,卷积核如下图所示。
Prewitt抑制噪声的原理是通过像素平均,因此噪声较多的图像处理得比较好。但是像素平均相当于对图像得低通滤波,所以Prewitt算子对边缘得定位不如Roberts算子。
代码实例:Prewitt算子边缘检测
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread('test.jpg', cv.COLOR_BGR2GRAY)
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
# 灰度化处理图像
grayImage = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# Prewitt 算子
kernelx = np.array([[1,1,1],[0,0,0],[-1,-1,-1]],dtype=int)
kernely = np.array([[-1,0,1],[-1,0,1],[-1,0,1]],dtype=int)
# 使用cv.filter2D函数对灰度图像进行卷积操作,得到水平和垂直方向的梯度图像。
x = cv.filter2D(grayImage, cv.CV_16S, kernelx)
y = cv.filter2D(grayImage, cv.CV_16S, kernely)
# 转 uint8 ,图像融合
absX = cv.convertScaleAbs(x)
absY = cv.convertScaleAbs(y)
# 将两个方向的梯度图像融合
Prewitt = cv.addWeighted(absX, 0.5, absY, 0.5, 0)
# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = ['原始图像', 'Prewitt 算子']
images = [rgb_img, Prewitt]
for i in range(2):
plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
代码效果图:
9.4 LoG边缘检测算子
该算法首先对图像做高斯滤波,然后求其拉普拉斯(Laplacian)二阶导数,即图像与Laplacian of the Gaussian function 进行滤波运算。
LoG算子也就是高斯拉普拉斯函数,常用于数字图像的边缘提取和二值化。首先对原始图像进行最佳平滑处理,最大限度地抑制噪声,再对平滑后的图像求取边缘。
该算法的主要思路和步骤:滤波、增强、检测。
具体的内容我拍照上传一下:
代码实例图:LoG算子边缘检测
import cv2 as cv
import matplotlib.pyplot as plt
# 读取图像
img = cv.imread("test.jpg")
rgb_img = cv.cvtColor(img, cv.COLOR_BGR2RGB)
gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 先通过高斯滤波降噪
gaussian = cv.GaussianBlur(gray_img, (3, 3), 0)
# 再通过拉普拉斯算子做边缘检测,cv.Laplacian函数计算图像的二阶导数
dst = cv.Laplacian(gaussian, cv.CV_16S, ksize=3)
LOG = cv.convertScaleAbs(dst)
# 用来正常显示中文标签
plt.rcParams['font.sans-serif'] = ['SimHei']
# 显示图形
titles = ['原始图像', 'LOG 算子']
images = [rgb_img, LOG]
for i in range(2):
plt.subplot(1, 2, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
plt.show()
代码效果图:
9.5 边缘检测的最新技术与方法
- 基于小波与分形理论边缘检测技术
- 基于数学形态学的边缘检测技术
- 基于模糊学的边缘检测技术
- 基于遗传算法的边缘检测技术
- 基于神经网络的边缘检测技术
参考学习书总结:OpenCv4.5 计算机视觉开发实战(基于python)
代码来自书本,供自己学习复习使用,继续学习ing...
标签:plt,检测,图像,边缘,算子,视觉,cv From: https://blog.csdn.net/KingGodZ/article/details/141277471