一、梯度处理
如果你还记得高数中用一阶导数来求极值的话,就很容易理解了:把图片想象成连续函数,因为边缘部分的像素值是与旁边像素明显有区别的,所以对图片局部求极值,就可以得到整幅图片的边缘信息了。不过图片是二维的离散函数,导数就变成了差分,这个差分就称为图像的梯度。
垂直边缘提取:
水平边缘提取:
垂直卷积核的转置就是水平卷积核,运算同上例。
cv2.filter2D(src, ddepth, kernel)
filter2D函数是用于对图像进行二维卷积(滤波)操作。它允许自定义卷积核(kernel)来实现各种图像处理效果,如平滑、锐化、边缘检测等
sobel算子:
sobel_image = cv2.Sobel(src, ddepth, dx, dy, ksize)
src:这是输入图像,通常应该是一个灰度图像(单通道图像),因为 Sobel 算子是基于像素亮度梯度计算的。在彩色图像的情况下,通常需要先将其转换为灰度图像。
ddepth:这个参数代表输出图像的深度,即输出图像的数据类型。在 OpenCV 中,-1 表示输出图像的深度与输入图像相同。
dx,dy:当组合为dx=1,dy=0时求x方向的一阶导数,在这里,设置为1意味着我们想要计算图像在水平方向(x轴)的梯度。当组合为 dx=0,dy=1时求y方向的一阶导数(如果同时为1,通常得不到想要的结果,想两个方向都处理的比较好 学习使用后面的算子)
ksize:Sobel算子的大小,可选择3、5、7,默认为3。
laplacian算子:
cv2.Laplacian(src, ddepth)
src:这是输入图像
ddepth:这个参数代表输出图像的深度,即输出图像的数据类型。在 OpenCV 中,-1 表示输出图像的深度与输入图像相同。
Laplacian算子是二阶边缘检测的典型代表,一/二阶边缘检测各有优缺点,大家可自行了解。
二、图像边缘检测
边缘检测是一套流程包括,高斯滤波,计算图像的梯度和方向,非极大值抑制,双阈值筛选。
1.高斯滤波
就是去除噪点!
边缘检测本身属于锐化操作,对噪点比较敏感,所以需要进行平滑处理。这里使用的是一个5*5的高斯核对图像进行消除噪声。
2.计算图像的梯度和方向
这里使用了sobel算子来计算图像的梯度值
3.非极大值抑制
得到每个边缘的方向之后,其实把它们连起来边缘检测就算完了,但是为什么还有这一步与下一步呢?是因为经过第二步得到的边缘不经过处理是没办法使用的,因为高斯滤波的原因,边缘会变得模糊,导致经过第二步后得到的边缘像素点非常多,因此我们需要对其进行一些过滤操作,而非极大值抑制就是一个很好的方法,它会对得到的边缘像素进行一个排除,使边缘尽可能细一点。
在该步骤中,我们需要检查每个像素点的梯度方向上的相邻像素,并保留梯度值最大的像素,将其他像素抑制为零。假设当前像素点为(x,y),其梯度方向是0°,梯度值为G(x,y),那么我们就需要比较G(x,y)与两个相邻像素的梯度值:G(x-1,y)和G(x+1,y)。如果G(x,y)是三个值里面最大的,就保留该像素值,否则将其抑制为零。
4.双阈值筛选
当某一像素位置的幅值超过最高阈值时,该像素必是边缘像素;当幅值低于最低像素时,该像素必不是边缘像素;幅值处于最高像素与最低像素之间时,如果它能连接到一个高于阈值的边缘时,则被认为是边缘像素,否则就不会被认为是边缘。
API使用:
edges = cv2.Canny(image, threshold1, threshold2),即使读到的是彩色图也可以进行处理。
image
:输入的灰度/二值化图像数据。
threshold1
:低阈值,用于决定可能的边缘点。
threshold2
:高阈值,用于决定强边缘点。
三、绘制图像轮廓
轮廓是一系列相连的点组成的曲线,代表了物体的基本外形。相对于边缘,轮廓是连续的,边缘不一定连续。轮廓是一个闭合的、封闭的形状。
寻找轮廓需要将图像做一个二值化处理,并且根据图像的不同选择不同的二值化方法来将图像中要绘制轮廓的部分置为白色,其余部分置为黑色。也就是说,我们需要对原始的图像进行灰度化、二值化的处理,令目标区域显示为白色,其他区域显示为黑色。
寻找轮廓函数:
contours,hierarchy = cv2.findContours(image,mode,method)
返回值:[ 轮廓点坐标 ] 和 [ 层级关系 ]。
contours:表示获取到的轮廓点的列表。检测到有多少个轮廓,该列表就有多少子列表,每一个子列表都代表了一个轮廓中所有点的坐标。
hierarchy:表示轮廓之间的关系。对于第i条轮廓,, , ,分别表示其后一条轮廓、前一条轮廓、(同层次的第一个)子轮廓、父轮廓的索引(如果没有相应的轮廓,则对应位置为-1)。该参数的使用情况会比较少。
image:表示输入的二值化图像。
mode:表示轮廓的检索模式。
method:轮廓的表示方法。
轮廓检索模式。mode参数共有四个选项分别为:RETR_LIST( 表示列出所有的轮廓。并且在hierarchy里的轮廓关系中,每一个轮廓只有前一条轮廓与后一条轮廓的索引,而没有父轮廓与子轮廓的索引),RETR_EXTERNAL(表示只查找最外层的轮廓。并且在hierarchy里的轮廓关系中,每一个轮廓只有前一条轮廓与后一条轮廓的索引,而没有父轮廓与子轮廓的索引. ),RETR_CCOMP(表示列出所有的轮廓。并且在hierarchy里的轮廓关系中,轮廓会按照成对的方式显示。 ),RETR_TREE(表示列出所有的轮廓。并且在hierarchy里的轮廓关系中,轮廓会按照树的方式显示,其中最外层的轮廓作为树根,其子轮廓是一个个的树枝.)。
轮廓存储方法。轮廓近似方法。决定如何简化轮廓点的数量。就是找到轮廓后怎么去存储这些点。
method参数有三个选项:CHAIN_APPROX_NONE、CHAIN_APPROX_SIMPLE、CHAIN_APPROX_TC89_L1。
CHAIN_APPROX_NONE
表示将所有的轮廓点都进行存储
CHAIN_APPROX_SIMPLE
表示只存储有用的点,比如直线只存储起点和终点,四边形只存储四个顶点,默认使用这个方法;
对于mode和method这两个参数来说,一般使用RETR_EXTERNAL和CHAIN_APPROX_SIMPLE这两个选项。
绘制轮廓函数:
cv2.drawContours(image, contours, contourIdx, color, thickness)
image:原始图像,一般为单通道或三通道的 numpy 数组。
contours:包含多个轮廓的列表,每个轮廓本身也是一个由点坐标构成的二维数组(numpy数组)。
contourIdx:要绘制的轮廓索引。如果设为 -1
,则会绘制所有轮廓。根据索引找到轮廓点绘制出来。默认是-1。
color:绘制轮廓的颜色,可以是 BGR 值或者是灰度值(对于灰度图像)。
thickness:轮廓线的宽度,如果是正数,则画实线;如果是负数,则填充轮廓内的区域。
四、凸包检测
通俗的讲,凸包其实就是将一张图片中物体的最外层的点连接起来构成的凸多边形,它能包含物体中所有的内容。
一般来说,凸包都是伴随着某类点集存在的,也被称为某个点集的凸包。
对于一个点集来说,如果该点集存在凸包,那么这个点集里面的所有点要么在凸包上,要么在凸包内。
凸包检测常用在物体识别、手势识别、边界检测等领域。
获取凸包点:
cv2.convexHull(points)
points
:输入参数,图像的轮廓
凸包绘制函数:
cv2.polylines(image, pts, isClosed, color, thickness=1)
image
:要绘制线条的目标图像,它应该是一个OpenCV格式的二维图像数组(如numpy数组)。
pts
:一个二维 numpy 数组,每个元素是一维数组,代表一个多边形的一系列顶点坐标。
isClosed
:布尔值,表示是否闭合多边形,如果为 True,会在最后一个顶点和第一个顶点间自动添加一条线段,形成封闭的多边形。
color
:线条颜色,可以是一个三元组或四元组,分别对应BGR或BGRA通道的颜色值,或者是灰度图像的一个整数值。
thickness
(可选):线条宽度,默认值为1。