OpenCV学习--基于OpenCV的边缘检测

本节主要学习Opencv中边缘检测的各种算子和滤波器–Canny算子、Sobel算子、Laplacian算子以及Scharr滤波器。本文主要参考《OpenCV3编程入门》一书。
一、边缘检测的一般步骤
I. 滤波
边缘检测的算法主要是基于图像强度的一阶和二阶导数(稍后会介绍原理),但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能(模糊处理)。常用的滤波方法主要有高斯滤波,几采用离散化的高斯函数产生一组归一化的高斯核,然后基于高斯核函数对图像灰度矩阵的每一点进行加权求和。
II. 增强
增强边缘的基础是确定图像各点领域强度的变化值。增强算法可以将图像灰度点领域强度值有显著变化的点凸显出来。可通过计算梯度值来确定。
III. 检测
经过增强的图像,往往邻域中有很多点的梯度值比较大,在特定应用中,这些点不是要找到边缘点,所以应将这些点舍弃,实际工程中最常用的方法是通过阀值化方法来检测。

注:Sobel算子、Laplacian算子以及Scharr滤波器都是带方向的。并且这些滤波函数都会将非边缘区域转换为黑色,将边缘区域转为白色或其他饱和色。
二、图像强度的一阶和二阶导数
边缘(edge)是指图像局部强度变化最显著的部分。主要存在于目标与目标、目标与背景、区域与区域(包括不同色彩)之间,是图像分割、纹理特征和形状特征等图像分析的重要基础。
图像强度的显著变化可分为:
阶跃变化函数,即图像强度在不连续处的两边的像素灰度值有着显著的差异;
线条(屋顶)变化函数,即图像强度突然从一个值变化到另一个值,保持一较小行程后又回到原来的值。
图像的边缘有方向和幅度两个属性,沿边缘方向像素变化平缓,垂直于边缘方向像素变化剧烈.边缘上的这种变化可以用微分算子检测出来,通常用一阶或二阶导数来检测边缘。
OpenCV学习--基于OpenCV的边缘检测_第1张图片
(a)(b)分别是阶跃函数和屋顶函数的二维图像;(c)(d)是阶跃和屋顶函数的函数图像;(e)(f)对应一阶倒数;(g)(h)是二阶倒数。
来自 https://blog.csdn.net/xiaowei_cqu/article/details/7829481

三、Canny算子
Canny边缘检测算子是一个多级边缘检测算法,Canny的目标是找到一个最优的边缘检测算法,其评价标准为:低错误率、高定位性、最小响应。
Canny边缘检测步骤

Canny函数
Python:
edges = cv.Canny( image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]] )
image 源图像,需是单通道8位图像
edges 输出的边缘图像,需和源图像具有一样的大小和类型
threshold1 第一个滞后性阀值,double
threshold2 第二个滞后性阀值,double
apertureSize 应用Sobel算子孔径大小,默认值:3
L2gradient a flag, indicating whether a more accurate L 2 norm =(dI/dx) 2 +(dI/dy) 2 − − − − − − − − − − − − − − − − √ should be used to calculate the image gradient magnitude ( L2gradient=true ), or whether the default L 1 norm =|dI/dx|+|dI/dy| is enough ( L2gradient=false ).

来自 https://docs.opencv.org/4.1.0/dd/d1a/group__imgproc__feature.html

注:阀值1和阀值2中较小的值用于边缘连接,而较大的值用于控制强边缘的初始段,推荐高低阀值比在2:1到3:1之间。

代码示例:

import cv2
import matplotlib.pyplot as plt

img=cv2.imread(“STC-MBS500U3V(17JE359).bmp”,0)

dest=cv2.Canny(img,150,100,3)

blur=cv2.blur(img,(3,3))#使用3*3矩阵降噪
dest2=cv2.Canny(blur,150,100,3)

plt.subplot(2,2,1)
plt.imshow(img,cmap=‘gray’)

plt.subplot(2,2,2)
plt.imshow(dest,cmap=‘gray’)

plt.subplot(2,2,3)
plt.imshow(blur,cmap=‘gray’)

plt.subplot(2,2,4)
plt.imshow(dest2,cmap=‘gray’)

plt.show()

四、sobel算子
Sobel算子是一个主要用于边缘检测的离散微分算子(discrete differentiation operator)。它结合来了高斯平滑和微分求导,用来计算图像灰度函数的近视梯度。在图像的任何一点使用此算子,都将会产生对应的梯度矢量或是其法矢量。
sobel算子的计算过程
OpenCV学习--基于OpenCV的边缘检测_第2张图片
Python:
dst = cv.Sobel( src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]] )
src 输入图像,源图像
dst 输出的边缘图像,需和源图像具有一样的大小和类型
ddepth 输出图像深度, see combinations; in the case of 8-bit input images it will result in truncated derivatives.
dx x方向上差分阶数
dy y方向上差分阶数
ksize Sobel核的大小,必须取1、3、5、7。默认值为3
scale 计算导数时可选的缩放因子,默认值为1,表示没有应用缩放 (see getDerivKernels for details).

delta 表示在结果存入目标图之前可选的dalta值,默认值为0.
borderType 边缘模式, see BorderTypes

来自 https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html

注:
I. 一般情况下都是使用ksizeksize内核来计算导数的。但是当ksize=1时,一般使用31或1*3的内核,这时不会进行高斯平滑操作。
II. 当内核大小为3时,Sobel内核可能产生比较明显的误差,因为Sobel算子只是求取了导数的近似值而已。为解决这个问题,Opencv提供了Scharr函数,该函数仅作用于大小为3的内核。
III. 因为Sobel算子结合了高斯平滑和分化,因此结果会具有更多的抗噪性。所以通常情况下一般分别求x、y方向的导数。

代码示例:

import cv2
import matplotlib.pyplot as plt

img=cv2.imread(“STC-MBS500U3V(17JE359).bmp”,0)

dstx=cv2.Sobel(img,cv2.CV_16S,1,0,3,1)
dsty=cv2.Sobel(img,cv2.CV_16S,0,1,3,1)

dst=cv2.addWeighted(dstx,0.5,dsty,0.5,0)

plt.subplot(2,2,1)
plt.imshow(img,cmap=‘gray’)

plt.subplot(2,2,2)
plt.imshow(dstx,cmap=‘gray’)

plt.subplot(2,2,3)
plt.imshow(dsty,cmap=‘gray’)

plt.subplot(2,2,4)
plt.imshow(dst,cmap=‘gray’)

plt.show()

五、Laplacian算子
Laplacian算子是n维欧几里德空间中的一个二阶微分算子,定义为梯度grad的散度div。因此如果f是二维可维的实函数,则f的拉普拉斯算子定义如下:
OpenCV学习--基于OpenCV的边缘检测_第3张图片
注:让一幅图像减去它的Laplacian算子可以增强对比度。
Python:
dst = cv.Laplacian( src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]] )
src 源图像
dst 输出图像,与源图像有相同的大小
ddepth 目标图像的深度
ksize 用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,默认值为1
scale 计算拉普拉斯的时候可选的比例因子,默认值1
delta 表示在结果存入目标图
borderType 边界模式, see BorderTypes

来自 https://docs.opencv.org/4.1.0/d4/d86/group__imgproc__filter.html
import cv2
import matplotlib.pyplot as plt

img=cv2.imread(“20180226104151813.jpg”)

gaussian_blur=cv2.GaussianBlur(img,(5,5),0,0)#使用高斯滤波去除噪声
src_gray=cv2.cvtColor(gaussian_blur,cv2.COLOR_BGR2GRAY)#灰度图
dst=cv2.Laplacian(img,cv2.CV_16S,3,1)#拉普拉斯算子
abs_dst=cv2.convertScaleAbs(dst)#计算绝对值,并转换为8位

plt.subplot(1,2,1)
plt.imshow(src_gray,cmap=‘gray’)

plt.subplot(1,2,2)
plt.imshow(abs_dst,cmap=‘gray’)

plt.show()

六、 scharr滤波器
一般直接称scharr为滤波器,因为Sobel算子对于核=3时,精度比较低,所以opencv提供了Scharr,Scharr滤波器同sobel一样快,,且精度更高,使用方式也同sobel相似。所以不再介绍。

你可能感兴趣的:(opencv,opencv,python)