【python】OpenCV—Feature Detection and Matching

在这里插入图片描述

参考学习来自OpenCV基础(23)特征检测与匹配

文章目录

  • 1 背景介绍
  • 2 Harris角点检测
  • 3 Shi-Tomasi角点检测
  • 4 Fast 角点检测
  • 5 BRIEF 特征描述子
  • 6 ORB(Oriented Fast and Rotated Brief) 特征描述子
  • 7 SIFT(Scale Invariant Feature Transform) 特征描述子
  • 8 SURF(Speeded Up Robust Features) 特征描述子
  • 9 Brute-Force Matcher 特征匹配
  • 10 FLANN Matcher 特征匹配

1 背景介绍

在这里插入图片描述

在计算机图像处理中,特征检测和匹配是两个至关重要的环节,它们在多个领域如SLAM(即时定位与地图构建)、SFM(结构从运动恢复)、AR(增强现实)、VR(虚拟现实)等中发挥着关键作用。以下是对特征检测和匹配的详细解析:

一、特征检测

  1. 定义与意义

特征检测是指使用计算机算法从图像中提取出具有独特性质的特征点,这些特征点能够代表图像中的关键信息,并且通常具有旋转、尺度和光照变化的不变性。这些特性使得特征点在图像的不同位置和角度下都能被准确检测。

  1. 特征点的性质
  • 独特性:特征点应具有足够的独特性,以便在不同图像间进行区分。
  • 可重复性:同一场景的不同图像所提取的特征点应保持一致。
  • 稳定性:即使图像发生光照、旋转或尺度变化,特征点也应保持稳定。
  1. 检测方法
  • 基于图像的亮度:通过图像导数来检测图像中的局部极值点,如SIFT(尺度不变特征变换)算法。
  • 基于边界提取:通过边缘检测和曲率分析来提取特征点,如Canny边缘检测算法后进一步分析边缘的走向。
  1. 常用算法
  • SIFT(尺度不变特征变换):该算法通过构建图像金字塔,在不同尺度下寻找局部极值点,并生成描述子来描述这些特征点。
  • ORB(Oriented FAST and Rotated BRIEF):ORB算法结合了FAST特征点检测子和BRIEF特征描述子,并加入了方向信息,提高了特征点的旋转不变性。
  • HOG(方向梯度直方图):虽然HOG主要用于目标检测,但它通过计算和统计图像局部区域的梯度方向直方图来构成特征,也是一种有效的特征描述方法。

二、特征匹配

  1. 定义与意义

特征匹配是指将两个或多个图像中的特征点进行对应,以实现图像间的关联和匹配。通过特征匹配,可以进行目标跟踪、图像配准、三维重建等任务。

  1. 匹配方法
  • 距离计算:常见的距离计算方法包括欧式距离、余弦距离等,用于计算特征向量之间的距离,从而确定特征点之间的匹配关系。
  • 匹配算法:常用的匹配算法包括暴力匹配(BruteForce)和基于近似最近邻的匹配(FlannBased)等。
  1. 匹配策略
  • 单应性矩阵估计:在图像配准和拼接中,常通过估计单应性矩阵来实现两幅图像之间的变换关系。
  • RANSAC(随机抽样一致算法):在存在大量误匹配点的情况下,RANSAC算法可以通过迭代的方式找到最佳的单应性矩阵估计。

三、总结

在计算机图像处理中,特征检测和匹配是实现图像识别、目标跟踪、图像配准等任务的基础。通过设计和改进特征点检测算法、优化特征描述子、采用多尺度和多模态特征检测与匹配策略,以及应用深度学习等先进技术,可以进一步提高特征检测和匹配的准确性和鲁棒性。这些技术的应用不仅推动了计算机视觉领域的发展,也为自动驾驶、智能监控、虚拟现实等多个领域提供了有力的技术支持。

2 Harris角点检测

在这里插入图片描述

在这里插入图片描述

特征值,特征向量(花了10分钟,终于弄懂了特征值和特征向量到底有什么意义)

在这里插入图片描述

Harris角点检测是一种在计算机视觉中广泛应用的角点检测算法,它能够有效地在图像中检测出角点特征。以下是关于Harris角点检测的详细介绍:

  1. 定义与原理
  • 定义:Harris角点检测用于检测图像中的角点,这些角点通常表示物体的边缘或角落,是图像中具有明显亮度变化的位置。
  • 原理:Harris角点检测算法通过计算图像中每个像素的角点响应函数来确定角点的位置。该算法首先计算图像的梯度,然后计算每个像素周围窗口内的梯度幅值和方向的自相关矩阵。接着,使用这个自相关矩阵来计算每个像素的角点响应函数,该函数度量了像素周围区域的角点特征。最后,通过非极大值抑制来保留局部最大值作为角点。
  1. 优点
  • 鲁棒性强:Harris角点检测算法对图像的旋转、缩放和亮度变化具有较好的鲁棒性。
  • 计算效率高:算法的计算复杂度相对较低,适用于实时应用。
  • 检测准确性高:Harris角点检测算法能够准确地检测出图像中的角点位置。
  1. 缺点
  • 对噪声敏感:算法对图像中的噪声比较敏感,可能会将噪声误判为角点。
  • 对尺度变化不敏感:Harris角点检测算法在处理尺度变化较大的图像时效果较差。
  • 对旋转变化不敏感:虽然算法对图像的旋转变化有一定的鲁棒性,但在某些情况下可能会导致角点检测结果不准确。
  1. 改进方法

为了解决Harris角点检测算法的一些缺点,研究者们提出了一些改进的方法,如尺度不变特征变换(SIFT)和加速稳健特征(SURF)等。这些改进算法在角点检测的准确性和鲁棒性上有所提升。

  1. 应用领域

Harris角点检测算法在计算机视觉领域有广泛的应用,包括但不限于

  • 物体识别:通过检测物体上的角点特征来进行物体识别。
  • 图像配准:利用角点特征来对齐和匹配两幅或多幅图像。
  • 三维重建:通过角点检测来提取和重建物体的三维结构。

总之,Harris角点检测是一种简单、快速且有效的角点检测方法,在计算机视觉领域具有广泛的应用前景。

实现可参考 :【python】OpenCV—Edge, Corner, Face Detection(3)

import cv2
import numpy as np# 读取原始图像
cv_image = cv2.imread("1.jpg")
cv2.namedWindow("src", 0)
cv2.imshow("src", cv_image)
# 转换为灰度
gray_image = cv2.cvtColor(cv_image, cv2.COLOR_BGR2GRAY)
# 将图像像素数据转换为 float32,以避免进一步的尺寸不兼容冲突
gray_image = np.float32(gray_image)
# syntax cv2.corenrHarris(input_image, block size for neighborhood pixels to be considered, sobel operator size, border type)
result_image = cv2.cornerHarris(gray_image, blockSize=2, ksize=3, k=0.04)
cv2.imshow("result_image", result_image)
cv2.imwrite("result_image.jpg", result_image)
# 膨胀以突出角点
result_image = cv2.dilate(result_image, None)
cv2.imshow("dilate", result_image)
cv2.imwrite("dilate.jpg", result_image)
# 使用最佳阈值恢复到原始图像
cv_image[result_image > 0.01 * result_image.max()] = [0, 0, 255]
cv2.namedWindow("haris", 0)
cv2.imwrite("haris.jpg", cv_image)
cv2.imshow("haris", cv_image)
cv2.waitKey()

输入图片
在这里插入图片描述

result_image.jpg

在这里插入图片描述
dilate.jpg
在这里插入图片描述

在这里插入图片描述

3 Shi-Tomasi角点检测

一、算法概述

  • 算法来源:Shi-Tomasi算法于1994年在文章《Good Features to Track》中被提出。
  • 算法基础:基于Harris角点检测算法,通过改进角点响应函数的计算方式,提高了角点检测的准确性和效率。

二、算法原理

  • 角点定义:在图像中,角点是指那些在各个方向上灰度变化都很大的点。具体来说,当窗口在角点处沿任意方向移动时,窗口内的灰度变化都非常大。
  • 特征值分析:Shi-Tomasi算法通过计算图像中每个像素点的梯度,并构建自相关矩阵M。然后,对M进行特征值分解,得到两个特征值λ1和λ2。
  • 角点响应函数:Shi-Tomasi算法使用min(λ1, λ2)作为角点响应函数R。如果R大于设定的阈值,则认为该点为角点。这种改进使得算法能够更准确地识别出图像中的强角点。

三、demo

实现可参考 :【python】OpenCV—Edge, Corner, Face Detection(3)

import numpy as np
import cv2# 输入图像
cv_img = cv2.imread('1.jpg')
cv_gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
# syntax cv2.goodFeaturesToTrack(input_image, max_corner_to_detect, qualityLevel, minDistance)
corners = cv2.goodFeaturesToTrack(cv_gray, maxCorners=25, qualityLevel=0.01, minDistance=10)
corners = np.float32(corners)
for item in corners:x, y = item[0].astype("int")cv2.circle(cv_img, (x, y), 3, (0, 0, 255), -1)
cv2.imshow("image", cv_img)
cv2.imwrite("shi_result.jpg", cv_img)
cv2.waitKey()

输入图片

在这里插入图片描述
输出

在这里插入图片描述
可以看到零星的红色角点,效果一般

4 Fast 角点检测

FAST(Features from Accelerated Segment Test)角点检测算法是一种快速且高效的角点检测方法,广泛应用于计算机视觉和图像处理领域。

一、算法原理

  • FAST角点检测算法的基本思想是通过比较一个像素点与其周围像素点的灰度差异来判断该点是否为角点。具体来说,如果一个像素点与其周围足够多的像素点在灰度上存在显著差异(即这些点的灰度值要么都比中心像素点的灰度值大t,要么都比其小t,其中t为设定的阈值),则认为该像素点为角点。

二、算法步骤

  • 选择候选点:从图像中选取一个像素点p作为候选点。
  • 设置阈值:设定一个灰度阈值t,用于比较像素点之间的灰度差异。
  • 选择圆形区域:以候选点p为中心,选择一个半径为3像素的离散化圆(即Bresenham圆),该圆上通常有16个等间隔的像素点作为测试点。
  • 比较灰度值:比较候选点p的灰度值Ip与圆周上16个测试点的灰度值。如果在这16个点中,有连续N个点的灰度值要么都比Ip+t大,要么都比Ip-t小(N通常取12,但也可以取9或11等其他值),则认为候选点p是一个角点候选。
  • 加速检测:为了提高检测速度,FAST算法采用了一种预测试策略。首先比较圆周上第1、5、9、13这四个点的灰度值,如果这四个点中有三个或三个以上的点与中心点的灰度差异满足条件(即大于Ip+t或小于Ip-t),则继续进行后续的16点检测;否则,直接排除该候选点。
  • 非极大值抑制:对检测到的所有角点候选进行非极大值抑制处理,去除局部非极大值点,从而得到最终的角点集合。

三、算法优势

  • 速度快:FAST算法通过预测试策略和高效的灰度比较方法,显著提高了角点检测的速度。
  • 精度高:尽管FAST算法速度快,但其检测精度也相当高,能够满足大多数应用场景的需求。
  • 易于实现:FAST算法的原理相对简单,实现起来较为容易,适用于多种编程语言和开发环境。

四、demo

import cv2# 输入图像
cv_img = cv2.imread('../1.jpg')
cv_gray = cv2.cvtColor(cv_img, cv2.COLOR_BGR2GRAY)
fast = cv2.FastFeatureDetector_create()
fast.setNonmaxSuppression(False)
keypoint = fast.detect(cv_gray, None)
keypoint_image = cv2.drawKeypoints(cv_img, keypoint, None, color=(0, 0, 255))
cv2.imshow("FAST", keypoint_image)
cv2.imwrite("fast.jpg", keypoint_image)
cv2.waitKey()

输出图像,不开启 NMS

在这里插入图片描述

下面对比下开启 NMS 和不开启 NMS 的结果对比

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
#  FAST
import cv2
import matplotlib.pyplot as plt
import numpy as np# 加载图像
image = cv2.imread('../1.jpg')# 将图像转换为 RGB
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)# 将图像转换为灰度
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)# 显示图像和灰度图像
fx, plots = plt.subplots(1, 2, figsize=(20,10))plots[0].set_title("Orignal Image")
plots[0].imshow(image)
plots[0].axis("off")plots[1].set_title("Gray Image")
plots[1].imshow(gray, cmap="gray")
plots[1].axis("off")
plt.savefig("gray.jpg")
plt.show()fast = cv2.FastFeatureDetector_create()# 用非最大抑制检测关键点
keypoints_with_nonmax = fast.detect(gray, None)# 禁用非最大抑制
fast.setNonmaxSuppression(False)# 在没有非最大抑制的情况下检测关键点
keypoints_without_nonmax = fast.detect(gray, None)image_with_nonmax = np.copy(image)
image_without_nonmax = np.copy(image)# 在输入图像上绘制关键点
cv2.drawKeypoints(image, keypoints_with_nonmax, image_with_nonmax, color=(255,0,0),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.drawKeypoints(image, keypoints_without_nonmax, image_without_nonmax, color=(255,0,0),flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 显示有和没有非最大抑制的图像
fx, plots = plt.subplots(1, 2, figsize=(20,10))plots[0].set_title("With non max suppression")
plots[0].imshow(image_with_nonmax)
plots[0].axis("off")
plt.imsave("nms.jpg", image_with_nonmax)plots[1].set_title("Without non max suppression")
plots[1].imshow(image_without_nonmax)
plots[1].axis("off")
plt.imsave("nonms.jpg", image_without_nonmax)# 打印使用NMS在图像中检测到的关键点数
print("Number of Keypoints Detected In The Image With Non Max Suppression: ", len(keypoints_with_nonmax))# 打印不使用NMS在图像中检测到的关键点数
print("Number of Keypoints Detected In The Image Without Non Max Suppression: ", len(keypoints_without_nonmax))
plt.show()
# Number of Keypoints Detected In The Image With Non Max Suppression:  17295
# Number of Keypoints Detected In The Image Without Non Max Suppression:  89925

输出 gray.jpg

在这里插入图片描述
输出 nonms.jpg
在这里插入图片描述
输出 nms.jpg

在这里插入图片描述

5 BRIEF 特征描述子

在图像领域,特征描述子(Feature Descriptors)是用于描述图像中特定属性或纹理信息的数学表示,它们在图像匹配、对象识别和图像检索等任务中发挥着关键作用。eg:SHIFT(尺度不变特征变换)、SURF(加速稳健特征)、ORB(加速稳健特征)、HOG(方向梯度直方图)、LBP(局部二值模式)

BRIEF(Binary Robust Independent Elementary Features)是一种高效的特征描述子算法,它主要用于对图像中的关键点(如角点)进行描述,以便进行特征匹配、图像识别等任务。BRIEF算法的核心在于通过比较关键点周围随机选取的点对的像素强度差异,来生成一个紧凑的二进制字符串作为该关键点的描述子。

特点

  • 二进制字符串:BRIEF描述子是一个二进制字符串,这意味着它非常紧凑,易于存储和传输,同时也便于快速比较。
  • 随机采样:在关键点周围的邻域内,BRIEF通过随机选取的点对来生成描述子。这种随机性使得算法对噪声和小的形变具有一定的鲁棒性。
  • 快速计算:由于描述子是二进制的,因此其计算和匹配过程都非常快速,特别适合实时应用。
  • 非旋转不变性:原始的BRIEF算法并不具有旋转不变性,即如果图像发生旋转,则同一关键点的BRIEF描述子也会发生变化。然而,通过结合具有旋转不变性的关键点检测算法(如ORB中的oFAST)或在描述子生成前对关键点邻域进行旋转校正,可以使得BRIEF描述子具有旋转不变性
  • 尺度不变性:BRIEF算法本身并不直接处理尺度不变性。然而,在实际应用中,通常会与具有尺度不变性的关键点检测算法结合使用,或者通过构建图像金字塔并在多个尺度上检测关键点来间接实现尺度不变性。

Demo

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File    : BRIEF.py
@Time    : 2021/10/13 11:07
@Author  : David
@Software: PyCharm
"""
# BRIEF(Binary Robust Independent Elementary Features)# 导入库,显示图像import cv2
import matplotlib.pyplot as plt
import numpy as np# 加载图像
image1 = cv2.imread('./2.png')# 将训练图像转换为RGB
training_image = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)# 将训练图像转换为灰度
training_gray = cv2.cvtColor(training_image, cv2.COLOR_RGB2GRAY)# 通过添加缩放不变性和旋转不变性来创建测试图像
test_image = cv2.pyrDown(training_image)
test_image = cv2.pyrDown(test_image)
num_rows, num_cols = test_image.shape[:2]rotation_matrix = cv2.getRotationMatrix2D((num_cols / 2, num_rows / 2), 30, 1)
test_image = cv2.warpAffine(test_image, rotation_matrix, (num_cols, num_rows))test_gray = cv2.cvtColor(test_image, cv2.COLOR_RGB2GRAY)# 显示训练图像和测试图像
fx, plots = plt.subplots(1, 2, figsize=(20, 10))plots[0].set_title("Training Image")
plots[0].imshow(training_image)
plots[0].axis("off")plots[1].set_title("Testing Image")
plots[1].imshow(test_image)
plots[1].axis("off")
plt.savefig("tran-test.jpg")# 检测关键点并创建描述符fast = cv2.FastFeatureDetector_create()
brief = cv2.xfeatures2d.BriefDescriptorExtractor_create()train_keypoints = fast.detect(training_gray, None)
test_keypoints = fast.detect(test_gray, None)train_keypoints, train_descriptor = brief.compute(training_gray, train_keypoints)
test_keypoints, test_descriptor = brief.compute(test_gray, test_keypoints)keypoints_without_size = np.copy(training_image)
keypoints_with_size = np.copy(training_image)cv2.drawKeypoints(training_image, train_keypoints, keypoints_without_size,color=(0, 255, 0))cv2.drawKeypoints(training_image, train_keypoints, keypoints_with_size,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 显示图像有和没有关键点大小
fx, plots = plt.subplots(1, 2, figsize=(20, 10))plots[0].set_title("Train keypoints With Size")
plots[0].imshow(keypoints_with_size, cmap='gray')
plots[0].axis("off")plots[1].set_title("Train keypoints Without Size")
plots[1].imshow(keypoints_without_size, cmap='gray')
plots[1].axis("off")
plt.savefig("keypoints.jpg")# 打印训练图像中检测到的关键点数量
print("Number of Keypoints Detected In The Training Image: ", len(train_keypoints))# 打印查询图像中检测到的关键点数量
print("Number of Keypoints Detected In The Query Image: ", len(test_keypoints))# 匹配关键点# 创建一个Brute Force Matcher对象。
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)# 对训练图像和测试图像的BRIEF描述符进行匹配
matches = bf.match(train_descriptor, test_descriptor)# 距离较短的是我们想要的。
matches = sorted(matches, key=lambda x: x.distance)result = cv2.drawMatches(training_image, train_keypoints, test_gray, test_keypoints, matches, test_gray, flags=2)# 显示最佳匹配点
plt.rcParams['figure.figsize'] = [14.0, 7.0]
plt.title('Best Matching Points')
plt.imsave("matching.jpg", result)
plt.imshow(result)
plt.show()# 打印训练图像和查询图像之间的匹配点总数
print("\nNumber of Matching Keypoints Between The Training and Query Images: ", len(matches))
# Number of Keypoints Detected In The Training Image:  7975
# Number of Keypoints Detected In The Query Image:  525
# Number of Matching Keypoints Between The Training and Query Images:  194

tran-test.jpg

注意,测试图片进行了两次下采样,大小为原图的 1/4,这里可视化成一样的大小了
在这里插入图片描述

keypoints.jpg

在这里插入图片描述

matching.jpg——BRIEF+Brute Force Matcher

在这里插入图片描述


看看另外一张图片的匹配结果

在这里插入图片描述

6 ORB(Oriented Fast and Rotated Brief) 特征描述子

import cv2
import matplotlib.pyplot as plt
import numpy as np# 加载图像
image1 = cv2.imread('../2.png')# 将训练图像转换为RGB
training_image = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)# 将训练图像转换为灰度
training_gray = cv2.cvtColor(training_image, cv2.COLOR_RGB2GRAY)# 通过添加缩放不变性和旋转不变性来创建测试图像
test_image = training_image
num_rows, num_cols = test_image.shape[:2]rotation_matrix = cv2.getRotationMatrix2D((num_cols/2, num_rows/2), 30, 1)
test_image = cv2.warpAffine(test_image, rotation_matrix, (num_cols, num_rows))test_gray = cv2.cvtColor(test_image, cv2.COLOR_RGB2GRAY)# 显示训练图像和测试图像
fx, plots = plt.subplots(1, 2, figsize=(20,10))plots[0].set_title("Training Image")
plots[0].imshow(training_image)
plots[0].axis("off")
plt.imsave("training_image.jpg", training_image)plots[1].set_title("Testing Image")
plots[1].imshow(test_image)
plots[1].axis("off")
plt.imsave("test_image.jpg", test_image)orb = cv2.ORB_create()train_keypoints, train_descriptor = orb.detectAndCompute(training_gray, None)
test_keypoints, test_descriptor = orb.detectAndCompute(test_gray, None)keypoints_without_size = np.copy(training_image)
keypoints_with_size = np.copy(training_image)cv2.drawKeypoints(training_image, train_keypoints, keypoints_without_size, color = (0, 255, 0))cv2.drawKeypoints(training_image, train_keypoints, keypoints_with_size, flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 显示图像有和没有关键点大小
fx, plots = plt.subplots(1, 2, figsize=(20,10))plots[0].set_title("Train keypoints With Size")
plots[0].imshow(keypoints_with_size, cmap='gray')
plots[0].axis("off")
plt.imsave("keypoints_with_size.jpg", keypoints_with_size)plots[1].set_title("Train keypoints Without Size")
plots[1].imshow(keypoints_without_size, cmap='gray')
plots[1].axis("off")
plt.imsave("keypoints_without_size.jpg", keypoints_without_size)# 打印训练图像中检测到的关键点个数
print("Number of Keypoints Detected In The Training Image: ", len(train_keypoints))# 打印查询图像中检测到的关键点数量
print("Number of Keypoints Detected In The Query Image: ", len(test_keypoints))# 创建一个Brute Force Matcher对象。
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck = True)# 执行训练图像和测试图像的ORB描述符之间的匹配
matches = bf.match(train_descriptor, test_descriptor)# 距离较短的是我们想要的。
matches = sorted(matches, key = lambda x : x.distance)result = cv2.drawMatches(training_image, train_keypoints, test_gray, test_keypoints, matches, test_gray, flags = 2)# 显示最佳匹配点
plt.rcParams['figure.figsize'] = [14.0, 7.0]
plt.title('Best Matching Points')
plt.imsave("result.jpg", result)
plt.imshow(result)
plt.show()# 打印训练图像和查询图像之间的匹配点总数
print("\nNumber of Matching Keypoints Between The Training and Query Images: ", len(matches))
# Number of Keypoints Detected In The Training Image:  500
# Number of Keypoints Detected In The Query Image:  500
#
# Number of Matching Keypoints Between The Training and Query Images:  325

输入图片

在这里插入图片描述

输出

test_image.jpg,这次实验测试图片和原图的大小保持了一致

在这里插入图片描述

keypoints_with_size.jpg

在这里插入图片描述

keypoints_without_size.jpg

在这里插入图片描述
result.jpg——ORB+Brute Force Matcher

在这里插入图片描述

7 SIFT(Scale Invariant Feature Transform) 特征描述子

测试图片 4 倍下采样了

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File    : sift.py
@Time    : 2021/10/13 13:01
@Author  : David
@Software: PyCharm
"""
# SIFT (Scale-Invariant Feature Transform)# 导入库函数与显示图像import cv2
import matplotlib.pyplot as plt
import numpy as np# 导入图像
image1 = cv2.imread('../2.png')# 将训练图像转换为RGB
training_image = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)# 将训练图像转换为灰度
training_gray = cv2.cvtColor(training_image, cv2.COLOR_RGB2GRAY)# 通过添加缩放不变性和旋转不变性来创建测试图像
test_image = cv2.pyrDown(training_image)
test_image = cv2.pyrDown(test_image)
num_rows, num_cols = test_image.shape[:2]rotation_matrix = cv2.getRotationMatrix2D((num_cols / 2, num_rows / 2), 30, 1)
test_image = cv2.warpAffine(test_image, rotation_matrix, (num_cols, num_rows))test_gray = cv2.cvtColor(test_image, cv2.COLOR_RGB2GRAY)# 显示训练图像和测试图像
fx, plots = plt.subplots(1, 2, figsize=(20, 10))plots[0].set_title("Training Image")
plots[0].imshow(training_image)
plots[0].axis("off")
plt.imsave("training_image.jpg", training_image)plots[1].set_title("Testing Image")
plots[1].imshow(test_image)
plots[1].axis("off")
plt.imsave("test_image.jpg", test_image)
# 检测关键点并创建描述符sift = cv2.xfeatures2d.SIFT_create()
train_keypoints, train_descriptor = sift.detectAndCompute(training_gray, None)
test_keypoints, test_descriptor = sift.detectAndCompute(test_gray, None)keypoints_without_size = np.copy(training_image)
keypoints_with_size = np.copy(training_image)cv2.drawKeypoints(training_image, train_keypoints, keypoints_without_size, color=(0, 255, 0))cv2.drawKeypoints(training_image, train_keypoints, keypoints_with_size,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 显示图像有和没有关键点大小
fx, plots = plt.subplots(1, 2, figsize=(20, 10))plots[0].set_title("Train keypoints With Size")
plots[0].imshow(keypoints_with_size, cmap='gray')
plots[0].axis("off")
plt.imsave("keypoints_with_size.jpg", keypoints_with_size)plots[1].set_title("Train keypoints Without Size")
plots[1].imshow(keypoints_without_size, cmap='gray')
plots[1].axis("off")
plt.imsave("keypoints_without_size.jpg", keypoints_without_size)# 打印训练图像中检测到的关键点个数
print("Number of Keypoints Detected In The Training Image: ", len(train_keypoints))# 打印查询图像中检测到的关键点数量
print("Number of Keypoints Detected In The Query Image: ", len(test_keypoints))# 关键点匹配# 创建一个Brute Force Matcher对象。
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=False)# 对训练图像和测试图像的SIFT描述子进行匹配
matches = bf.match(train_descriptor, test_descriptor)# 距离较短的是我们想要的。
matches = sorted(matches, key=lambda x: x.distance)result = cv2.drawMatches(training_image, train_keypoints, test_gray, test_keypoints, matches, test_gray, flags=2)# 显示最佳匹配点
plt.rcParams['figure.figsize'] = [14.0, 7.0]
plt.title('Best Matching Points')
plt.imsave("result.jpg", result)
plt.imshow(result)
plt.show()# 打印训练图像和查询图像之间的匹配点总数
print("\nNumber of Matching Keypoints Between The Training and Query Images: ", len(matches))
# Number of Keypoints Detected In The Training Image:  1080
# Number of Keypoints Detected In The Query Image:  245
#
# Number of Matching Keypoints Between The Training and Query Images:  1080

输出

keypoints_with_size.jpg

在这里插入图片描述

keypoints_without_size.jpg

在这里插入图片描述

result.jpg——SIFT+Brute Force Matcher

在这里插入图片描述

8 SURF(Speeded Up Robust Features) 特征描述子

较新的 opencv 版本不支持 SURF,这里仅展示 Code

#!/usr/bin/python3
# -*- encoding: utf-8 -*-
"""
@File    : surf.py
# SURF (Speeded-Up Robust Features)
# 新版OpenCV不能使用Surf了,我使用了opencv-contrib-python==3.4.11.45
"""
# 导入库和显示图像
import cv2
import matplotlib.pyplot as plt
import numpy as np# 加载图像
image1 = cv2.imread('./1.jpg')# 将训练图像转换为RGB
training_image = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)# 将训练图像转换为灰度
training_gray = cv2.cvtColor(training_image, cv2.COLOR_RGB2GRAY)# 通过添加缩放不变性和旋转不变性来创建测试图像
test_image = cv2.pyrDown(training_image)
test_image = cv2.pyrDown(test_image)
num_rows, num_cols = test_image.shape[:2]rotation_matrix = cv2.getRotationMatrix2D((num_cols / 2, num_rows / 2), 30, 1)
test_image = cv2.warpAffine(test_image, rotation_matrix, (num_cols, num_rows))test_gray = cv2.cvtColor(test_image, cv2.COLOR_RGB2GRAY)# 显示训练图像和测试图像
fx, plots = plt.subplots(1, 2, figsize=(20, 10))plots[0].set_title("Training Image")
plots[0].imshow(training_image)
plots[0].axis("off")
plt.imsave("training_image.jpg", training_image)plots[1].set_title("Testing Image")
plots[1].imshow(test_image)
plots[1].axis("off")
plt.imsave("test_image.jpg", test_image)# 检测关键点并创建描述符surf = cv2.xfeatures2d.SURF_create(800)train_keypoints, train_descriptor = surf.detectAndCompute(training_gray, None)
test_keypoints, test_descriptor = surf.detectAndCompute(test_gray, None)keypoints_without_size = np.copy(training_image)
keypoints_with_size = np.copy(training_image)cv2.drawKeypoints(training_image, train_keypoints, keypoints_without_size, color=(0, 255, 0))cv2.drawKeypoints(training_image, train_keypoints, keypoints_with_size,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)# 显示图像有和没有关键点大小
fx, plots = plt.subplots(1, 2, figsize=(20, 10))plots[0].set_title("Train keypoints With Size")
plots[0].imshow(keypoints_with_size, cmap='gray')
plots[0].axis("off")
plt.imsave("keypoints_with_size.jpg", keypoints_with_size)plots[1].set_title("Train keypoints Without Size")
plots[1].imshow(keypoints_without_size, cmap='gray')
plots[1].axis("off")
plt.imsave("keypoints_without_size.jpg", keypoints_without_size)# 打印训练图像中检测到的关键点个数
print("Number of Keypoints Detected In The Training Image: ", len(train_keypoints))# 打印查询图像中检测到的关键点数量
print("Number of Keypoints Detected In The Query Image: ", len(test_keypoints))# 关键点匹配# 创建一个Brute Force Matcher对象。
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)# 对训练图像和测试图像的SURF描述符进行匹配
matches = bf.match(train_descriptor, test_descriptor)# 距离较短的是我们想要的。
matches = sorted(matches, key=lambda x: x.distance)result = cv2.drawMatches(training_image, train_keypoints, test_gray, test_keypoints, matches, test_gray, flags=2)# 显示最佳匹配点
plt.rcParams['figure.figsize'] = [14.0, 7.0]
plt.title('Best Matching Points')
plt.imsave("result.jpg", result)
plt.imshow(result)
plt.show()# 打印训练图像和查询图像之间的匹配点总数
print("\nNumber of Matching Keypoints Between The Training and Query Images: ", len(matches))
# Number of Keypoints Detected In The Training Image:  242
# Number of Keypoints Detected In The Query Image:  29
# 
# Number of Matching Keypoints Between The Training and Query Images:  21

9 Brute-Force Matcher 特征匹配

import cv2cv_img1 = cv2.imread('1.jpg', 1)
cv_img2 = cv2.imread('2.jpg', 1)
orb = cv2.ORB_create(nfeatures=500)
kp1, des1 = orb.detectAndCompute(cv_img1, None)
kp2, des2 = orb.detectAndCompute(cv_img2, None)
# matcher接受normType,它被设置为cv2.NORM_L2用于SIFT和SURF, cv2.NORM_HAMMING用于ORB, FAST and BRIEF
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)
matches = sorted(matches, key=lambda x: x.distance)  # 前50匹配点
match_img = cv2.drawMatches(cv_img1, kp1, cv_img2, kp2, matches[:50], None)
cv2.imshow('Matches', match_img)
cv2.imwrite("Match.jpg", match_img)
cv2.waitKey()

输入 1.jpg

在这里插入图片描述
输入 2.jpg

在这里插入图片描述

输出

在这里插入图片描述

10 FLANN Matcher 特征匹配

使用 ORB 检测器和校正失真图像来实现匹配操作。

import cv2
import numpy as npdef get_corrected_img(cv_img1, cv_img2):MIN_MATCHES = 10orb = cv2.ORB_create(nfeatures=500)kp1, des1 = orb.detectAndCompute(cv_img1, None)kp2, des2 = orb.detectAndCompute(cv_img2, None)index_params = dict(algorithm=6,table_number=6,key_size=12,multi_probe_level=2)search_params = {}flann = cv2.FlannBasedMatcher(index_params, search_params)matches = flann.knnMatch(des1, des2, k=2)# 根据 Lowe 的比率测试来过滤良好的匹配good_matches = []for m, n in matches:if m.distance < 0.8 * n.distance:good_matches.append(m)if len(good_matches) > MIN_MATCHES:src_points = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)dst_points = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)print(src_points.shape)good_matches = sorted(good_matches, key=lambda x: x.distance)  # 前50匹配点match_img = cv2.drawMatches(cv_img1, kp1, cv_img2, kp2, good_matches[:50], None)cv2.imshow('flannMatches', match_img)cv2.imwrite("flannMatch.jpg", match_img)cv2.waitKey()m, mask = cv2.findHomography(src_points, dst_points, cv2.RANSAC, 5.0)corrected_img = cv2.warpPerspective(cv_img1, m, (cv_img2.shape[1], cv_img2.shape[0]))return corrected_imgreturn Noneif __name__ == "__main__":cv_im1 = cv2.imread('1.jpg')cv_im2 = cv2.imread('2.jpg')img = get_corrected_img(cv_im2, cv_im1)if img is not None:cv2.imshow('Corrected image', img)cv2.imwrite("corrected_image.jpg", img)cv2.waitKey()

输入图片

corrected_image.jpg

在这里插入图片描述

flannMatch.jpg

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/39682.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Milvus ConnectionRefusedError: how to connect locally

题意&#xff1a;怎样在本地连接到 Milvus 数据库。连接 Milvus 数据库被拒绝的错误 问题背景&#xff1a; I am trying to run a RAG pipeline using haystack & Milvus. 我正在尝试使用 haystack 和 Milvus 运行一个 RAG&#xff08;检索增强型生成&#xff09;管道。 …

vue+element-ui简洁完美实现个人博客“​响石潭 ​”

目录 一、项目介绍 二、项目截图 1.项目结构图 2.首页 3.生活 ​编辑 4.文章详情 ​编辑 5.关于我 ​编辑 ​编辑 三、源码实现 1.项目依赖package.json 2.项目启动 3.首页源码 四、总结 一、项目介绍 本项目在线预览&#xff1a;点击访问 参考官网&#xff1…

腾讯 TRANSAGENTS: 多智能体翻译框架上线

之前介绍的由腾讯 AI 实验室搞得TRANSAGENTS&#xff08;多 Agent 系统&#xff0c;模拟现实翻译出版流程&#xff09;终于上线演示了&#xff01;提供了基于 GPT-4o 的免费试用, 暂时还是期货开源。

R语言fastshap包进行支持向量机shap可视化分析

1995年VAPINK 等人在统计学习理论的基础上提出了一种模式识别的新方法—支持向量机 。它根据有限的样本信息在模型的复杂性和学习能力之间寻求一种最佳折衷。 以期获得最好的泛化能力.支持向量机的理论基础决定了它最终求得的是全局最优值而不是局部极小值,从而也保证了它对未知…

[数据集][目标检测]围栏破损检测数据集VOC+YOLO格式1196张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1196 标注数量(xml文件个数)&#xff1a;1196 标注数量(txt文件个数)&#xff1a;1196 标注…

40V转5V,40V转3.3V,40V转3V使用什么降压芯片型号?

40V转5V,40V转3.3V,40V转3V使用什么降压芯片型号? # 40V转5V、3.3V、3V降压芯片&#xff1a;AH8820A的介绍与应用 在电子电路设计中&#xff0c;电压转换是一个常见的需求。特别是在需要将较高电压转换为较低电压以供微控制器、传感器和其他低电压设备使用时&#xff0c;降压…

力扣1685.有序数组中差绝对值之和

力扣1685.有序数组中差绝对值之和 记录左边之和 和 右边之和从左到右遍历每个元素 求res class Solution {public:vector<int> getSumAbsoluteDifferences(vector<int>& nums) {int n nums.size(),lsum 0,rsum accumulate(nums.begin(),nums.end(),0);ve…

匿名方法与Lambda表达式

知识集锦 一、lambda表达式介绍 无参数 () >{return "1";}; 等同于 string getnum(){ return "1"; } 有两个参数 (p1, p2) >{ return p1*p2;}; 等同于 int mul(p1, p2) { return p1*p2;}; lambda表达式可以捕获外部变量&#xff0c;并在其主体中使用…

怎么在电脑上录屏?跟着教程一步步操作

随着数字化时代的到来&#xff0c;电脑录屏已经成为一项必备技能。无论是录制游戏画面、制作教程视频&#xff0c;还是保存线上会议记录&#xff0c;录屏都能帮上大忙。可是怎么在电脑上录屏呢&#xff1f;本文将介绍两种在电脑上进行录屏的方法&#xff0c;这两种方法各有特点…

陶建辉当选 GDOS 全球数据库及开源峰会荣誉顾问

近日&#xff0c;第二十三届 GOPS 全球运维大会暨 XOps 技术创新峰会在北京正式召开。本次会议重点议题方向包括开源数据库落地思考、金融数据库自主可控、云原生时代下数据库、数据库智能运维、数据库安全与隐私、开源数据库与治理。大会深入探讨这些方向&#xff0c;促进了数…

宇宙第一大厂亚马逊云科技AWS人工智能/机器学习证书即将上线,一篇文章教你轻松拿下

据麦肯锡《在华企业如何填补AI人才缺口》研究表明&#xff0c;到2030年人工智能为中国带来的潜在价值有望超过1万亿美元&#xff0c;而随着各大企业进入人工智能化&#xff0c;对该领域的人才需求将从目前的100万增长到2030年的600万。然而到保守估计&#xff0c;到2030可以满足…

DevOps:开发与运维的无缝融合

目录 前言1. DevOps的起源与概念1.1 DevOps的起源1.2 DevOps的定义 2. DevOps的核心实践2.1 持续集成2.2 持续交付2.3 自动化 3. DevOps工具链3.1 版本控制系统3.2 持续集成工具3.3 配置管理工具3.4 容器化与编排工具3.5 监控和日志工具 4. DevOps的实际应用4.1 案例分析&#…

C语言实战 | 用户管理系统

近期推出的青少年防沉迷系统&#xff0c;采用统一运行模式和功能标准。在“青少年模式”下&#xff0c;未成年人的上网时段、时长、功能和浏览内容等方面都有明确的规范。防沉迷系统为青少年打开可控的网络空间。 01、综合案例 防沉迷系统的基础是需要一个用户管理系统管理用户…

C# 计算椭圆上任意一点坐标

已知圆心坐标 &#xff08;x0&#xff0c;y0&#xff09;&#xff0c;横轴 A&#xff08;长半轴&#xff09;&#xff0c;竖轴 B&#xff08;短半轴&#xff09;&#xff0c;角度 a&#xff0c;则圆边上点&#xff08;x&#xff0c;y&#xff09;的坐标为&#xff1a; 方法一 …

docker push 推送镜像到阿里云仓库

1.登陆阿里云 镜像服务&#xff0c;跟着指引操作就行 创建个人实例&#xff0c;创建命名空间、镜像仓库&#xff0c;绑定代码源头 2.将镜像推送到Registry $ docker login --username*** registry.cn-beijing.aliyuncs.com $ docker tag [ImageId] registry.cn-beijing.aliy…

Vue入门-如何创建一个Vue实例

创建一个一个Vue实例总共分为四步&#xff1a; 1.创建一个容器 2.引包&#xff1a;地址栏搜索v2.cn.vuejs.org这是vue2的官网地址&#xff0c;把2去掉就是vue3的官网地址&#xff0c;我们的包分为开发版本和生产版本&#xff0c;开发版本包含完整的警告和调试模式生产版本删除…

太阳辐射系统日光全光谱模拟太阳光模拟器

太阳光模拟器是一种用于评估太阳能电池性能的重要设备。它能够模拟太阳光的特性&#xff0c;通过测试电池的短路电流、开路电压、填充因子和光电转化效率等关键指标&#xff0c;来评估电池的性能优劣。 设备型号&#xff1a;KYF-GC004品牌制造商&#xff1a;科迎法电气太阳光模…

UE5基本操作(二)

文章目录 前言相机的移动速度修改默认地图使用初学者内容包文件夹结构 总结 前言 在我们的上一篇文章中&#xff0c;我们已经介绍了一些Unreal Engine 5&#xff08;UE5&#xff09;的基本操作。UE5是一款强大的游戏开发引擎&#xff0c;它提供了许多工具和功能&#xff0c;使…

蓝牙压力测试和稳定性测试工具(nRF Connect)

蓝牙压力测试和稳定性测试工具&#xff08;nRF Connect&#xff09; 文章目录 1、如何使用nRF Connect事件记录功能2、如何使用nRF Connect录制操作2.1、点击右下角的开始录制2.2、输入想要测试的指令2.3、模拟持续数据访问2.4、开始压力测试 1、如何使用nRF Connect事件记录功…

【python】OpenCV—QR Code

文章目录 1 QR Code2 准备工作3 生成 QR 码4 读取 QR 码5 与 Zbar 比较 1 QR Code QR Code&#xff08;Quick Response Code&#xff09;是一种二维条码&#xff0c;由日本Denso-Wave公司于1994年发明。QR Code的主要特点是存储信息量大、编码范围广、容错能力强、识读速度快&…