基于特征点匹配的图像相似度算法之SIFT特征(一)

导读

在之前的文章图像处理中常用的相似度评估指标中,我们介绍了通过 MSEPSNRSSIM以及 UQI等指标来计算图像之间的相似度。但是,在使用这些算法计算图像相似的时候两张图像的 size必须一致,而且这些算法对于图像的 旋转缩放平移仿射变换以及 光照强度等都是不鲁棒的。

这篇文章我们来介绍几个更加鲁棒的图像相似度计算的算法, SIFTSURF以及 ORB三种算法,它们都是基于特征点的提取来计算图像之间的相似度。

注意:因为需要用到 SHIFTSURF以及 ORB算法,所以需要安装 opencv-python==3.4.2.16opencv-contrib-python==3.4.2.16,如果是高本版 opencv由于license的问题可能会无法使用到这些算法

环境

  • Python:3.7
  • opencv:3.4.2.16
  • opencv-contrib:3.4.2.16

SIFT

SIFT (Scale-Invariant Feature Transform):尺度不变特征变换,是用于图像处理中的一种描述。这种描述具有尺度不变性,可在图像中检测出关键点,是一种局部特征的描述子。在图像的特征匹配和特征提取中,经常使用到。

特点

  • 不变性:SIFT特征是提取图像的局部特征,它对于 旋转尺度缩放亮度变换保持不变性,对于 噪声视角变换仿射变换也能保持一定的不变性
  • 差异性:提取的特征信息量丰富,适合在海量数据中快速找到目标
  • 实时性:优化版的SIFT算法提取特征的速度可以达到实时
  • 扩展性:提取的特征向量可以和其他的特征向量进行融合

提取特征的步骤

  1. 尺度空间的极值检测:通过高斯微分函数来寻找图像在尺度变换和旋转不变的关键点
  2. 关键点定位:在每个候选关键点上,通过拟合精细的模型来确定尺度和位置,最终的选择依据它们的稳定程度
  3. 方向的确定:基于图像局部的梯度方向,分配给每个关键点一个或多个方向
  4. 关键点描述:在关键点的领域内,选定的尺度上测量图像的局部梯度,这些梯度被变换成一种表示,这种表示允许比较大的局部变形和光照的变化

代码实现

下面我们用python来提取图像的SIFT特征

  • 导包
import cv2
import numpy as np
from matplotlib import pyplot as plt
  • 提取图像的SIFT关键点
def extract_sift_feature(img):

    sift = cv2.xfeatures2d.SIFT_create()

    keypoints, descriptors = sift.detectAndCompute(img, None)
    return keypoints,descriptors

def show_img_sift_dot(img):
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    keypoints, descriptors = extract_sift_feature(img)

    img1 = cv2.drawKeypoints(rgb_img, keypoints, img)
    plt.imshow(img1)
    plt.show()

基于特征点匹配的图像相似度算法之SIFT特征(一)
图像上面的绘制出来的圆圈就是使用 SIFT算法提取的特征点
  • 图像的关键点匹配
def draw_match_image(img1,img2):
    rgb_img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
    rgb_img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)

    keypoints1, descriptors1 = extract_sift_feature(img1)
    keypoints2, descriptors2 = extract_sift_feature(img2)

    bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)

    matches = bf.match(descriptors1, descriptors2)

    matches = sorted(matches, key=lambda x: x.distance)

    img3 = cv2.drawMatches(rgb_img1, keypoints1, rgb_img2, keypoints2, matches[:50], rgb_img2, flags=2)
    plt.imshow(img3)
    plt.show()

基于特征点匹配的图像相似度算法之SIFT特征(一)
上面是两张图片,左图是原图,右图是在原图的基础上增加了高斯噪声,直线连接了两张图像的相似的关键点
  • 通过匹配的关键点个数来计算相似度
    通过计算两张图之间SIFT关键点的匹配个数占总匹配数量的比例来计算相似度,这个算法计算出来的上面的两张图片的相似度只有28%,比较低
def cal_SIFT_sim(img1,img2):

    img1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
    img2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

    keypoints1,descriptors1 = extract_sift_feature(img1)
    keypoints2,descriptors2 = extract_sift_feature(img2)

    bf = cv2.BFMatcher()

    matches1 = bf.knnMatch(descriptors1,descriptors2,k=2)
    top_results1 = []
    for m,n in matches1:
        if m.distance < 0.7 * n.distance:
            top_results1.append(m)

    matches2 = bf.knnMatch(descriptors2,descriptors1,k=2)
    top_results2 = []
    for m,n in matches2:
        if m.distance < 0.7 * n.distance:
            top_results2.append(m)

    top_results = []
    for m1 in top_results1:
        m1_query_idx = m1.queryIdx
        m1_train_idx = m1.trainIdx

        for m2 in top_results2:
            m2_query_idx = m2.queryIdx
            m2_train_idx = m2.trainIdx

            if m1_query_idx == m2_train_idx and m1_train_idx == m2_query_idx:
                top_results.append(m1)

    image_sim = len(top_results) / min(len(keypoints1),len(keypoints2))
    return image_sim
  • 提取图片SIFT特征的向量计算相似度
    将图片中的每个SIFT特征点转换称为一个128维的特征向量,通过控制提取特征的个数来控制特征向量的长度,理论上来说组合特征向量用到的特征越多计算出来的图片相似度越高。
def extract_SIFT_vector(img,vector_size):
    gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    sift = cv2.xfeatures2d.SIFT_create()
    keypoints = sift.detect(gray_img, None)

    keypoints = sorted(keypoints, key=lambda x: -x.response)
    img_kps = keypoints[:vector_size]

    kps, des = sift.compute(gray_img, img_kps)

    vector = des.flatten()

    vector_len = vector_size * 128

    if vector.size < vector_len:
        vector = np.concatenate(vector, np.zeros(vector_len - vector.size))
    return vector

 import scipy.spatial as T

vector_size = 30
img_path1 = "demo.png"
img_path2 = "demo_gauss_noise.png"
img1 = cv2.imread(img_path1)
img2 = cv2.imread(img_path2)

img1_vector = extract_SIFT_vector(img1,vector_size).reshape(-1,128*vector_size)
img2_vector = extract_SIFT_vector(img2,vector_size).reshape(-1,128*vector_size)

sim = T.distance.cdist(img1_vector, img2_vector, 'cosine')
print(sim)

总结

这篇文章我们主要介绍了如何使用opencv来提取图片的SIFT特征,以及如何来使用SIFT特征点来进行图像匹配和图像的相似度计算

参考

  1. https://medium.com/@shehan.a.perera/a-comparison-of-sift-surf-and-orb-333d64bcaaea
  2. https://docs.opencv.org/4.5.5/df/dd2/tutorial_py_surf_intro.html
  3. https://github.com/ShehanPerera/Research
  4. https://stackoverflow.com/questions/64525121/sift-surf-set-opencv-enable-nonfree-cmake-solution-opencv-3-opencv-4
  5. https://docs.opencv.org/4.x/dc/dc3/tutorial_py_matcher.html

Original: https://blog.csdn.net/sinat_29957455/article/details/125136620
Author: 修炼之路
Title: 基于特征点匹配的图像相似度算法之SIFT特征(一)

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/701158/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球