图像特征匹配-SIFT函数应用【opencv】

相关函数

OpenCV中SIFT(Scale-Invariant Feature Transform)算法的一个重要函数。SIFT算法是一种用于图像特征提取和匹配的经典方法,可以在图像中提取出具有尺度不变性、旋转不变性和部分视角不变性特征点特征描述子

sift.detectAndCompute

  1. 功能
    detectAndCompute函数执行两个主要任务:
    (1)检测图像中的关键点(Key Points)。
    (2) 计算图像中每个关键点的特征描述子(Feature Descriptors)。
  2. 输入参数
    image: 输入的灰度图像或彩色图像,类型为uint8或float32。
    mask(可选): 可选的掩膜图像,指定哪些区域需要进行特征检测。如果不需要,可以将其设置为None。
    kp(可选): 可选的输入关键点。如果提供关键点,则函数将不再检测关键点,而是直接使用输入的关键点。如果不需要,可以将其设置为None。
    descriptors(可选): 可选的输入特征描述子。如果提供特征描述子,则函数将不再计算特征描述子,而是直接使用输入的描述子。如果不需要,可以将其设置为None。
  3. 输出结果
    kp: 检测到的关键点列表,每个关键点是一个cv2.KeyPoint对象,其中包含关键点的坐标(x、y)、尺度(scale)和方向(angle)等信息。
    des: 计算得到的特征描述子,是一个numpy数组,形状为(n, 128),其中n是关键点的数量,128表示每个特征描述子的维度为128。
  4. 使用案例
import cv2

# 读取图像
image = cv2.imread("example.jpg", cv2.IMREAD_GRAYSCALE)

# 创建SIFT对象
sift = cv2.SIFT_create()

# 检测关键点并计算特征描述子
kp, des = sift.detectAndCompute(image, None)

# 绘制关键点到图像上
image_with_keypoints = cv2.drawKeypoints(image, kp, None)

# 显示结果
cv2.imshow("Image with Keypoints", image_with_keypoints)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv.drawKeypoints

cv.drawKeypoints是OpenCV库中的一个函数,用于在图像上绘制特征点。

  1. 函数原型
cv.drawKeypoints(image, keypoints, outImage[, color[, flags]])
  1. 参数说明
    (1)image:输入的图像,即要在其上绘制特征点的图像。它应该是一个灰度图像或彩色图像,类型为numpy.ndarray。
    (2)keypoints:一个包含特征点信息的列表。每个特征点都是一个cv.KeyPoint对象,其中包含特征点的坐标、大小、方向等信息。
    (3)outImage:输出图像,即将特征点绘制在其上的图像。这应该是一个和image具有相同尺寸和通道数的图像,类型为numpy.ndarray。
    (4)color (可选):特征点的颜色。默认为随机颜色。可以通过(B, G, R)形式的元组来指定BGR颜色,例如(0, 255, 0)表示绿色。
    (4)flags (可选):特征点绘制的标志。可以使用以下值:
    cv.DRAW_MATCHES_FLAGS_DEFAULT:默认值,单个特征点用圆圈表示,显示特征点的大小和方向。
    cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS:绘制特征点的大小和方向,但使用特征点的尺寸和方向来显示特征点。

  2. 输出特点
    (1)outImage是一个新的图像,是输入图像的副本,并在其上绘制了特征点。原始图像不会被修改
    (2)特征点会以可视化的形式显示在输出图像上。通常,特征点会用圆圈表示,并根据特征点的大小和方向进行标记。
    (3)如果未指定颜色,函数会为每个特征点选择一个随机颜色,使得特征点在输出图像上可以区分开。

  3. 笔记:
    在计算机视觉领域,特征点的大小通常指的是特征点在图像中的尺寸,也称为特征点的尺度。它是描述特征点周围区域大小的一个重要属性。
    特征点检测算法通常会在图像中寻找具有不同尺度的特征点,因为不同尺度的特征点对于不同大小的目标和场景变化更具有鲁棒性。例如,在图像中找到一个突出的角点,可能在不同的图像尺度下具有不同的大小。特征点的尺度可以看作是特征点检测器所考虑的一个区域的大小,用来描述特征点周围的局部图像结构。
    一般来说,尺度较大的特征点对应于较大的图像结构或目标,而尺度较小的特征点对应于更细微的图像细节。特征点的尺度信息在后续的特征匹配和目标识别任务中起着至关重要的作用。例如,在特征点匹配中,我们可能希望将具有相似尺度的特征点进行匹配,因为它们可能对应于相似大小的目标。
    在cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS标志下,绘制特征点时会使用特征点的大小和方向信息。这样可以以视觉化的方式显示特征点的大小,并且在可视化特征点的同时也展示了它们的尺度和方向信息,使得结果更加丰富和信息丰富。
    在cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS标志下,特征点的大小和方向信息是通过cv.KeyPoint对象的属性来确定的。

cv.KeyPoint

链接:cv::KeyPoint::KeyPoint

cv::KeyPoint::KeyPoint( Point2f pt,
						float 	size,
						float 	angle = -1,
						float 	response = 0,
						int 	octave = 0,
						int 	class_id = -1 
						)	

cv.KeyPoint是一个类,它代表了一个特征点,其中包含以下属性:

  1. 相关参数
    (1)pt:特征点的位置坐标,通常为(x, y)的二维点。
    (2)size:特征点的尺度或大小。这个值用来表示特征点检测器在特征点周围选择的区域大小,用来描述特征点的局部结构。通常,size可以理解为特征点的邻域半径。
    (3)angle:特征点的方向或角度。这个值表示特征点在局部区域内的主要方向。在一些特征点检测算法中,特征点是具有主方向的,比如SIFT(尺度不变特征变换)算法。
    (4)response:特征点的响应值,表示检测器对该特征点的检测置信度或强度。在某些检测器中,响应值可以用来过滤掉一些不够显著的特征点。
    (5)octave:特征点所在的金字塔组(octave)。一些尺度空间的特征点检测器,如SIFT,通过图像金字塔来检测不同尺度的特征点。
    (6)class_id:特征点的类别ID,通常用于区分不同类别的特征点。
    当使用cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS标志绘制特征点时,会根据特征点的size和angle属性来决定绘制的样式。一般来说,特征点会以圆圈的形式绘制,圆圈的半径与特征点的size属性相关联,而箭头的方向表示特征点的angle属性
    需要注意的是,不同的特征点检测器可能会提供不同的属性信息。某些检测器可能没有angle属性,因为它们不计算特征点的方向,而只关注特征点的位置和尺度。因此,在使用特定的特征点检测器时,需要了解其输出的cv.KeyPoint对象的属性,并根据需要使用相应的属性来绘制特征点。
  2. 示例程序
import cv2
import numpy as np

def detect_and_display_keypoints(image_path):
    # 读取图像
    image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)

    # 创建SIFT特征点检测器
    sift = cv2.SIFT_create()

    # 检测特征点
    keypoints = sift.detect(image, None)

    # 绘制特征点
    image_with_keypoints = cv2.drawKeypoints(image, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

    # 输出特征点信息
    for i, kp in enumerate(keypoints):
        print(f"特征点 {i+1}:")
        print(f"  位置: ({kp.pt[0]}, {kp.pt[1]})")
        print(f"  尺度: {kp.size}")
        print(f"  方向: {kp.angle}")
        print(f"  金字塔组: {kp.octave & 0xFF}") # 提取低8位作为金字塔组
        print(f"  类别ID: {kp.class_id}")
        print()

    # 显示图像并等待按键退出
    cv2.imshow('Keypoints', image_with_keypoints)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == "__main__":
    image_path = "path/to/your/image.jpg"  # 替换为实际图像路径
    detect_and_display_keypoints(image_path)

cv2.BFMatcher

cv2.BFMatcher是OpenCV中用于创建暴力匹配器(Brute Force Matcher)的类,通常使用方式如下:

# 创建BFMatcher对象
bf = cv2.BFMatcher()

# 使用KNN匹配特征
matches = bf.knnMatch(descriptors_a, descriptors_b, k=2)

(1)bf:是一个cv2.BFMatcher对象,代表暴力匹配器(Brute Force Matcher)。它会尝试将第一幅图像(descriptors_a)的每个特征描述子与第二幅图像(descriptors_b)的所有特征描述子进行匹配。
(2)descriptors_a和descriptors_b:分别是第一幅图像和第二幅图像的特征描述子。在计算机视觉中,通常使用特征检测器(如SIFT、SURF、ORB等)来检测图像中的特征点,并提取这些特征点的描述子。这些描述子是用于表示特征点周围图像信息的向量。
(3)k=2:是KNN算法的参数之一,指定要返回的最近邻居的数量。在这里,设置为2,即对于每个特征描述子,返回两个最接近的邻居。
函数执行后,matches是一个包含所有匹配项的列表,每个匹配项都是两个最接近邻居的信息。每个匹配项都由以下信息组成:
(1)queryIdx:查询图像中的特征描述子索引,表示这个匹配是来自descriptors_a中的哪个特征点。
(2)trainIdx:训练图像中的特征描述子索引,表示这个匹配是来自descriptors_b中的哪个特征点。
(3)distance:两个描述子之间的距离,距离越小表示这两个描述子越相似。
根据描述子之间的距离(相似程度)可以选择最佳的匹配(去除不可靠的匹配,类似于设置一个置信度)

# 筛选最佳匹配
good_matches = []
for m, n in matches:
    if m.distance < 0.75 * n.distance:
        good_matches.append(m)