【python】OpenCV—Feature Detection and Matching

news2024/11/23 6:56:13

在这里插入图片描述

参考学习来自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 cv2

cv_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 np


def get_corrected_img(cv_img1, cv_img2):
    MIN_MATCHES = 10
    orb = 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_img
    return None


if __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.coloradmin.cn/o/1888402.html

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

相关文章

​​​​​​​​​​​​​​Spark Standalone集群环境

目录 Spark Standalone集群环境 修改配置文件 【workers】 【spark-env.sh】 【配置spark应用日志】 【log4j.properties】 分发到其他机器 启动spark Standalone 启动方式1&#xff1a;集群启动和停止 启动方式2&#xff1a;单独启动和停止 连接集群 【spark-shel…

基于Hadoop平台的电信客服数据的处理与分析③项目开发:搭建基于Hadoop的全分布式集群---任务1:运行环境说明

任务描述 项目的运行环境是基于Hadoop的全分布式模式集群。 任务的主要内容是规划集群节点及网络使用&#xff0c;准备初始环境&#xff0c;关闭防火墙和Selinux。 任务指导 1. 基于Hadoop的全分布式模式集群&#xff0c;如下图所示&#xff1b; 2. 硬软件环境&#xff1a;…

Android性能优化面试题经典之ANR的分析和优化

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 造成ANR的条件 以下四个条件都可以造成ANR发生&#xff1a; InputDispatching Timeout&#xff1a;5秒内无法响应屏幕触摸事件或键盘输入事件 …

《企业实战分享 · MyBatis 使用合集》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; 近期刚转战 CSDN&#xff0c;会严格把控文章质量&#xff0c;绝不滥竽充数&#xff0c;如需交流&#xff…

Seatunnel本地模式快速测验

前言 SeaTunnel&#xff08;先前称为WaterDrop&#xff09;是一个分布式、高性能、易于扩展的数据集成平台&#xff0c;旨在实现海量数据的同步和转换。它支持多种数据处理引擎&#xff0c;包括Apache Spark和Apache Flink&#xff0c;并在某个版本中引入了自主研发的Zeta引擎…

虚拟机交叉编译基于ARM平台的opencv(ffmpeg/x264)

背景&#xff1a; 由于手上有一块rk3568的开发板&#xff0c;需要运行yolov5跑深度学习模型&#xff0c;但是原有的opencv不能对x264格式的视频进行解码&#xff0c;这里就需要将ffmpegx264编译进opencv。 但是开发板算力有限&#xff0c;所以这里采用在windows下&#xff0c;安…

2024年07年01日 Redis数据类型以及使用场景

String Hash List Set Sorted Set String&#xff0c;用的最多&#xff0c;对象序列化成json然后存储 1.对象缓存&#xff0c;单值缓存 2.分布式锁 Hash&#xff0c;不怎么用到 1.可缓存经常需要修改值的对象&#xff0c;可单独对对象某个属性进行修改 HMSET user {userI…

Element中的选择器组件Select (一级选择组件el-select)

简述&#xff1a;在 Element UI 中&#xff0c;ElSelect&#xff08;或简称为 Select&#xff09;是一个非常常用的选择器组件&#xff0c;它提供了丰富的功能来帮助用户从一组预定义的选项中选择一个或多个值。这里来简单记录一下 一. 组件和属性配置 <el-selectv-model&q…

经典FC游戏web模拟器--EmulatorJS

简介 EmulatorJS是一个基于JavaScript和Webassembly技术的虚拟环境的实现&#xff0c;可以在网页中运行各种经典FC游戏系统&#xff0c;支持任天堂、世嘉、雅达利等经典红白机。EmulatorJS的诞生使得诸如超级玛丽、坦克大战、魂斗罗等经典FC游戏能够以一种全新的方式回归。本文…

MySQL:高效的索引

数据库索引 1. 索引介绍1.1 创建索引1.2 查看索引 2. 索引应用2.1 前缀索引2.2 全文索引2.3 复合索引2.4 复合索引中的列顺序2.5 建立最佳索引2.6 使用索引排序2.7 覆盖索引 3. 维护索引4. 建立性能数据库 索引对大型和高并发数据库非常有用&#xff0c;因为它可以显著提升查询…

KVM虚拟机动态添加网卡

一、在宿主机上临时在线添加虚拟网卡&#xff0c;关机再开机失效 1、查看运行的虚拟机 [rootlocalhost img]# virsh list 2、添加NAT网卡&#xff0c;会自动获取192.168.122.X网段的IP virsh attach-interface hadoop01 --type network --source default 3、查看虚机mac …

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

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

360的chromesafe64.dll动态链接库导致chrome和edge浏览器闪退崩溃关闭

在chrome或edge浏览器中打开特定的一些网页会导致浏览器闪退关闭 这是windows系统记录的报错日志 chrome报错日志 edge报错日志 日志指向的就是chromesafe64.dll这个动态库 然后用everything搜索发现原来在360安装目录下 360安装目录下的chromesafe64.dll文件 为什么360中的…

使用TensorFlow进行OCR识别:将表格图片转换为结构化数据

随着人工智能和机器学习技术的不断发展&#xff0c;OCR&#xff08;Optical Character Recognition&#xff0c;光学字符识别&#xff09;技术已经成为处理图像中文本信息的强大工具。TensorFlow是一个广泛使用的开源机器学习框架&#xff0c;它提供了丰富的API和工具&#xff…

独立开发者系列(17)——MYSQL的常见异常整理

虽然安装MYSQL到本地很简单&#xff0c;但是数据库报错还是经常出现&#xff0c;这个时候&#xff0c;需要我们进行逐步检查与修复。作为我们最常用的开发软件&#xff0c;无论切换php/go/python/node/java&#xff0c;数据库的身影都少不了&#xff0c;对于我们储存数据而言&a…

Android 如何通过一个设备开发多种分辨率屏幕UI

获取当前屏幕密度&#xff1a; adb shell wm density 获取当前分辨率&#xff1a; adb shell wm size 重置设备密度和分辨率 adb shell wm size reset adb shell wm density reset 屏幕1 adb shell wm size 3082x934 adb shell wm density 160 屏幕2 adb shell wm siz…

【数据结构与算法】利用堆结构高效解决TopK问题

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法》 期待您的关注 ​ 目录 一、引言 二、堆的基本概念 三、使用堆解决TopK问题 四、算法实现&#xff08;C语言…

HTTPS基础

目录 1. HTTPS概述2. HTTPS工作原理3. HTTPS证书4. HTTPS安全性特性5. 配置HTTPS示例5.1 获取和配置SSL/TLS证书5.2 示例&#xff1a;在Nginx上配置HTTPS5.3 实施HSTS 6. 结论 1. HTTPS概述 术语描述HTTPS超文本传输安全协议&#xff0c;HTTP的安全版本。SSL/TLS安全套接字层/…

UG NX二次开发(C++)-根据草图创建拉伸特征(UFun+NXOpen)

1、前言 UG NX是基于特征的三维建模软件,其中拉伸特征是一个很重要的特征,有读者问如何根据草图创建拉伸特征,我在这篇博客中讲述一下草图创建拉伸特征的UG NX二次开发方法,感兴趣的可以加入QQ群:749492565,或者在评论区留言。 2、在UG NX中创建草图,然后创建拉伸特征 …

uniapp + vue3 + Script Setup 写法变动 (持续更新)

一、uniapp 应用生命周期&#xff1a; https://uniapp.dcloud.net.cn/tutorial/vue3-composition-api.html 注意&#xff1a; 应用生命周期仅可在App.vue中监听&#xff0c;在其它页面监听无效。 二 、uniapp页面生命周期&#xff1a; https://uniapp.dcloud.net.cn/tutori…