深入剖析 OpenCV:全面掌握基础操作、图像处理算法与特征匹配
深入剖析 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 cv2image = 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 cv2image = 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 cv2image = 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 cv2image = 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 npimage = 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 cv2color_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 cv2image = 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 cv2image = 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 cv2image = 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 cv2image = 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 cv2image = 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 npimage = 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 cv2image = 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 npimage = 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 npimage = 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 npimage = 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 cv2image = 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 cv2image = 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 cv2image1 = 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 npimage1 = 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() 函数绘制有效的匹配点。
后面的区域~以后的文章再来探索吧
相关文章:
深入剖析 OpenCV:全面掌握基础操作、图像处理算法与特征匹配
深入剖析 OpenCV:全面掌握基础操作、图像处理算法与特征匹配 一、引言二、OpenCV 的安装(一)使用 pip 安装(二)使用 Anaconda 安装 三、OpenCV 基础操作(一)图像的读取、显示与保存(…...
【C语言显示Linux系统参数】
在C语言中,可以通过调用Linux系统提供的API来获取和显示系统参数。以下是一些常见的系统参数及其获取方法: 1. 获取系统名称和版本 可以使用uname函数来获取系统名称、版本等信息。 #include <stdio.h> #include <sys/utsname.h>int main…...
突破Ajax跨域困境,解锁前端通信新姿势
一、引言 在当今的 Web 开发领域,前后端分离的架构模式已经成为主流,它极大地提升了开发效率和项目的可维护性。在这种开发模式下,前端通过 Ajax 技术与后端进行数据交互,然而,跨域问题却如影随形,成为了开…...
Kotlin协变与逆变区别
在Kotlin中,协变和逆变是泛型编程中的两个重要概念,它们允许我们在类型系统中更加灵活地处理类型关系。 1.协变:协变允许我们使用比原始类型更具体的类型。在kotlin中,通过在类型参数上加out关键字来表示协变,生产者,例…...
driver中为什么要使用非阻塞赋值
1. 模拟硬件时序行为 实际硬件行为:DUT的输入信号通常在时钟边沿被采样。Driver需要确保信号的更新与时钟同步,而非阻塞赋值的延迟更新特性(在时间步结束时统一生效)能够准确模拟寄存器的行为。 示例: always (posedg…...
模板字符串【ES6】
“路漫漫其修远兮,吾将上下而求索。”—— 屈原《离骚》 目录 什么是模板字符串?模板字符串特性及代码举例:详细举例用法: 什么是模板字符串? 模板字符串(Template Literals)是JavaScript中引入…...
通往 AI 之路:Python 机器学习入门-数据结构
Python 数据结构 Python 提供了多种数据结构来存储和操作数据,其中列表(list)、字典(dict)、元组(tuple)和集合(set)是最常用的几种。本章将详细介绍这些数据结构的基本…...
我们应该如何优化UI(基于UGUI)
这是一道面试题,下面,我们来详细分析这个问题。 目录 1. 减少 Draw Call 合理设置图集 避免材质和 Shader 的频繁切换 减少 UI 元素的重叠 2. 优化UI布局 3. 优化UI元素的渲染 4.优化UI动画 5. 优化 UI 事件处理 6. 运行时优化 1. 减少 Draw C…...
CSS3 圆角:实现与优化指南
CSS3 圆角:实现与优化指南 随着网页设计的发展,CSS3 圆角已经成为了现代网页设计中不可或缺的元素之一。本文将详细讲解 CSS3 圆角的基本用法、实现方式以及优化技巧,帮助您在网页设计中更好地运用这一功能。 一、CSS3 圆角基本用法 1.1 基…...
【网络安全 | 扫描子域+发现真实IP】CloakQuest3r安装使用详细教程
原创文章,禁止转载。 本文仅作学习交流使用,不得用于非法渗透,笔者不承担任何责任。 文章目录 简介功能介绍执行流程限制安装步骤可选功能:SecurityTrails API使用示例简介 CloakQuest3r 是一款强大的 Python 工具,专为揭示受 Cloudflare 及类似服务保护的网站真实 IP 地…...
Mellanox OFED驱动如何给全局编译添加gcc的编译选项?(subdir-ccflags-y += -Wall)
背景 有些时候编译驱动需要给全局加一个编译选项,假设configure已经完成。可以直接在Makefile中修改 添加方式 修改OFED驱动目录下的: ./Makefile subdir-ccflags-y -Wall修改效果: 然后执行make,就能让添加的编译选项生效…...
【愚公系列】《Python网络爬虫从入门到精通》037-文件的存取
标题详情作者简介愚公搬代码头衔华为云特约编辑,华为云云享专家,华为开发者专家,华为产品云测专家,CSDN博客专家,CSDN商业化专家,阿里云专家博主,阿里云签约作者,腾讯云优秀博主,腾讯云内容共创官,掘金优秀博主,亚马逊技领云博主,51CTO博客专家等。近期荣誉2022年度…...
【一起学Rust | Tauri2.0框架】单实例应用程序的深入解析:零漏洞实现与优化实战
文章目录 前言一、 单实例应用的意义二、 实现单实例应用的方法1 Windows下的实现1.1 创建命名Mutex1.2 在Tauri应用中集成Mutex检查 2 macOS下的实现2.1 获取Bundle Identifier2.2 检查是否已经有实例在运行 3 Linux下的实现3.1 获取进程列表3.2 检查是否已经有实例在运行 4 在…...
PhyloSuite v1.2.3安装与使用-生信工具049
PhyloSuite 一个好用的win集成建树平台,官方相关文档视频等做的可好了PhyloSuite (jushengwu.com) 官网 https://github.com/dongzhang0725/PhyloSuite/releases #官网 http://phylosuite.jushengwu.com/dongzhang0725.github.io/installation/ #官方说明文档…...
使用Apache Lucene构建高效的全文搜索服务
使用Apache Lucene构建高效的全文搜索服务 在现代应用程序中,全文搜索功能是不可或缺的一部分。无论是电子商务网站、内容管理系统,还是数据分析平台,快速、准确地搜索大量数据是提升用户体验的关键。Apache Lucene 是一个强大的全文搜索引擎…...
SSH远程登录并执行命令
SSH远程登录并执行命令 1、登录远程服务器2、远程执行命令3、远程执行交互命令4、远程执行脚本5、退出远程SSH连接 SSH是Linux中的远程连接管理工具,可以在本地服务器上通过SSH协议连接到远程服务器,并在远程服务器上执行命令 SSH不仅可以用来登录远程服…...
EasyRTC:支持任意平台设备的嵌入式WebRTC实时音视频通信SDK解决方案
随着互联网技术的飞速发展,实时音视频通信已成为各行各业数字化转型的核心需求之一。无论是远程办公、在线教育、智慧医疗,还是智能安防、直播互动,用户对低延迟、高可靠、跨平台的音视频通信需求日益增长。 一、WebRTC与WebP2P:实…...
Golang语言特性
1.Go语言的优势 1.1极简单的部署方式 —可以直接编译成机器码。代码可以直接转换为二进制数据,在操作系统上可以直接./去执行。 —不依赖其他库。最终生成的可执行程序是一个静态的二进制文本文件。 —可以直接运行即可部署。 —静态类型语言。编译的时候检查出来隐…...
LangPrompt提示词
LangPrompt提示词 https://github.com/langgptai/LangGPT 学习LangGPT的仓库,帮我创建 一个专门生成LangGPT格式prompt的助手 根据LangGPT的格式规范设计的专业提示词生成助手框架。以下是分步骤的解决方案: 助手角色定义模板 # Role: LangGPT提示词架…...
Java 容器之 List
在 Java 的集合框架中,List 是 Collection 的重要子接口,以其有序、可重复的特点广泛应用于开发中。本文将详细探讨 List 的核心概念、主要实现类(如 ArrayList 和 LinkedList)的底层原理,以及使用中需要注意的常见问题…...
ExplorerPatcher使用指南:3步恢复Windows经典界面体验
ExplorerPatcher使用指南:3步恢复Windows经典界面体验 【免费下载链接】ExplorerPatcher This project aims to enhance the working environment on Windows 项目地址: https://gitcode.com/GitHub_Trending/ex/ExplorerPatcher ExplorerPatcher是一款强大的…...
提升前端效率:用快马实践vibe coding快速生成沉浸式番茄钟应用
最近在尝试提升前端开发效率时,发现了一种很有意思的开发方式——vibe coding。简单来说,就是通过描述想要的界面氛围和交互感觉,快速生成对应的功能代码。这种方式特别适合需要快速验证想法或者搭建基础框架的场景。 今天就用InsCode(快马)…...
黑马点评-“附近商户“功能无法实现
问题分析 由于Redis版本不够,因此我们使用不了GEOSEARCH命令(Redis 6.2.0 或更高版本) 需要升级Redis版本 下载高版本Redis Redis8.6.2点此下载 后缀的区别: 带有 -with-Service vs 不带 with-Service: 包含了将 Redis 注册为 Windows 系统后台服务的相关…...
专业级流媒体下载器实战解析:7个高效配置技巧掌握N_m3u8DL-RE
专业级流媒体下载器实战解析:7个高效配置技巧掌握N_m3u8DL-RE 【免费下载链接】N_m3u8DL-RE Cross-Platform, modern and powerful stream downloader for MPD/M3U8/ISM. English/简体中文/繁體中文. 项目地址: https://gitcode.com/GitHub_Trending/nm3/N_m3u8D…...
深入理解Vue的响应式原理:从Object.defineProperty到Proxy
Vue的响应式系统是其核心特性之一,它使得数据变化能够自动驱动视图更新。从Vue 2.x的Object.defineProperty到Vue 3.x的Proxy,这一演进不仅是技术实现上的突破,更体现了Vue对性能、兼容性和开发体验的深度思考。以下从技术原理、实现差异、性…...
AI智能体(Agent)的底层逻辑
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言 一、核心模块? 二、工作流程 三、关键设计思想 3.1 ReAct 模式 3.2 工具调用(Function Calling) 3.3 记忆管理 3.4 多智能体…...
2026届必备的AI辅助写作平台解析与推荐
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 人工智能论文工具正渐渐在学术写作流程里掺杂进来,变成研究者提高效率的管用帮手…...
丹青识画快速部署:开箱即用,体验智能影像理解与书法生成
丹青识画快速部署:开箱即用,体验智能影像理解与书法生成 1. 产品概览:当AI遇见东方美学 丹青识画是一款融合深度学习与东方美学的智能影像理解系统。它能够像一位精通诗书画的文人雅士般,精准解读画面内容,并以行云流…...
三层交换+单臂路由+ACL网络配置
一、拓扑与IP规划设备VLAN网关IP地址PC1/PC32192.168.2.254192.168.2.1/2PC23192.168.3.254192.168.3.1PC44192.168.4.254192.168.4.1PC55192.168.5.254192.168.5.1PC66192.168.6.254192.168.6.1二、交换机配置LSW1system-view vlan batch 2 3 4 5 6 interface GigabitEthernet…...
大麦网抢票自动化工具:5分钟快速上手完整指南
大麦网抢票自动化工具:5分钟快速上手完整指南 【免费下载链接】damaihelper 支持大麦网,淘票票、缤玩岛等多个平台,演唱会演出抢票脚本 项目地址: https://gitcode.com/gh_mirrors/dam/damaihelper 你是否曾经因为抢不到心仪的演唱会门…...
