RootSift 是论文 Three things everyone should know to improve object retrieval - 2012 所提出的.

A Comparative Analysis of RootSIFT and SIFT Methods for Drowsy Features Extraction - 2020

当比较直方图时,使用欧氏距离通常比卡方距离或Hellinger核时的性能差,但是在使用 SIFT 特征点为什么一直都使用欧氏距离呢?

不论是对 SIFT 特征点进行匹配,还是对 SIFT 特征集合进行聚类得到视觉词汇表,又或者对图像进行BoW编码,都使用的是欧氏距离. 但是 SIFT 特征描述子本质上也是一种直方图,为什么对 SIFT 特征描述子进行比较的时候要使用欧氏距离呢,有没有一种更精确的比较方法呢?

SIFT 描述子统计的是关键点邻域的梯度直方图.

论文作者认为之所以一直使用欧氏距离来测量 SIFT 特征的相似度,是由于在 SIFT 提出时,使用的是欧氏距离的度量,可以找出一种比较欧氏距离更为精确的度量方法. 故,提出了RootSift 对 SIFT 特征进行扩展.

具体操作如下:

在提取到 SIFT 描述向量 $x$ 后,进行如下处理,即可得到 RootSIFT:

[1] - 对特征向量 $x$ 进行 $l_1$ 的归一化得到 $x'$;

[2] - 对 $x'$ 的每一个元素求平方根;

[3] - 进行 $l_2$ 归一化.(可选)

[3]中,是否进行l2归一化,有些不一致. 在RootSIFT 论文 中并没有指出需要进行 l2 归一化,但是在 presentation, 却有 l2归一化.

也有认为,显式地执行L2规范化是不需要的. 通过采用L1规范,然后是平方根,已经有L2标准化的特征向量,不需要进一步的标准化.

参考:图像检索(4):IF-IDF,RootSift,VLAD -- RootSIFT

1. RootSIFT 实现

Python 实现如:

https://www.pyimagesearch.com/2015/04/13/implementing-rootsift-in-python-and-opencv/

https://github.com/jrosebr1/imutils/blob/master/imutils/feature/rootsift.py

import numpy as np
import cv2

class RootSIFT:
    def __init__(self):
        # initialize the SIFT feature extractor
        #OpenCV2.4
        # self.extractor = cv2.DescriptorExtractor_create("SIFT")
                #OpenCV3+
        self.extractor = cv2.xfeatures2d.SIFT_create()
        
    def compute(self, image, kps, eps=1e-7):
        # compute SIFT descriptors
        kps, descs = self.extractor.compute(image, kps)

        # if there are no keypoints or descriptors, return an empty tuple
        if len(kps) == 0:
            return ([], None)

        # apply the Hellinger kernel by first L1-normalizing and taking the
        # square-root
        descs /= (descs.sum(axis=1, keepdims=True) + eps)
        descs = np.sqrt(descs)
        #descs /= (np.linalg.norm(descs, axis=1, ord=2) + eps)

        # return a tuple of the keypoints and descriptors
        return (kps, descs)
#
image = cv2.imread("test.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
 
# detect Difference of Gaussian keypoints in the image
sift = cv2.xfeatures2d.SIFT_create()
kps, descs = sift.detectAndCompute(img1, None)
print "SIFT: kps=%d, descriptors=%s " % (len(kps), descs.shape)
 
# extract RootSIFT descriptors
root_sift = RootSIFT()
(kps, descs) = root_sift.compute(image, kps)
print "RootSIFT: kps=%d, descriptors=%s " % (len(kps), descs.shape)

C++ 实现:

for(int i = 0; i < siftFeature.rows; i ++){
        // Conver to float type
        Mat f;
        siftFeature.row(i).convertTo(f,CV_32FC1);

        normalize(f,f,1,0,NORM_L1); // l1 normalize
        sqrt(f,f); // sqrt-root  root-sift
        rootSiftFeature.push_back(f);
    }

2. 基于 RootSIFT 的相似图搜索

Last modification:February 20th, 2021 at 07:30 pm