深入剖析 OpenCV:全面掌握基础操作、图像处理算法与特征匹配
- 一、引言
- 二、OpenCV 的安装
- (一)使用 pip 安装
- (二)使用 Anaconda 安装
- 三、OpenCV 基础操作
- (一)图像的读取、显示与保存
- (二)图像的基本属性与操作
- (三)颜色空间转换
- 四、OpenCV 的图像处理算法
- (一)图像滤波
- (二)边缘检测
- (三)形态学操作
- 五、OpenCV 的特征提取与匹配
- (一)ORB 特征提取
- (二)SIFT 特征提取
- (三)特征匹配
- 1. ORB 特征匹配
- 2. SIFT 特征匹配
一、引言
在当今数字化的时代,计算机视觉技术正以前所未有的速度改变着我们的生活。从智能手机的人脸识别解锁到自动驾驶汽车的环境感知,从工业生产中的质量检测到医疗领域的影像分析,计算机视觉无处不在。OpenCV(Open Source Computer Vision Library)作为计算机视觉领域最具影响力的开源库之一,为开发者和研究人员提供了强大而便捷的工具。它拥有超过 2500 种优化算法,涵盖了图像和视频处理、特征提取、目标检测、机器学习等多个领域。本文将基于 Python 语言,全面深入地介绍 OpenCV 的各个方面,从基础操作到高级应用,帮助读者逐步掌握这一强大的工具。
二、OpenCV 的安装
在 Python 环境中安装 OpenCV 非常便捷,主要有两种常见的安装方式。
(一)使用 pip 安装
通过 pip
包管理器,我们可以轻松地安装 OpenCV。在命令行中输入以下命令:
pip install opencv-python
如果需要安装包含扩展功能的版本(如 SIFT、SURF 等算法,这些算法在非商业用途下可用),可以使用以下命令:
pip install opencv-contrib-python
(二)使用 Anaconda 安装
如果你使用 Anaconda 作为 Python 环境管理工具,可以使用以下命令进行安装:
conda install -c conda-forge opencv
安装完成后,我们可以在 Python 代码中导入 OpenCV 库进行测试:
import cv2
print(cv2.__version__)
如果能够正常输出 OpenCV 的版本号,说明安装成功。
如4.11.0
以下是去掉对图像读取检查后的代码内容,为你扩充了标题 3 - 5 的代码和解释:
三、OpenCV 基础操作
(一)图像的读取、显示与保存
- 读取图像
使用cv2.imread()
函数读取图像文件,支持常见的图像格式如.jpg
、.png
等。函数第一个参数为图像文件路径,第二个参数指定读取模式。常见的读取模式有:cv2.IMREAD_COLOR
:以彩色模式读取图像,默认模式。cv2.IMREAD_GRAYSCALE
:以灰度模式读取图像。cv2.IMREAD_UNCHANGED
:读取包含透明度通道的图像。
import cv2
# 以彩色模式读取图像
color_image = cv2.imread('example.jpg', cv2.IMREAD_COLOR)
# 以灰度模式读取图像
gray_image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 读取包含透明度通道的图像
alpha_image = cv2.imread('example.png', cv2.IMREAD_UNCHANGED)
解释:cv2.imread()
是 OpenCV 中用于读取图像的核心函数。通过不同的读取模式参数,可以灵活地获取图像的不同表示形式。彩色模式读取的图像包含三个通道(BGR),灰度模式将图像转换为单通道,而读取带透明度通道的图像适用于处理 PNG 等支持透明度的图像格式。
- 显示图像
通过cv2.imshow()
函数显示图像,第一个参数是窗口名称,第二个参数是要显示的图像对象。使用cv2.waitKey()
等待用户按键,cv2.destroyAllWindows()
关闭所有窗口。
# 显示彩色图像
cv2.imshow('Color Image', color_image)
# 显示灰度图像
cv2.imshow('Gray Image', gray_image)
# 等待用户按键(0 表示无限等待)
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
解释:cv2.imshow()
用于在一个新窗口中显示图像,窗口名称用于区分不同的显示窗口。cv2.waitKey()
函数会阻塞程序,直到用户按下任意键,参数为 0 时表示无限等待。cv2.destroyAllWindows()
用于关闭所有由 OpenCV 创建的窗口,释放资源。
- 保存图像
利用cv2.imwrite()
函数保存图像,第一个参数为保存路径,第二个参数是要保存的图像。
# 保存灰度图像
cv2.imwrite('saved_gray_image.jpg', gray_image)
解释:cv2.imwrite()
函数将指定的图像保存到指定的文件路径。保存的文件格式由文件扩展名决定,如 .jpg
、.png
等。
(二)图像的基本属性与操作
- 图像的基本属性
图像在 OpenCV 中以 NumPy 数组形式存储,我们可以获取其高度、宽度和通道数等属性。
import cv2
image = cv2.imread('example.jpg')
height, width, channels = image.shape
print(f"图像高度: {height}, 宽度: {width}, 通道数: {channels}")
# 额外获取图像的数据类型
print(f"图像的数据类型: {image.dtype}")
解释:图像在 OpenCV 里被存储为 NumPy 数组,通过 shape
属性可以获取图像的基本尺寸信息,dtype
属性则能查看图像的数据类型,通常为 uint8
(8 位无符号整数)。
- 图像的像素访问
可以直接通过索引访问和修改图像的像素值。
import cv2
image = cv2.imread('example.jpg')
# 获取坐标(100, 100)处的像素值(BGR 格式)
pixel = image[100, 100]
print(f"坐标(100, 100)处的像素值(BGR 格式): {pixel}")
# 修改坐标(100, 100)处的像素值为白色
image[100, 100] = [255, 255, 255]
new_pixel = image[100, 100]
print(f"修改后坐标(100, 100)处的像素值(BGR 格式): {new_pixel}")
解释:由于图像是 NumPy 数组,所以可以像操作数组一样通过索引来访问和修改像素值。在 OpenCV 中,彩色图像的像素值是按 BGR(蓝、绿、红)顺序存储的。
- 图像的裁剪、缩放与旋转
- 裁剪
通过指定行和列的范围来裁剪图像。
import cv2
image = cv2.imread('example.jpg')
# 裁剪图像,获取坐标(100, 100)到(300, 300)的区域
cropped_image = image[100:300, 100:300]
cv2.imshow('Cropped Image', cropped_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:裁剪图像是通过指定数组的行和列范围来实现的,即选取图像中指定区域的像素值,形成新的图像。
- 缩放
使用cv2.resize()
函数缩放图像,可以指定缩放比例或目标尺寸。
import cv2
image = cv2.imread('example.jpg')
# 按比例缩放,宽度和高度都变为原来的 0.5 倍
resized_image_1 = cv2.resize(image, None, fx=0.5, fy=0.5)
cv2.imshow('Resized Image by Scale', resized_image_1)
# 指定目标尺寸进行缩放
resized_image_2 = cv2.resize(image, (300, 300))
cv2.imshow('Resized Image by Size', resized_image_2)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:cv2.resize()
函数提供了灵活的缩放方式。fx
和 fy
参数用于指定水平和垂直方向的缩放比例,当第二个参数为 None
时使用这种方式。也可以直接指定目标尺寸,如 (300, 300)
来进行缩放。
- 旋转
借助cv2.getRotationMatrix2D()
获取旋转矩阵,再用cv2.warpAffine()
进行旋转操作。
import cv2
import numpy as np
image = cv2.imread('example.jpg')
height, width = image.shape[:2]
# 计算旋转中心
center = (width / 2, height / 2)
# 定义旋转角度和缩放因子
angle = 45
scale = 1.0
# 获取旋转矩阵
M = cv2.getRotationMatrix2D(center, angle, scale)
# 对图像进行旋转
rotated_image = cv2.warpAffine(image, M, (width, height))
cv2.imshow('Rotated Image', rotated_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:cv2.getRotationMatrix2D()
用于计算旋转矩阵,该矩阵包含了旋转中心、旋转角度和缩放因子等信息。cv2.warpAffine()
函数根据这个旋转矩阵对图像进行仿射变换,实现图像的旋转操作。
(三)颜色空间转换
常见的颜色空间有 RGB、灰度、HSV、Lab 等,使用 cv2.cvtColor()
函数进行颜色空间转换。
import cv2
color_image = cv2.imread('example.jpg')
# 转换为灰度图像
gray_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2GRAY)
cv2.imshow('Gray Image', gray_image)
# 转换为 HSV 图像
hsv_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2HSV)
cv2.imshow('HSV Image', hsv_image)
# 转换为 Lab 图像
lab_image = cv2.cvtColor(color_image, cv2.COLOR_BGR2Lab)
cv2.imshow('Lab Image', lab_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:不同的颜色空间适用于不同的图像处理任务。cv2.cvtColor()
函数可以在不同颜色空间之间进行转换,例如将 BGR 彩色图像转换为灰度图像、HSV 图像或 Lab 图像,方便后续的处理和分析。
四、OpenCV 的图像处理算法
(一)图像滤波
- 均值滤波
使用cv2.blur()
函数实现,通过计算局部区域像素平均值平滑图像。
import cv2
image = cv2.imread('example.jpg')
# 均值滤波,核大小为(5, 5)
blurred_image = cv2.blur(image, (5, 5))
cv2.imshow('Blurred Image (Mean Filter)', blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:均值滤波是一种简单的线性滤波方法,它以一个固定大小的核(如 (5, 5)
)在图像上滑动,计算每个核内像素的平均值,并将该平均值作为中心像素的新值,从而达到平滑图像的效果。
- 高斯滤波
利用cv2.GaussianBlur()
函数,基于高斯函数对图像进行滤波,抑制噪声同时保留边缘。
import cv2
image = cv2.imread('example.jpg')
# 高斯滤波,核大小为(5, 5),标准差为 0
gaussian_blurred_image = cv2.GaussianBlur(image, (5, 5), 0)
cv2.imshow('Blurred Image (Gaussian Filter)', gaussian_blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:高斯滤波是一种非线性滤波方法,它根据高斯函数对核内的像素进行加权平均。相比于均值滤波,高斯滤波在抑制噪声的同时能更好地保留图像的边缘信息,因为它对不同位置的像素赋予了不同的权重。
- 中值滤波
通过cv2.medianBlur()
函数,用局部区域的中值替换当前像素值,有效去除椒盐噪声。
import cv2
image = cv2.imread('example.jpg')
# 中值滤波,核大小为 5
median_blurred_image = cv2.medianBlur(image, 5)
cv2.imshow('Blurred Image (Median Filter)', median_blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:中值滤波是一种非线性滤波方法,它将核内的像素值进行排序,然后用中值替换中心像素的值。这种方法对于去除椒盐噪声(图像中出现的黑白孤立点)非常有效。
- 双边滤波
cv2.bilateralFilter()
函数可以在平滑图像的同时保留边缘信息,适用于需要保留图像细节的场景。
import cv2
image = cv2.imread('example.jpg')
# 双边滤波,直径为 9,颜色标准差为 75,空间标准差为 75
bilateral_blurred_image = cv2.bilateralFilter(image, 9, 75, 75)
cv2.imshow('Blurred Image (Bilateral Filter)', bilateral_blurred_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:双边滤波是一种保边滤波方法,它结合了空间域和值域的信息。在平滑图像时,它不仅考虑像素的空间距离,还考虑像素的颜色差异,因此能够在平滑图像的同时很好地保留边缘和细节信息。
(二)边缘检测
- Canny 边缘检测
cv2.Canny()
函数是常用的边缘检测算法,通过计算图像梯度和非极大值抑制等步骤检测边缘。
import cv2
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# Canny 边缘检测,设置高低阈值
edges = cv2.Canny(image, 100, 200)
cv2.imshow('Canny Edge Detection', edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:Canny 边缘检测是一种多阶段的边缘检测算法,主要包括高斯平滑、梯度计算、非极大值抑制和双阈值处理等步骤。高低阈值参数用于控制边缘的检测范围,只有当梯度值大于高阈值时才被确定为边缘,介于高低阈值之间的像素如果与确定的边缘相连也会被保留。
- Sobel 边缘检测
cv2.Sobel()
函数用于计算图像在 x 和 y 方向上的梯度,从而检测边缘。
import cv2
import numpy as np
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 计算 x 方向的 Sobel 梯度
sobelx = cv2.Sobel(image, cv2.CV_64F, 1, 0, ksize=3)
# 计算 y 方向的 Sobel 梯度
sobely = cv2.Sobel(image, cv2.CV_64F, 0, 1, ksize=3)
# 取绝对值并转换为 8 位无符号整数
sobelx = np.uint8(np.absolute(sobelx))
sobely = np.uint8(np.absolute(sobely))
# 合并 x 和 y 方向的梯度
sobel_combined = cv2.bitwise_or(sobelx, sobely)
cv2.imshow('Sobel Edge Detection', sobel_combined)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:Sobel 算子是一种一阶导数算子,用于计算图像在 x 和 y 方向上的梯度。通过分别计算两个方向的梯度,可以检测出图像中的水平和垂直边缘。最后将两个方向的梯度合并,得到完整的边缘信息。
- Laplacian 边缘检测
cv2.Laplacian()
函数通过计算图像的二阶导数来检测边缘。
import cv2
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# Laplacian 边缘检测
laplacian_edges = cv2.Laplacian(image, cv2.CV_64F)
laplacian_edges = np.uint8(np.absolute(laplacian_edges))
cv2.imshow('Laplacian Edge Detection', laplacian_edges)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:Laplacian 算子是一种二阶导数算子,它对图像的灰度变化非常敏感,能够检测出图像中的边缘。由于二阶导数可能为负值,所以需要取绝对值并转换为 8 位无符号整数才能正确显示边缘图像。
(三)形态学操作
- 膨胀与腐蚀
膨胀操作可以扩大图像中的前景区域,腐蚀操作则可以缩小前景区域。
import cv2
import numpy as np
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 定义结构元素
kernel = np.ones((5, 5), np.uint8)
# 膨胀操作
dilated_image = cv2.dilate(image, kernel, iterations=1)
# 腐蚀操作
eroded_image = cv2.erode(image, kernel, iterations=1)
cv2.imshow('Dilated Image', dilated_image)
cv2.imshow('Eroded Image', eroded_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:膨胀和腐蚀是基本的形态学操作,它们基于结构元素(如 (5, 5)
的全 1 矩阵)对图像进行处理。膨胀操作将结构元素在图像上滑动,如果结构元素与前景区域有重叠,则将中心像素置为前景;腐蚀操作则相反,如果结构元素完全包含在前景区域内,才将中心像素置为前景。
- 开运算与闭运算
开运算先进行腐蚀操作,再进行膨胀操作,用于去除小的噪声点;闭运算先进行膨胀操作,再进行腐蚀操作,用于填充小的空洞。
import cv2
import numpy as np
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
kernel = np.ones((5, 5), np.uint8)
# 开运算
opening = cv2.morphologyEx(image, cv2.MORPH_OPEN, kernel)
# 闭运算
closing = cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel)
cv2.imshow('Opening Image', opening)
cv2.imshow('Closing Image', closing)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:开运算和闭运算是基于膨胀和腐蚀操作的组合。开运算可以去除图像中的小噪声点,同时保持大的前景区域不变;闭运算则可以填充前景区域内的小空洞,使前景区域更加完整。
- 形态学梯度
形态学梯度是膨胀图像与腐蚀图像的差值,用于突出图像的边缘。形态学梯度能够帮助我们检测图像中物体的边界,在图像分割、目标检测等领域有着广泛的应用。
import cv2
import numpy as np
image = cv2.imread('example.jpg', cv2.IMREAD_GRAYSCALE)
# 定义结构元素,这里使用 5x5 的全 1 矩阵
kernel = np.ones((5, 5), np.uint8)
# 进行膨胀操作
dilated_image = cv2.dilate(image, kernel, iterations=1)
# 进行腐蚀操作
eroded_image = cv2.erode(image, kernel, iterations=1)
# 计算形态学梯度,即膨胀图像减去腐蚀图像
gradient = cv2.morphologyEx(image, cv2.MORPH_GRADIENT, kernel)
# 也可以手动计算形态学梯度
manual_gradient = cv2.subtract(dilated_image, eroded_image)
# 显示原始图像
cv2.imshow('Original Image', image)
# 显示通过 cv2.morphologyEx 计算得到的形态学梯度图像
cv2.imshow('Morphological Gradient (cv2.morphologyEx)', gradient)
# 显示手动计算得到的形态学梯度图像
cv2.imshow('Morphological Gradient (Manual)', manual_gradient)
# 等待用户按键
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
解释:
- 结构元素定义:我们使用
np.ones((5, 5), np.uint8)
定义了一个 5x5 的全 1 矩阵作为结构元素。结构元素的大小和形状会影响形态学操作的效果,不同的任务可能需要不同的结构元素。 - 膨胀和腐蚀操作:通过
cv2.dilate()
和cv2.erode()
函数分别对图像进行膨胀和腐蚀操作。膨胀操作会使图像中的前景区域扩大,而腐蚀操作会使前景区域缩小。 - 形态学梯度计算:
- 使用
cv2.morphologyEx()
:这是 OpenCV 提供的用于进行复杂形态学操作的函数,cv2.MORPH_GRADIENT
表示计算形态学梯度。 - 手动计算:通过
cv2.subtract()
函数将膨胀后的图像减去腐蚀后的图像,也能得到形态学梯度。这两种方法的结果是相同的,但使用cv2.morphologyEx()
更简洁。
- 使用
- 图像显示:使用
cv2.imshow()
函数分别显示原始图像、通过cv2.morphologyEx
计算得到的形态学梯度图像以及手动计算得到的形态学梯度图像,方便我们对比和观察形态学梯度的效果。
通过形态学梯度,我们可以清晰地看到图像中物体的边缘信息,这对于后续的图像处理和分析非常有帮助。例如,在目标检测中,我们可以利用形态学梯度来初步定位物体的边界,然后再进行更精确的检测和识别。
五、OpenCV 的特征提取与匹配
(一)ORB 特征提取
ORB(Oriented FAST and Rotated BRIEF)是一种快速的特征提取和描述算法。它结合了 FAST(Features from Accelerated Segment Test)特征点检测和 BRIEF(Binary Robust Independent Elementary Features)描述符,并且对其进行了改进,使其具有旋转不变性。
import cv2
image = cv2.imread('example.jpg')
# 创建 ORB 对象
orb = cv2.ORB_create()
# 检测特征点并计算描述符
keypoints, descriptors = orb.detectAndCompute(image, None)
# 在图像上绘制特征点
image_with_keypoints = cv2.drawKeypoints(image, keypoints, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('ORB Keypoints', image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:首先使用 cv2.ORB_create()
创建一个 ORB 对象。detectAndCompute()
方法用于检测图像中的特征点并计算对应的描述符。特征点是图像中具有独特特征的点,描述符则是对这些特征点的一种量化表示,用于后续的特征匹配。cv2.drawKeypoints()
函数将检测到的特征点绘制在原始图像上,方便我们直观地看到特征点的位置。
(二)SIFT 特征提取
SIFT(尺度不变特征变换)是一种具有尺度、旋转和光照不变性的特征提取算法,但由于专利问题,在使用时需要安装 opencv - contrib - python
库。SIFT 算法通过在不同尺度空间上查找极值点来检测特征点,并计算其主方向和描述符。
import cv2
image = cv2.imread('example.jpg')
# 创建 SIFT 对象
sift = cv2.SIFT_create()
# 检测特征点并计算描述符
keypoints, descriptors = sift.detectAndCompute(image, None)
# 在图像上绘制特征点
image_with_keypoints = cv2.drawKeypoints(image, keypoints, None, color=(0, 255, 0), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('SIFT Keypoints', image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:cv2.SIFT_create()
用于创建一个 SIFT 对象。与 ORB 类似,detectAndCompute()
方法检测特征点并计算描述符。SIFT 算法对图像的尺度、旋转和光照变化具有较好的鲁棒性,因此在很多场景下都能得到较好的特征提取效果。最后使用 cv2.drawKeypoints()
函数将特征点绘制在图像上进行可视化。
(三)特征匹配
特征匹配是计算机视觉中一个重要的任务,用于在不同图像中找到对应的特征点。这里将分别介绍使用 ORB 特征和 SIFT 特征进行匹配的方法。
1. ORB 特征匹配
使用 cv2.BFMatcher()
进行 ORB 特征匹配。
import cv2
image1 = cv2.imread('image1.jpg')
image2 = cv2.imread('image2.jpg')
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(image1, None)
kp2, des2 = orb.detectAndCompute(image2, None)
# 创建 Brute - Force 匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 匹配描述符
matches = bf.match(des1, des2)
# 按照距离排序
matches = sorted(matches, key=lambda x: x.distance)
# 绘制前 10 个匹配点
matching_result = cv2.drawMatches(image1, kp1, image2, kp2, matches[:10], None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('ORB Feature Matching', matching_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:首先分别对两张图像使用 ORB 算法检测特征点并计算描述符。cv2.BFMatcher()
创建一个暴力匹配器,cv2.NORM_HAMMING
表示使用汉明距离来衡量描述符之间的相似度,crossCheck = True
表示只保留那些相互匹配的特征点对。bf.match()
方法进行特征匹配,返回匹配结果。将匹配结果按照距离排序,距离越小表示匹配度越高。最后使用 cv2.drawMatches()
函数绘制前 10 个匹配点,方便我们观察匹配效果。
2. SIFT 特征匹配
对于 SIFT 特征,可以使用 FLANN(快速最近邻近似库)进行匹配。
import cv2
import numpy as np
image1 = cv2.imread('image1.jpg')
image2 = cv2.imread('image2.jpg')
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(image1, None)
kp2, des2 = sift.detectAndCompute(image2, None)
# FLANN 参数设置
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
# 创建 FLANN 匹配器
flann = cv2.FlannBasedMatcher(index_params, search_params)
# 匹配描述符
matches = flann.knnMatch(des1, des2, k=2)
# 应用比率测试
good_matches = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
good_matches.append(m)
# 绘制匹配点
matching_result = cv2.drawMatches(image1, kp1, image2, kp2, good_matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow('SIFT Feature Matching', matching_result)
cv2.waitKey(0)
cv2.destroyAllWindows()
解释:同样先对两张图像使用 SIFT 算法检测特征点并计算描述符。FLANN 是一种快速的近似最近邻搜索算法,适合处理大规模的特征匹配问题。index_params
和 search_params
分别设置 FLANN 的索引参数和搜索参数。flann.knnMatch()
方法返回每个特征点的 k 个最近邻匹配结果。为了提高匹配的准确性,使用比率测试,即当第一个匹配的距离小于第二个匹配距离的 0.7 倍时,才认为这个匹配是有效的。最后使用 cv2.drawMatches()
函数绘制有效的匹配点。
后面的区域~以后的文章再来探索吧