《Opencv》基础操作详解(4)
目录
22、图像形态学操作
(1)、顶帽(原图-开运算)
公式:
应用场景:
代码示例:
(2)、黑帽(闭运算-原图)
公式:
应用场景:
代码示例:
23、边缘检测
(1)、Sobel算子边缘检测
用法说明:
代码示例:
(2)、Scharr算子边缘检测
用法说明:
代码示例:
(3)、Laplacian算子边缘检测
用法说明:
代码示例:
(4)、 Canny边缘检测(常用)
24、图像轮廓检测
(1)、轮廓检测、绘制轮廓
## 查找轮廓
用法说明:
返回值:
## 绘制轮廓
用法说明:
代码示例:
(2)、轮廓特征
22、图像形态学操作
(1)、顶帽(原图-开运算)
顶帽操作是原始图像与开运算结果之间的差值。它可以用于提取比背景亮的微小细节。
cv2.morphologyEx(image, cv2.MORPH_TOPHAT, kernel)
公式:
Top Hat=原始图像−开运算结果
应用场景:
-
提取图像中比背景亮的微小区域(如文本、细胞、颗粒等)。
-
去除不均匀光照的影响。
代码示例:
import cv2
import numpy as np
sun = cv2.imread('./images/sun.png')
cv2.imshow('sun',sun)
cv2.waitKey(0)
kernel = np.ones((2,2),np.uint8)
# 顶帽
tophat = cv2.morphologyEx(sun,cv2.MORPH_TOPHAT,kernel)
cv2.imshow('tophat',tophat)
cv2.waitKey(0)
(2)、黑帽(闭运算-原图)
黑帽操作是闭运算结果与原始图像之间的差值。它可以用于提取比背景暗的微小细节cv2.morphologyEx(image, cv2.MORPH_BLACKHAT, kernel)
公式:
Black Hat=闭运算结果−原始图像
应用场景:
-
提取图像中比背景暗的微小区域(如裂缝、孔洞等)。
-
检测图像中的暗区域。
代码示例:
import cv2
import numpy as np
sun = cv2.imread('./images/sun.png')
cv2.imshow('sun',sun)
cv2.waitKey(0)
kernel = np.ones((2,2),np.uint8)
# 黑帽
blackhat = cv2.morphologyEx(sun,cv2.MORPH_BLACKHAT,kernel)
cv2.imshow('blackhat',blackhat)
cv2.waitKey(0)
23、边缘检测
(1)、Sobel算子边缘检测
Sobel 算子是一种离散的微分算子,该算子结合了高斯平滑和微分求导运算。该算子利用局部差分寻找边缘,计算所得的是一个梯度的近似值。
Sobel算子包含2组3×3的矩阵,分别为横向和纵向模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。
用法说明:
cv2.Sobel(src, ddepth, dx, dy, ksize=None, scale=None, delta=None, borderType=None)
-
src: 输入图像,通常是单通道灰度图像。
-
ddepth: 输出图像的深度(数据类型),例如
cv2.CV_8U
、cv2.CV_16S
等。 -
dx: x 方向上的导数阶数。
-
dy: y 方向上的导数阶数。
-
ksize: Sobel 核的大小,必须是 1、3、5 或 7。默认值为 3。
-
scale: 可选的比例因子,应用于计算结果。
-
delta: 可选的增量值,添加到结果中。
-
borderType: 边界填充类型,默认值为
cv2.BORDER_DEFAULT
。
代码示例:
import cv2
yuan = cv2.imread('./images/yuan.png')
cv2.imshow('yuan',yuan)
cv2.waitKey(0)
# x方向
yuan_x = cv2.Sobel(yuan,-1,dx=1,dy=0)
yuan_x_64 = cv2.Sobel(yuan,cv2.CV_64F,dx=1,dy=0)
yuan_x_abs = cv2.convertScaleAbs(yuan_x_64)
cv2.imshow('yuan_x',yuan_x_abs)
cv2.waitKey(0)
# y方向
yuan_y = cv2.Sobel(yuan,-1,dx=0,dy=1)
yuan_y_64 = cv2.Sobel(yuan,cv2.CV_64F,dx=0,dy=1)
yuan_y_abs = cv2.convertScaleAbs(yuan_y_64)
cv2.imshow('yuan_y',yuan_y_abs)
cv2.waitKey(0)
# x、y同时
yuan_xy = cv2.Sobel(yuan,-1,dx=1,dy=1)
cv2.imshow('yuan_xy',yuan_xy)
cv2.waitKey(0)
# x方向、y方向权重相加
yuan_xy_add = cv2.addWeighted(yuan_x_abs,1,yuan_y_abs,1,0)
cv2.imshow('yuan_xy_add',yuan_xy_add)
cv2.waitKey(0)
(2)、Scharr算子边缘检测
Scharr 算子是 Soble 算子在 ksize=3 时的优化,与 Soble 的速度相同,且精度更高。Scharr 算子与 Sobel 算子的不同点是在平滑部分,其中心元素占的权重更重,相当于使用较小标准差的高斯函数,也就是更瘦高的模板。
用法说明:
cv2.Scharr(src, ddepth, dx, dy, scale=None, delta=None, borderType=None)
-
src: 输入图像,通常是单通道灰度图像。
-
ddepth: 输出图像的深度(数据类型),例如
cv2.CV_8U
、cv2.CV_16S
等。 -
dx: x 方向上的导数阶数(0 或 1)。
-
dy: y 方向上的导数阶数(0 或 1)。
-
scale: 可选的比例因子,应用于计算结果。
-
delta: 可选的增量值,添加到结果中。
-
borderType: 边界填充类型,默认值为
cv2.BORDER_DEFAULT
。
代码示例:
import cv2
cat = cv2.imread('./images/cat.jpg',0)
cat_x_64 = cv2.Scharr(cat,cv2.CV_64F,dx=1,dy=0)
cat_x_abs = cv2.convertScaleAbs(cat_x_64)
cat_y_64 = cv2.Scharr(cat,cv2.CV_64F,dx=0,dy=1)
cat_y_abs = cv2.convertScaleAbs(cat_y_64)
cat_xy = cv2.addWeighted(cat_x_abs,1,cat_y_abs,1,0)
cv2.imshow('cat_Scharr',cat_xy)
cv2.waitKey(0)
(3)、Laplacian算子边缘检测
不再以x和y的方向计算,而是以圆方向计算变化率。因此不需要Gx+Gy。
用法说明:
cv2.Laplacian(src, ddepth, ksize=None, scale=None, delta=None, borderType=None)
-
src: 输入图像,通常是单通道灰度图像。
-
ddepth: 输出图像的深度(数据类型),例如
cv2.CV_8U
、cv2.CV_16S
等。 -
ksize: 拉普拉斯核的大小,必须是正奇数(默认值为 1,表示使用最简单的 3x3 核)。
-
scale: 可选的比例因子,应用于计算结果。
-
delta: 可选的增量值,添加到结果中。
-
borderType: 边界填充类型,默认值为
cv2.BORDER_DEFAULT
。
代码示例:
import cv2
cat = cv2.imread('./images/cat.jpg',0)
cat_lap = cv2.Laplacian(cat,cv2.CV_64F)
cat_lap_abs = cv2.convertScaleAbs(cat_lap)
cv2.imshow('cat_laplacian',cat_lap_abs)
cv2.waitKey(0)
(4)、 Canny边缘检测(常用)
canny边缘检测分为4个部分:图像降噪 、梯度计算 、非极大值抑制 、双阈值边界跟踪
- 图像降噪:图像去噪是进行边缘检测的第一步,通过去噪可以去除图像中的一些噪点,从而使边缘检测时免受噪点干扰。高斯滤波。
- 梯度计算:要进行边缘检测,就需要得到图像梯度信息,根据图像的梯度幅值和梯度方向来确定边缘,一般均采用sobel算子对图像进行梯度幅值与梯度方向计算。
- 非极大值抑制NMS:在梯度图像中寻找梯度方向上的最大值作为边缘,不是梯度方向上的最大值则抑制为0。因为梯度方向是灰度变化最大的方向。比较梯度图像中每一点的灰度值与梯度方向上至少两个梯度图像像素点灰度值的大小,根据上述大小关系来确定是否保留该点的灰度值。
- 双阈值边界追踪:双阈值处理就是根据实际情况需要设置一个灰度高阈值和一个灰度低阈值对NMS后的图像进行过滤,使得得到的边缘尽可能是真实的边缘。
用法说明:
cv2.Canny(image, threshold1, threshold2, apertureSize=None, L2gradient=None)
-
image: 输入图像,通常是单通道灰度图像。
-
threshold1: 低阈值,用于边缘连接。
-
threshold2: 高阈值,用于强边缘检测。
-
apertureSize: Sobel 算子的核大小,默认值为 3。
-
L2gradient: 是否使用 L2 范数计算梯度幅值。如果为
True
,则使用更精确的 L2 范数;如果为False
,则使用 L1 范数(默认值为False
)。
代码示例:
import cv2
cat = cv2.imread('./images/cat.jpg',0)
cv2.imshow('cat',cat)
cv2.waitKey(0)
cat_canny = cv2.Canny(cat,100,200)
cv2.imshow('cat_canny',cat_canny)
cv2.waitKey(0)
24、图像轮廓检测
使用轮廓检测可以获得物体的边界,方便在图像中对他们进行定位。通常在一些有趣的应用中轮廓检测是第一处理环节。比如图像前景提取,简单的图像分割,检测以及识别等。
(1)、轮廓检测、绘制轮廓
## 查找轮廓
用法说明:
cv2.findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
-
image: 输入的二值图像(通常是经过边缘检测或阈值处理后的图像)。注意:
findContours()
会修改输入图像,因此建议使用副本。 -
mode: 轮廓检索模式,决定如何提取轮廓。常用的模式包括:
-
cv2.RETR_EXTERNAL
: 只检测外部轮廓。 -
cv2.RETR_LIST
: 检测所有轮廓,但不建立轮廓之间的层次关系。 -
cv2.RETR_TREE
: 检测所有轮廓,并建立完整的层次结构。
-
-
method: 轮廓近似方法,决定如何存储轮廓点。常用的方法包括:
-
cv2.CHAIN_APPROX_NONE
: 存储所有轮廓点。 -
cv2.CHAIN_APPROX_SIMPLE
: 压缩水平、垂直和对角方向的轮廓点,只保留端点。
-
-
contours: 输出的轮廓列表,每个轮廓是一个点集。
-
hierarchy: 输出的轮廓层次结构,描述轮廓之间的关系。
-
offset: 可选的偏移量,应用于所有轮廓点。
返回值:
-
contours: 检测到的轮廓列表。每个轮廓是一个点集(通常是一个 NumPy 数组)。
-
hierarchy: 轮廓的层次结构。它是一个 NumPy 数组,形状为
(N, 4)
,其中N
是轮廓的数量。每个轮廓的层次信息由 4 个值表示:-
[next, previous, first_child, parent]
:-
next
: 同一层级的下一个轮廓索引。 -
previous
: 同一层级的上一个轮廓索引。 -
first_child
: 第一个子轮廓索引。 -
parent
: 父轮廓索引。
-
-
## 绘制轮廓
用法说明:
cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
-
image: 目标图像,轮廓将绘制在这张图像上。
-
contours: 轮廓列表,通常是通过
findContours()
函数得到的。 -
contourIdx: 要绘制的轮廓索引。如果为
-1
,则绘制所有轮廓。 -
color: 轮廓的颜色,格式为
(B, G, R)
。 -
thickness: 轮廓线的宽度。如果为
-1
,则填充轮廓内部。 -
lineType: 线条类型,默认为
cv2.LINE_8
(8-connected line)。 -
hierarchy: 轮廓的层次结构(可选),通常由
findContours()
返回。 -
maxLevel: 绘制轮廓的最大层级(可选)。如果为
0
,则只绘制指定的轮廓;如果为1
,则绘制指定轮廓及其嵌套轮廓。 -
offset: 可选的偏移量,应用于所有轮廓点。
代码示例:
img = cv2.imread('./images/img_2.png')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('img_gray',img_gray)
cv2.waitKey(0)
_,img_binary = cv2.threshold(img_gray,100,255,cv2.THRESH_BINARY)
cv2.imshow('img_bin',img_binary)
cv2.waitKey(0)
_,contours,hierarchy = cv2.findContours(img_binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
print(hierarchy)
print(len(contours))
img_copy = img.copy()
img_copy = cv2.drawContours(image=img_copy,contours=contours,contourIdx=-1,color=(255,255,0),thickness=2)
cv2.imshow('Contous',img_copy)
cv2.waitKey(0)
(2)、轮廓特征
获取轮廓后,通常基于轮廓的特征进行筛选、识别和处理。例如,基于轮廓的周长和面积对轮廓进行筛选,然后绘制筛选的目标轮廓或其最小外接矩形。
- 轮廓面积:cv2.contourArea()
- 轮廓周长: cv2.arcLength()
# 获取索引为0的轮廓的面积
area_0 = cv2.contourArea(contours[0])
print(area_0)
# 获取索引为0的轮廓的周长
Length = cv2.arcLength(contours[0],closed=True)
print(Length)
# 筛选面积大于10000像素的轮廓并绘制
a_list = []
for i in contours:
if cv2.contourArea(i)>10000:
a_list.append(i)
img_copy1 = img.copy()
img_copy1 = cv2.drawContours(image=img_copy1,contours=a_list,contourIdx=-1,color=(0,255,255),thickness=2)
cv2.imshow('Contours_10000',img_copy1)
cv2.waitKey(0)