1. Opencv简介
入门前可以稍稍了解一些关于OpenCV的介绍,以下做简略介绍:
OpenCV 的主要功能:
- 图像处理:包括图像变换(如缩放、旋转、仿射变换)、图像滤波(如平滑、锐化、边缘检测)、图像阈值处理等。
- 视频分析:读取、显示视频文件,视频帧处理,视频流处理等。
- 特征检测与匹配:检测图像中的关键点(如角点、边缘等),并用于图像匹配、目标识别等。
- 对象检测:使用预训练的模型检测图像中的特定对象(如人脸、车辆等)。
- 面部识别:利用面部特征进行身份认证或表情分析等。
- 3D重建:从多视角图像或视频中重建三维场景。
- 机器学习:OpenCV 包含了一些基本的机器学习算法,可用于图像分类、聚类等任务。
OpenCV 的官方文档:
官方网站: OpenCV - Open Computer Vision Library
文档页面: OpenCV-Python Tutorials
GitHub仓库:OpenCV GitHub Repository
1.1 图像相关概念
1.1.1 位数
计算机采用0/1编码的系统,数字图像也是利用0/1来记录信息。我们常接触的图像都是8位数图像,包含0~255灰度,其中0,表示最黑,1,表示最白。
8位图像:每个像素可以显示256种颜色的图像。这种图像通常被称为标准清晰度图像,广泛应用于电视和计算机屏幕上。8位图像可以显示的颜色数量为2e8 = 256种颜色(灰度图),对于彩色图像,如果每个颜色通道(红、绿、蓝)都是8位,则总颜色数为2563 = 16,777,216种颜色,这种图像也被称为24位图像或真彩色图像。
1.1.2 二值图
二值图是一种简洁的图像表示方式,它仅包含黑色和白色两种颜色,每个像素点非黑即白,没有中间灰度值。这种图像形式因其数据量小、处理方便且边缘清晰的特点,在图像分割、字符识别、计算机视觉等领域得到广泛应用。
1.1.3 灰度图
灰度图是一种图像表示方式,其中图像中的每个像素点具有不同的灰度级别,这些级别通常是从黑色(灰度值为0)到白色(灰度值为255)之间的连续变化。灰度图不包含颜色信息,只展示图像的亮度变化,因此在处理和分析图像时,能够更专注于图像的纹理、形状等特征。
1.1.4 彩色图
彩色图像是一种包含丰富色彩信息的图像表示方式。它不仅能够展现图像的亮度信息,还能通过红、绿、蓝(RGB,分量介于0~255)三种基色的不同组合来精确地表示出成千上万种颜色。彩色图像中的每个像素点都对应着这三个颜色通道上的具体数值,这些数值共同决定了该像素点的颜色。彩色图像因其色彩丰富、细节表现力强,被广泛应用于数字摄影、电影制作、广告设计、医学成像等多个领域,为人们提供了更加真实、生动的视觉体验。
1.2 OpenCV安装
可以参考这篇文章:Pycharm安装Opencv详细教程
1.3 OpenCV模块
OpenCV具有多个功能模块,包括深度神经网络模块(dnn)、机器学习模块(ML)、视频分析模块(Video)、快速近似最近邻库(Flann)、照片模块(Photo)、图像拼接模块(Stitching)、形状模块(Shape)、超分辨率模块(Superres)、视频稳定模块(Videstab)、3D可视化模块(Viz)、图像编解码模块(Imgcodecs)、对象检测模块(ObjDetect)、相机标定与三维重建模块(Calib3D)、核心模块(Core)、图像处理模块(Imgproc)、高GUI模块(Highgui)、特征检测与匹配模块(Features2D)等,其中标红部分为主要学习模块,简介如下:
- 核心模块(Core)
该模块是其他模块的基础,提供了基本的核心功能、数据结构和函数。它包括了基本的数据类型、动态数据结构、数学函数、数组操作等。
- 图像处理模块(Imgproc)
专门用于图像处理,包括色彩空间转换、几何变换(如缩放、旋转、仿射变换)、图像滤波(如平滑、锐化、边缘检测)、直方图操作等。
- 高GUI模块(Highgui)
用于创建和操作图形用户界面元素,如显示图像的窗口、处理键盘和鼠标事件等。不过,在新版本的OpenCV中,Highgui的功能可能已被其他模块(如imgcodecs和videoio)所取代。
- 特征检测与匹配模块(Features2D)
包括特征检测器(如SIFT、SURF、ORB等)和描述符提取器,用于在图像中检测关键点并提取其描述符,进而进行特征匹配和图像配准。
2 OpenCV基本操作
2.1 基本操作
2.1.1 图像读取、显示、保存
- 图像读取:cv2.imread()
import cv2
# 使用cv2.imread()读取图像
# 参数1: 图像文件的路径
# 参数2: 读取模式
# cv2.IMREAD_COLOR: 加载彩色图像,任何图像的透明度都会被忽略(默认)
# cv2.IMREAD_GRAYSCALE: 以灰度模式加载图像
# cv2.IMREAD_UNCHANGED: 包括alpha通道的加载图像
image = cv2.imread('path_to_your_image.jpg', cv2.IMREAD_COLOR)
# 检查图像是否成功加载
if image is not None:
# 在这里处理图像
# 例如,显示图像
cv2.imshow('Loaded Image', image)
# 等待按键操作
cv2.waitKey(0)
# 关闭所有OpenCV窗口
cv2.destroyAllWindows()
else:
print("Error: Image could not be read.")
注:图像路径中不得存在中文,否则会出现cv2.error: OpenCV(4.10.0) D:\a\opencv-python\opencv-python\opencv\modules\highgui\src\window.cpp:973: error: (-215:Assertion failed) size.width>0 && size.height>0 in function 'cv::imshow'错误。
注:opencv图像读取通道为B\G\R,matplotlib图像读取通道为R\G\B
- 显示图像:cv2.imshow()
# 显示图像,'Image Window'是窗口名称,image是要显示的图像
cv2.imshow('Image Window', image)
# 等待按键事件,参数为等待时间(毫秒),0表示无限期等待,按任意键结束
cv2.waitKey(0)
# 关闭所有OpenCV创建的窗口
cv2.destroyAllWindows()
- 保存图像 :cv2.imwrite()
import cv2
# 读取图像
image = cv2.imread('input.jpg')
# 检查图像是否正确读取
if image is None:
print("Error: 图像未能正确读取")
else:
# 保存图像
is_saved = cv2.imwrite('output.png', image)
# 检查图像是否保存成功
if is_saved:
print("图像已保存")
else:
print("Error: 图像未能保存")
注:保存图像路径设置最好不要有中文!!!
2.1.2 图像上绘制几何图形
- 绘制直线:使用
cv2.line()
函数来绘制线条。你需要指定线条的起点和终点坐标,以及线条的颜色和粗细。
import cv2
import numpy as np
# 创建一个黑色的空白图像
img = np.zeros((512,512,3), np.uint8)
# 绘制一条对角线
cv2.line(img,(0,0),(511,511),(255,0,0),5)
# 显示图像
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 绘制矩形:使用
cv2.rectangle()
函数来绘制矩形。你需要指定矩形的左上角和右下角坐标,以及颜色和线条粗细(或者如果填充的话,使用-1
作为线条粗细)。
import cv2
import numpy as np
# 创建一个黑色的空白图像
img = np.zeros((512,512,3), np.uint8)
# 绘制一个蓝色的矩形
cv2.rectangle(img,(384,0),(510,128),(255,0,0),3)
# 绘制一个填充的矩形
cv2.rectangle(img,(0,384),(128,510),(0,255,0),-1)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 绘制圆形:使用
cv2.circle()
函数来绘制圆形。你需要指定圆心的坐标、半径、颜色以及线条粗细(或者如果填充的话,使用-1
)。
import cv2
import numpy as np
# 创建一个黑色的空白图像
img = np.zeros((512,512,3), np.uint8)
# 绘制一个绿色的圆
cv2.circle(img,(447,63), 63, (0,255,0), -1)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 绘制多边形:对于多边形,你可以使用
cv2.polylines()
函数。但请注意,你需要将多边形的点坐标作为点集列表传入,并且每个点需要是元组的元组(对于轮廓)或列表的列表(对于形状)。
import cv2
import numpy as np
# 创建一个黑色的空白图像
img = np.zeros((512,512,3), np.uint8)
# 定义三角形的顶点
pts = np.array([[100,50],[200,360],[100,250]], np.int32)
pts = pts.reshape((-1,1,2))
# 绘制三角形
cv2.polylines(img,[pts],isClosed=True,color=(255,255,255),thickness=3)
cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
- 添加文字:在OpenCV中,添加文字到图像上可以通过
cv2.putText()
函数实现。这个函数允许你在指定的位置绘制文本字符串,你可以自定义文本的内容、字体、大小、颜色等属性。
import cv2
import numpy as np
# 创建一个黑色的空白图像
img = np.zeros((512, 512, 3), np.uint8)
# 设置文本内容
text = "Hello, OpenCV!"
# 设置文本的起始坐标(左下角)
org = (50, 50)
# 设置字体
# OpenCV提供了几种字体,但是它们的名称依赖于系统,通常是:
# cv2.FONT_HERSHEY_SIMPLEX, cv2.FONT_HERSHEY_PLAIN, cv2.FONT_HERSHEY_DUPLEX, 等
# 你可能需要尝试不同的字体来找到最适合你需求的
font = cv2.FONT_HERSHEY_SIMPLEX
# 设置字体大小
fontScale = 1
# 设置字体颜色(BGR)
color = (255, 0, 0) # 蓝色
# 设置线条粗细
thickness = 2
# 在图像上添加文本
cv2.putText(img, text, org, font, fontScale, color, thickness, cv2.LINE_AA)
# 显示图像
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
2.1.3 获取并修改图像中的像素点
按照numpy操作数组的增、删、改、查等操作即可获取并修改图像中的像素点。
2.1.4 获取图像属性
属性 | API |
形状 | img.shape |
图像大小 | img.size |
数据类型 | img.dtype |
2.1.5 图像通道的拆分与合并
# 通道拆分
b, g, r = cv2.split(img)
# 通道合并
img = cv2.merge((b,g,r))
2.1.6 色彩空间的改变
OpenCV最广泛的两种图像色彩转换方法,分别是BGR与Gray互转,BGR与HSV互转。
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为HSV图像
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
2.2 算数运算
图像的算术运算在OpenCV中是一组基本的图像处理操作,包括加法、减法、乘法和除法等。这些运算可以用于多种图像处理任务,如图像融合、噪声消除、对比度调整等。
2.2.1 图像加法
图像加法是将两幅图像或一幅图像与一个标量(单一的数值)进行相加。在OpenCV中,图像加法可以通过加号运算符“+”或cv2.add()
函数来实现。
- 加号运算符“+”:当使用加号运算符对图像进行加法运算时,如果相加的结果超过了像素值的最大值(对于8位图像通常是255),则结果会进行模256运算,即取余数。这可能导致图像看起来不自然,因为原本应该更亮的像素点可能会变暗。
cv2.add()
函数:该函数会对超过图像饱和值的数值进行饱和处理,即将结果截断为最大值(对于8位图像是255)。这使得图像整体看起来更加自然,亮度增加。
2.2.2 图像减法
图像减法用于从一幅图像中减去另一幅图像或标量。在OpenCV中,可以使用cv2.subtract()
函数或“-”运算符来实现。图像减法常用于去除背景、检测图像差异等场景。
cv2.subtract()
函数:该函数直接计算两幅图像或图像与标量的差值,如果结果为负数,则结果会被截断为0。- “-”运算符:与加号运算符类似,但用于减法运算。
2.2.3 图像乘法
图像乘法是将两幅图像或一幅图像与一个标量进行相乘。在OpenCV中,可以使用cv2.multiply()
函数或“*”运算符来实现。图像乘法常用于调整图像的亮度和对比度。
cv2.multiply()
函数:该函数对两幅图像或图像与标量进行逐像素相乘,并处理乘积超出像素值范围的情况。- “*”运算符:直接对图像进行乘法运算,但需要注意数据类型和结果的处理。
2.2.4 图像除法
图像除法是将一幅图像除以另一幅图像或标量。在OpenCV中,可以使用cv2.divide()
函数或“/”运算符来实现。图像除法常用于归一化图像、调整图像亮度等。
cv2.divide()
函数:该函数对两幅图像或图像与标量进行逐像素相除,并处理除数为0或结果超出像素值范围的情况。- “/”运算符:直接对图像进行除法运算,但需要注意数据类型和结果的处理。
2.2.5 图像混合
cv2.addWeighted(src1, alpha, src2, beta, gamma, dst, dtype=-1)
src1
和src2
:输入的两个图像。alpha
和beta
:src1
和src2
的权重,它们的和不一定为1,但通常为了方便计算和理解,会设置为和为1的权重。gamma
:一个加到混合结果上的标量值,可以是0。dst
:输出图像,与输入图像具有相同的尺寸和类型。dtype
:输出图像的深度,可选参数,默认为-1,表示与输入图像相同的深度。
注:
- 在进行图像算术运算时,需要确保参与运算的图像具有相同的尺寸和类型。
- 对于不同类型的图像(如灰度图像和彩色图像),可能需要分别处理每个通道。
- 运算结果可能需要进一步处理,以确保其在有效的像素值范围内。
3 OpenCV图像处理
3.1 几何变换
3.1.1 图像缩放
resized = cv2.resize(src, dsize=None, fx=0, fy=0, interpolation=cv2.INTER_LINEAR)
- src: 原始图像。
- dsize: 输出图像的尺寸(宽度, 高度)。如果它是None,那么dsize将由fx和fy决定。
- fx: 沿水平轴的比例因子(宽度)。
- fy: 沿垂直轴的比例因子(高度)。
- interpolation: 插值方法,决定了图像的缩放方式。常用的插值方法有
cv2.INTER_LINEAR
(双线性插值,默认)和cv2.INTER_AREA
(区域插值,更适用于缩小图像)。
更多插值方法见下面这篇文章:
http://t.csdnimg.cn/INnRYhttp://t.csdnimg.cn/INnRY示例:
img = cv2.imread('img\\1.png')
# 绝对尺寸
rows, cols = img.shape[:2]
res = cv2.resize(img, (2*cols, 2*rows), interpolation=cv2.INTER_CUBIC)
# 相对尺寸
res1 = cv2.resize(img, None, fx=0.5, fy=0.5)
3.1.2 图像平移
cv2.wrapAffine(img, M, dsize)
- img:原始图像。
- M:2*3矩阵。根据平移量创建一个2x3的矩阵。在OpenCV中,平移矩阵通常是这样的形式:
[[1, 0, tx], [0, 1, ty]]
,其中tx
和ty
分别是x轴和y轴上的平移量。 - dsize:输出图像大小。
注:输出图像的大小,它应该是(宽度,高度)的形式。请记住,width=列数,height=行数。
示例:
img = cv2.imread('your_image_path.jpg')
# 定义平移量
tx, ty = 100, 50 # x轴向右平移100像素,y轴向下平移50像素
# 获取图像的高度和宽度
rows, cols = img.shape[:2]
# 创建平移矩阵
M = np.float32([[1, 0, tx], [0, 1, ty]])
# 应用仿射变换
# 注意:输出图像的大小应该与原图像相同,除非你有特殊需求
translated = cv2.warpAffine(img, M, (cols, rows))
# 显示原图和平移后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Translated Image', translated)
注:在这个示例中,cv2.warpAffine()
函数的第三个参数是输出图像的大小,这里我们简单地将其设置为与原图像相同的大小(cols, rows)
。然而,如果你知道平移后的图像可能会超出这个范围,你可能需要调整输出图像的大小以包含整个平移后的图像。但是,在大多数情况下,如果你只是进行小范围的平移,使用原图像的大小作为输出大小就足够了。另外,请注意,如果平移导致图像的一部分超出了输出图像的边界,那么这些部分将被裁剪掉。如果你想要保留整个平移后的图像(包括超出原图像边界的部分),你可能需要创建一个更大的输出图像,并在其上进行仿射变换。这可以通过调整cv2.warpAffine()
函数的输出大小参数来实现。
3.1.3 图像旋转
# 定义旋转矩阵
M = cv2.getRotationMatrix2D(center, angle, scale)
# 进行旋转转换
cv2.warpAffine(image, M, (w, h))
- center:旋转中心
- angle:旋转角度(逆时针方向为正,顺时针方向为负)
- scale:缩放比例
- image:原始图像
- w,h:输出图像的列数、行数
注:当你想要在任意中心进行旋转,可以加入这个平移矩阵,不太懂得可以数学公式推导一下,不做详细介绍。
[[1, 0, 0]
[0 -1 0]
[left, top, 1]]
示例:
image = cv2.imread('your_image_path.jpg')
# 定义旋转中心 (图像中心)
(h, w) = image.shape[:2]
center = (w // 2, h // 2)
# 定义旋转角度(逆时针方向)
angle = 45 # 旋转45度
# 获取旋转矩阵(这里还可以指定缩放因子)
M = cv2.getRotationMatrix2D(center, angle, 1.0)
# 执行旋转
rotated = cv2.warpAffine(image, M, (w, h))
# 显示原图和旋转后的图像
cv2.imshow('Original Image', image)
cv2.imshow('Rotated Image', rotated)
3.1.4 仿射变换
定义:仿射变换是指在几何中,一个向量空间进行一次线性变换并接上一个平移,变换为另一个向量空间的过程。在二维空间中,它保持图形的“平直性”和“平行性”,即变换后直线还是直线,平行线依然是平行线,且直线上的点的位置顺序不变。
仿射变换矩阵:参考博主|@我菜就爱学|的这篇文章。
http://t.csdnimg.cn/7Vq4Ghttp://t.csdnimg.cn/7Vq4GAPI:
cv2.warpAffine(src, M, dsize[, dst[, flags[, borderMode[, borderValue]]]])
- src: 输入图像。
- M: 2x3的变换矩阵。
- dsize: 输出图像的大小。
- dst: 输出图像,可选参数,函数调用后的运算结果将存储在这里。
- flags: 插值方法的标识符,默认为
INTER_LINEAR
(线性插值)。 - borderMode: 边界像素模式,默认为
BORDER_CONSTANT
(常量填充)。 - borderValue: 边界填充值,默认为0。
示例:
img = cv2.imread('input.jpg')
rows, cols, _ = img.shape
# 定义仿射变换前后的三个点
pts1 = np.float32([[50, 50], [200, 50], [50, 200]])
pts2 = np.float32([[10, 100], [200, 50], [100, 250]])
# 获取仿射变换矩阵
M = cv2.getAffineTransform(pts1, pts2)
# 进行仿射变换
dst = cv2.warpAffine(img, M, (cols, rows))
# 显示原始图像和变换后的图像
cv2.imshow('Input', img)
cv2.imshow('Output', dst)
3.1.5 透射变换
概念:OpenCV中的透射变换(Perspective Transformation)是一种用于图像处理的几何变换方法,它可以将图像从一个视角转换到另一个视角,同时保持图像中的直线仍为直线,但不一定保持平行性。透射变换通常用于校正图像中的透视畸变,如拍摄时由于相机角度导致的物体形状扭曲,或者将图像中的某个区域映射到一个新的矩形或四边形中。
应用场景:
- 图像校正:校正由于相机角度或镜头畸变导致的图像扭曲。
- 图像拼接:在图像拼接过程中,透射变换可以用于将多张具有透视畸变的图像拼接成全景图。
- 文档扫描:在文档扫描和识别中,透射变换可以用于校正扫描图像的透视畸变,提高识别准确率。
- 虚拟现实和增强现实:在虚拟现实和增强现实应用中,透射变换可以用于将虚拟对象投影到真实场景中,并保持正确的透视关系。
示例:透射变换cv2.warpPerspective中四个参数:原图、变换矩阵、输出图像的大小(宽度和高度)以及插值方法(可选)。
img = cv2.imread('image.jpg')
# 定义原图和目标图的对应点
pts1 = np.float32([[56, 65], [368, 52], [28, 387], [389, 390]])
pts2 = np.float32([[0, 0], [300, 0], [0, 300], [300, 300]])
# 计算透视变换矩阵
M = cv2.getPerspectiveTransform(pts1, pts2)
# 进行透射变换
dst = cv2.warpPerspective(img, M, (300, 300))
# 显示变换前后的图像
cv2.imshow('Original Image', img)
cv2.imshow('Perspective Transformed Image', dst)
3.1.6 图像金字塔
概念:OpenCV中的图像金字塔是一种用于图像多尺度表示的技术,它通过对图像进行连续的模糊和下采样(或上采样)操作,生成一系列分辨率逐渐降低(或增加)的图像集合。图像金字塔在图像处理、计算机视觉和机器学习等领域有着广泛的应用,如图像压缩、特征提取、图像融合等。
图像金字塔类型:
图像金字塔主要分为两种类型:高斯金字塔(Gaussian Pyramid)和拉普拉斯金字塔(Laplacian Pyramid)。
- 高斯金字塔:
- 构建过程:从原始图像开始,作为金字塔的最底层。对当前层图像进行高斯模糊,然后对模糊后的图像进行下采样(通常是按图像尺寸的一半进行),得到下一层图像。重复这个过程,直到达到预定的层数或图像尺寸小于一定阈值。
- 目的:高斯金字塔用于图像的多尺度分析,通过逐层降低图像的分辨率,可以提取图像在不同尺度下的特征。
- 应用:图像压缩、特征提取、物体检测等。
- 拉普拉斯金字塔:
- 构建过程:拉普拉斯金字塔是高斯金字塔的一种变体,通过记录每层图像与其上层图像之间的差异来构建。具体来说,对高斯金字塔中的每一层图像进行上采样(放大),并减去相应的上一层图像(也需要进行适当的调整以匹配尺寸),得到当前层的拉普拉斯金字塔图像。
- 目的:拉普拉斯金字塔能够有效地表示图像的细节信息,特别是边缘和纹理信息。
- 应用:图像压缩、图像融合、图像增强等。
API:
- cv2.pyrDown():用于构建高斯金字塔中的下采样层。该函数首先对图像进行高斯模糊,然后丢弃图像的偶数行和列,从而实现下采样。
- cv2.pyrUp():用于对图像进行上采样,以构建拉普拉斯金字塔或进行图像放大。该函数通过插值方法(如双线性插值)增加图像的尺寸。
3.2 形态学操作
日期2024/07/28,这几天将陆续更新……同时,文章目前只是第一版,后续会对文章中的不足进行补充,对文章排版进行美化等。
3.2.1 腐蚀和膨胀
3.2.2 开/闭运算
3.2.3 礼帽和黑帽
3.3 图像平滑
3.3.1 图像噪声
3.3.2 均值滤波
3.3.3 高斯滤波
3.3.4 中值滤波
3.4 直方图
3.4.1 原理
2.4.2 直方图计算与绘制
2.4.3 掩膜的应用
2.4.4 直方图均衡化
2.4.5 自适应的直方图均衡化
3.5 边缘检测
3.5.1 原理
3.5.2 Sobel算子
3.5.3 Schaar算子
3.5.4 Laplacian算子
3.5.5 Canny边缘检测
3.5.6 算子比较
3.6 模糊匹配和霍夫变换
3.6.1 模板匹配
3.6.2 霍夫变换
3.6.3 霍夫线检测
3.6.4 霍夫圆检测
4 图像特征提取与描述
4.1 角点特征
角点特征在计算机视觉和图像处理中是一个核心概念,它通常指的是图像中那些在局部区域内具有显著且独特性的点。这些点往往是图像中信息含量较高的部分,能够反映图像的结构和形状特征。具体来说,角点特征的定义可以从以下几个方面来理解:
-
局部极大值点:角点通常被认为是图像灰度值或亮度在局部区域内变化最为剧烈的点,即局部极大值点。这种变化可以通过计算图像的一阶或二阶导数来检测。
-
边缘交点:角点也常被视为图像中两条或多条边缘的交点。这些交点处于不同方向边缘的汇聚点,因此具有独特的结构特征。
-
稳定性:角点特征应该具有一定的稳定性,即在不同视角、光照条件或图像尺度变化下,仍然能够被准确地检测和识别出来。这种稳定性是角点特征在实际应用中非常重要的一个特性。
-
信息丰富性:角点通常包含了图像中的重要信息,如形状、纹理等。通过提取角点特征,可以大大简化图像数据的处理量,同时保留图像的主要特征,便于后续的图像分析、匹配和识别等操作。
综上所述,角点特征是指图像中在局部区域内具有显著变化、独特结构、稳定性和信息丰富性的点。这些特征在计算机视觉和图像处理领域有着广泛的应用,如图像匹配、目标跟踪、运动估计、三维场景重建等。为了有效地检测和提取角点特征,研究者们提出了多种算法和方法,如Harris角点检测器、SUSAN角点检测器、FAST算法、ORB特征等。
4.2 Harris和Shi-Tomas算法
4.2.1 Harris角点检测
原理:Harris角点检测的原理是通过分析图像局部窗口内的灰度变化来检测角点。当窗口在图像上沿任意方向移动时,如果窗口内的灰度变化都很大,则认为该窗口中心是一个角点。这种灰度变化通过计算窗口内像素点的梯度并构建协方差矩阵来量化。协方差矩阵的特征值反映了窗口内灰度变化的主方向和强度,进而通过角点响应函数R来判断是否为角点。
具体可以参考这篇文章:
计算视觉——Harris角点检测 - zzb1234 - 博客园 (cnblogs.com)https://www.cnblogs.com/zzb123456789/p/12364340.htmlAPI:
cv2.cornerHarris(src, blockSize, ksize, k[, dst[, borderType]])
-
src: 输入图像,必须是单通道(灰度图)的float32或uint8类型。如果传递的是uint8类型,则在函数内部会先将其转换为float32类型,然后再进行处理。
-
blockSize: 用于角点检测的邻域大小,即考虑像素点周围多大的一个区域来计算角点响应函数。该值必须是正奇数。
-
ksize: Sobel算子的窗口大小,用于计算图像的一阶导数。该值也必须是正奇数。
-
k: Harris角点检测方程中的自由参数,用于设置角点检测的灵敏度。k的值越大,检测到的角点越少,但角点的质量更高(即更可能是真正的角点)。
-
dst: 输出图像,与输入图像具有相同的尺寸和类型。函数计算得到的角点响应值将存储在这个图像中。如果此参数为None,则函数将创建一个新的Numpy数组来存储结果。
-
borderType: 图像边界的模式。这个参数指定了图像外推像素的方法。默认值为
cv2.BORDER_DEFAULT
。
返回值:
如果dst
参数不是None,则函数不返回任何值,结果直接存储在dst
中。如果dst
是None,则函数返回一个Numpy数组,包含了角点响应值。
示例:
# 读取图像并转换为灰度图
image = cv2.imread('your_image_path.jpg', 0)
# 应用Harris角点检测
gray = np.float32(image)
dst = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
# 将结果图像转换为uint8类型,以便显示
dst = cv2.dilate(dst, None)
ret, dst = cv2.threshold(dst, 0.01*dst.max(), 255, 0)
# 显示原图和处理后的图像
plt.subplot(121), plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)), plt.title('Original Image')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(dst, cmap='gray'), plt.title('Harris Corners')
plt.xticks([]), plt.yticks([])
plt.show()
4.2.2 Shi-Tomas角点检测
原理:Shi-Tomas角点检测算法是对Harris角点检测算法的改进,它通过计算角点检测器响应的最小特征值而非Harris角点检测中的特征值差来工作,从而提高了角点检测的稳定性。
API:
cv2.goodFeaturesToTrack(image, maxCorners, qualityLevel, minDistance, useHarrisDetector=False, k=0.04)
- image:输入图像,应为灰度图。
- maxCorners:返回角点的最大数量。如果实际检测到的角点数超过这个值,则只返回最强的(即最好的)角点。
- qualityLevel:角点检测器的接受质量水平参数。这个参数是一个介于0到1之间的浮点数,它乘以最佳角点的最小质量分数(即响应值最小的角点),低于这个乘积的角点会被拒绝。
- minDistance:两个角点之间的最小欧氏距离。这个参数用来避免检测到的角点过于集中。
- useHarrisDetector:布尔值,指定是否使用Harris角点检测器代替Shi-Tomasi角点检测器。如果设置为True,则使用Harris角点检测器;如果为False(默认值),则使用Shi-Tomasi角点检测器。
- k:用于Harris角点检测器的自由参数。仅当
useHarrisDetector=True
时有效。
返回值:
该函数返回一个NumPy数组,其中包含了检测到的角点的坐标(x, y)。
示例:
# 读取图像并转换为灰度图
image = cv2.imread('image.jpg', 0)
# Shi-Tomasi角点检测
corners = cv2.goodFeaturesToTrack(image, maxCorners=100, qualityLevel=0.3, minDistance=7, useHarrisDetector=False)
# 绘制角点
corners = np.int0(corners)
for i in corners:
x, y = i.ravel()
cv2.circle(image, (x, y), 3, 255, -1)
# 显示图像
cv2.imshow('Corners', image)
4.3 SIFT/SURF算法
4.3.1 SIFT算法
原理:SIFT(Scale-Invariant Feature Transform)算法,即尺度不变特征变换,是一种用于侦测与描述影像中的局部性特征的电脑视觉算法。该算法由David Lowe在1999年发表,并在2004年进行了完善总结。SIFT算法通过在不同的尺度空间中寻找极值点(也称为关键点或特征点),并提取其位置、尺度、旋转不变量来构建关键点描述符,从而实现对图像特征的提取。
具体参考下面这篇文章:@crossoverpptx
http://t.csdnimg.cn/kCb7Rhttp://t.csdnimg.cn/kCb7R注:在Python中使用OpenCV库进行SIFT(尺度不变特征变换,Scale-Invariant Feature Transform)特征点提取时,需要注意的是,从OpenCV 4.x版本开始,SIFT算法被移到了opencv-contrib模块中,因为它涉及到了专利问题。在较旧的OpenCV版本中(如3.x),SIFT算法可能直接包含在opencv-python包中。
API:
sift = cv2.SIFT_create()
keypoints, descriptors = sift.detectAndCompute(img, None)
SIFT_create()
方法可以接受一些参数来自定义SIFT特征提取的行为,但通常情况下,使用默认参数即可获得较好的效果。以下是一些可选参数:
nfeatures
(int):要返回的特征点的最大数量。设置为0表示返回所有检测到的特征点。nOctaveLayers
(int):每个尺度空间中的层数。默认值通常为3。contrastThreshold
(float):决定哪些关键点将被接受的最小对比度。edgeThreshold
(float):用于过滤边缘响应的低对比度候选点的阈值。sigma
(float):用于初始化高斯平滑的sigma值。
示例:
# 读取图像
img = cv2.imread('your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 检测关键点和描述符
keypoints, descriptors = sift.detectAndCompute(img, None)
# 显示图像和关键点
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('SIFT Keypoints', img_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.3.2 SURF算法
原理:SURF(Speeded-up Robust Features)算法是一种加速且鲁棒的局部特征提取算法,它是SIFT(Scale-Invariant Feature Transform)算法的改进版和加速版。SURF算法在保持SIFT算法优良性能的同时,通过引入积分图像和盒式滤波器等方法,显著提高了运算速度。SURF算法由Herbert Bay等人在2006年提出,并发表在当年的欧洲计算机视觉国际会议(ECCV)上。该算法主要用于图像的特征点提取和描述,具有对旋转、尺度缩放、亮度变化等保持不变性的优点,同时对视角变换、仿射变换、噪声也保持一定程度的稳定性。
具体参考下面这篇文章:@dl_风禾
http://t.csdnimg.cn/wnuA6http://t.csdnimg.cn/wnuA6注:
cv2.xfeatures2d.SURF_create()
函数用于创建一个SURF检测器对象。需要注意的是,在OpenCV的某些版本中(尤其是OpenCV 4.x及以上),SURF算法被包含在了opencv-contrib
模块中,因此你需要确保已经安装了opencv-contrib-python
包。
API:
cv2.xfeatures2d.SURF_create()
cv2.xfeatures2d.SURF_create()
函数可以接受多个可选参数来自定义SURF特征提取的行为。这些参数包括:
参数名称 | 类型 | 默认值 | 描述 |
---|---|---|---|
hessianThreshold | float | 100 | Hessian矩阵行列式响应值的阈值。用于控制检测到的特征点的数量和质量。阈值越高,检测到的特征点越少。 |
nOctaves | int | 4 | 金字塔组数。决定了图像金字塔中图像的层数,从而影响特征点的尺度范围。 |
nOctaveLayers | int | 3 | 每组金字塔中的层数。该值加2等于每组图像中所包含的层数。 |
extended | bool | False | 扩展描述符标志。当设置为True时,使用128维的扩展描述符;当设置为False时,使用64维的基本描述符。扩展描述符提供了更多的特征信息,但会增加计算量和存储需求。 |
upright | bool | False | 垂直向上或旋转的特征标志。当设置为True时,不计算特征点的方向,使得算法速度更快,但会失去旋转不变性。当设置为False时,计算特征点的方向,保持旋转不变性。 |
示例:
img = cv2.imread('your_image.jpg', cv2.IMREAD_GRAYSCALE)
# 创建SURF检测器
surf = cv2.xfeatures2d.SURF_create(hessianThreshold=400, nOctaves=4, nOctaveLayers=3, extended=True, upright=False)
# 检测关键点和描述符
keypoints, descriptors = surf.detectAndCompute(img, None)
# 显示图像和关键点
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('SURF Keypoints', img_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.4 Fast和ORB算法
4.4.1 Fast算法
原理:参考下面这篇文章:@暖洋洋的好日子
【CV学习7】FAST算法详解-CSDN博客https://blog.csdn.net/liuyuehui110/article/details/131308690API:
cv2.FastFeatureDetector_create([, threshold[, nonmaxSuppression[, type]]])
- threshold:
- 类型: int
- 默认值: 通常OpenCV文档或实现中可能会给出默认值,但具体值可能因OpenCV版本而异。常见的默认值是10或类似的较小整数。
- 描述: 用于判断角点的阈值。如果圆周上有n个连续像素点的灰度值小于
Ip - t
或者大于Ip + t
(其中Ip
是中心像素的灰度值,t是阈值),则这个中心像素点被认为是角点。n的值通常为9或12,但在OpenCV的FastFeatureDetector
中,它可能通过其他参数或内部机制来管理。
- nonmaxSuppression:
- 类型: bool
- 默认值: True
- 描述: 是否使用非极大值抑制。非极大值抑制是一种用于去除相邻角点中得分较低角点的方法,以避免在局部区域内检测到多个角点。如果设置为True,则启用非极大值抑制;如果设置为False,则关闭此功能。
- type:
- 类型: int
- 默认值: 可能依赖于OpenCV的具体实现,但通常在文档中会有说明。
- 描述: 指定FAST算法的类型或变种。OpenCV中的
FastFeatureDetector
类可能允许用户通过此参数选择不同的FAST变种,如TYPE_5_8
、TYPE_7_12
、TYPE_9_16
等,这些值分别表示使用不同的圆周点数和连续点数作为角点检测的条件。但是,请注意,并非所有OpenCV版本都支持这些特定的类型值,且实际可用的值可能因版本而异。
返回值:
返回一个FastFeatureDetector
对象,该对象可用于检测图像中的角点。
示例:
img = cv2.imread('image.jpg', 0) # 以灰度模式读取图像
# 创建Fast检测器
fast = cv2.FastFeatureDetector_create(threshold=30, nonmaxSuppression=True, type=cv2.FastFeatureDetector_TYPE_9_16)
# 检测角点
keypoints = fast.detect(img, None)
# 绘制角点
img_with_keypoints = cv2.drawKeypoints(img, keypoints, None, color=(0, 0, 255))
# 显示图像
cv2.imshow('FAST Corners', img_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.4.2 ORB算法
原理:参考下面这篇文章
ORB算办法python源码 orb算法原理_小蝌蚪的技术博客_51CTO博客https://blog.51cto.com/u_12226/6940679API:
1. cv2.ORB_create()
这个函数用于初始化ORB检测器。通过这个函数,可以创建一个ORB对象,用于后续的特征点检测和描述符计算。
参数解释:
nfeatures
:最大特征点数量,默认为500。这个参数决定了算法检测到的特征点的最大数量。scaleFactor
:图像金字塔中上下两层之间的尺度比例因子,默认为1.2。这个参数用于构建尺度金字塔,以检测不同尺度的特征点。nlevels
:金字塔的层数,默认为8。这个参数决定了金字塔的层数,从而影响到检测到的特征点的尺度范围。edgeThreshold
:边缘阈值,默认为31。这个参数用于FAST检测时,忽略边缘效应的影响。firstLevel
:用于计算的金字塔的第一层的索引,默认为0。这个参数可以调整金字塔的起始层。WTA_K
:用于计算描述符时,在每个点周围选取的点数,默认为2。这个参数影响描述符的生成。scoreType
:用于对特征点进行排序的准则,默认为cv2.ORB_HARRIS_SCORE
,即使用Harris角点响应值进行排序。patchSize
:用于计算描述符的邻域大小,默认为31。这个参数决定了描述符的局部区域大小。fastThreshold
:FAST检测中使用的阈值,默认为20。这个参数决定了像素点被认为是角点的条件。
返回值:
- 返回一个ORB对象,该对象包含了ORB检测器的所有设置和参数。
2. orb.detectAndCompute()
这个函数用于在图像上检测关键点并计算其描述符。
参数解释:
img
:输入图像,应为灰度图像。mask
:可选参数,用于指定检测区域。如果为None,则在整个图像上检测特征点。
返回值:
kp
:检测到的关键点信息,包括位置、尺度和方向等。des
:关键点的描述符,是一个二进制字符串数组,每个关键点对应一个描述符。
示例:
img = cv2.imread('path_to_image.jpg', cv2.IMREAD_GRAYSCALE)
# 初始化ORB检测器
orb = cv2.ORB_create(nfeatures=500)
# 检测关键点并计算描述符
kp, des = orb.detectAndCompute(img, None)
# 绘制关键点
img_with_keypoints = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)
# 显示图像
cv2.imshow('ORB Keypoints', img_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
4.5 LBP和HOG特征算子
参考下面这篇文章:@あずにゃん
OpenCV:LBP和HOG特征算子_cv2.lbp-CSDN博客https://blog.csdn.net/zimiao552147572/article/details/105346532
5 视频操作
这一部分以后有用到的话再更新,目前需求只是处理图像,故视频操作暂不学习。
6 案例:人脸案例
6.1 Haar特征
参考下面这篇文章:
图像特征提取之Haar特征 - 你的雷哥 - 博客园 (cnblogs.com)https://www.cnblogs.com/henuliulei/p/10589211.html
6.2 人脸检测
import cv2
# 读取图像
image = cv2.imread('img\\001.jpg')
# 获取XML文件,加载人脸检测器
face_cascade = cv2.CascadeClassifier(
'C:\\Users\\20648\\AppData\\Local\\Programs\\Python\\Python311\\Lib\\site-packages\\cv2\\data'
'\\haarcascade_frontalface_default.xml')
# 色彩转换,转换为灰度图像
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 调用函数检测人脸
faces = face_cascade.detectMultiScale(gray, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
# 打印人脸数量
print(f"发现{len(faces)}个人脸!")
# 逐个标注人脸
for (x, y, w, h) in faces:
cv2.rectangle(image, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 显示结果
cv2.imshow("Detected Faces", image)
cv2.waitKey(0)
cv2.destroyAllWindows()
获取XML文件方法:
1、外部库-->site-packages
2、 在site-packages中找到cv2
3、在cv2中找到Data包,打开Data包里面即可找到各种XML文件