图像检索之IF-IDF,RootSift,VLAD

2022-04-16 04:26:13

TF-IDF

TF-IDF是一种用于信息检索的常用加权技术,在文本检索中,用以评估词语对于一个文件数据库中的其中一份文件的重要程度。词语的重要性随着它在文件中出现的频率成正比增加,但同时会随着它在文件数据库中出现的频率成反比下降。像‘的',‘我们',‘地'等这些常用词在所有文章中出现的频率会很高,并不能很好的表征一个文档的内容。

同样的在图像检索中也引入了IF-IDF权重,

词频(Term Frequency,TF) 一个visual word在一个图像中出现的频率的很高,则说明该visual word 能够很好的代表图像的内容。

图像检索之IF-IDF,RootSift,VLAD

逆文档词频(Inverse Document Frequency,IDF) 一些常见的word,会在每一图像出现的频率都很高,但是这些word并不能很好的表示图像的内容,所以要给这一部分word低一些的权重。IDF,描述一个word的普遍重要性,如古欧word在很多的图像中出现的频率都很高,则给予其较低的权重。

图像检索之IF-IDF,RootSift,VLAD

将分母+1是为了防止除数为0的情况出现。从上式中可以看出,包含当前word的图像个数越多,IDF的值越小,说明该词越不重要。反之,该词越重要。

计算得到了TF和IDF,则有

FT 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)

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

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);    }

VLAD

局部聚合向量(Vector of Locally Aggregated Descriptors,VLAD)

前面介绍的BoW方法,在图像的检索和检索中有这广泛的应用。BoW通过聚类,对图像的局部特征进行重新编码,有很强的表示能力,并且使用SVM这样基于样本间隔的分类器,也能取得了很好的分类效果。但是在图像规模比较大的情况下,由于视觉词汇表Vocabulary大小的限制,BoW对图像的表示会越来越粗糙,编码后损失的图像信息较多,检索精度也随之而降低。

2010年,论文Aggregating local descriptors into a compact image representation中提出了一对新的图像表示方法,VLAD。从三个方面进行改进:

使用VLAD表示图像的局部特征 PCA 索引ADC的构建方法

BoW的表示方法中,是统计每个特征词汇www.easck.com在图像中出现的频率。VLAD则是求落在同一个聚类中心的特征和该聚类中心残差的累加和。公式表示如下:

图像检索之IF-IDF,RootSift,VLAD

由于,VLAD是特征和其最邻近的聚类中心的残差和,该向量的很多分量很多分量都为0,也就是说该向量是稀疏的(sparse,很少的分量占有大部分的能量),所以可以对VLAD进行降维处理(例如,PCA)能进一步缩小向量的大小。

void Vocabulary::transform_vlad(const cv::Mat &f,cv::Mat &vlad){    // Find the nearest center    Ptr<FlannBasedMatcher> matcher = FlannBasedMatcher::create();    vector<DMatch> matches;    matcher->match(f,m_voc,matches);    // Compute vlad    Mat responseHist(m_voc.rows,f.cols,CV_32FC1,Scalar::all(0));    for( size_t i = 0; i < matches.size(); i++ ){        auto queryIdx = matches[i].queryIdx;        int trainIdx = matches[i].trainIdx; // cluster index        Mat residual;        subtract(f.row(queryIdx),m_voc.row(trainIdx),residual,noArray());        add(responseHist.row(trainIdx),residual,responseHist.row(trainIdx),noArray(),responseHist.type());    }    // l2-norm    auto l2 = norm(responseHist,NORM_L2);    responseHist /= l2;    //normalize(responseHist,responseHist,1,0,NORM_L2);    //Mat vec(1,m_voc.rows * f.cols,CV_32FC1,Scalar::all(0));    vlad = responseHist.reshape(0,1); // Reshape the matrix to 1 x (k*d) vector}

借助于OpenCV实现还是比较简单的。这里使用FlannBasedMatchermatch方法来查找特征最邻近的聚类中心(视觉词汇)。可以分为以下三步:

subtract计算特征和其最近邻的聚类中心的差值,add将同一个聚类中心的差值累加起来 对上面得到的矩阵的responseHist进行(l_2)的归一化处理 使用reshape方法,将矩阵拉伸为一维(k*d(128))的一维向量VLAD。

Summary

Bow通常要搭配TF-IDF进行使用,但是由于Vocabulary的大小的限制,VLAD是一个不错的替代选择。RootSift是对原生sift的扩展。