使用 Matlab 从 VLFeat 中的 SIFT 描述符中提取 VLAD
Extracting VLAD from SIFT Descriptors in VLFeat with Matlab
我有一个图片文件夹。我想计算每个图像的 VLAD 特征。
我遍历每个图像,加载它,并按如下方式获取 SIFT 描述符:
repo = '/media/data/images/';
filelist = dir([repo '*.jpg']);
sift_descr = {}
for i = 1:size(filelist, 1)
I = imread([repo filelist(i).name]) ;
I = single(rgb2gray(I)) ;
[f,d] = vl_sift(I) ;
sift_descr{i} = d
end
但是,VLAD 要求描述符矩阵是二维的。参见 here。在 VLAD 编码之前,处理我的 SIFT 描述符的正确方法是什么?谢谢。
首先,你需要获得一个视觉词词典,或者更具体地说:使用k-均值聚类对所有图像的SIFT特征进行聚类。在 [1] 中,粗聚类使用例如建议使用 64 或 256 个簇。
为此,我们必须将所有描述符连接成一个矩阵,然后我们可以将其传递给 vl_kmeans
函数。此外,我们将描述符从 uint8
转换为 single
,因为 vl_kmeans
函数要求输入为 single
或 double
.
all_descr = single([sift_descr{:}]);
centroids = vl_kmeans(all_descr, 64);
其次,您必须创建一个分配矩阵,其维度为 NumberOfClusters-by-NumberOfDescriptors,它将每个描述符分配给一个集群。您在创建此分配矩阵时有很大的灵活性:您可以进行软分配或硬分配,您可以自行决定使用简单的最近邻搜索或 kd-trees 或其他近似或分层最近邻方案。
在教程中,他们使用 kd-trees,所以让我们坚持这一点:首先,必须构建一个 kd-tree。此操作属于在找到 centroids
:
之后
kdtree = vl_kdtreebuild(centroids);
然后,我们准备为每个图像构建 VLAD 向量。因此,我们必须再次遍历所有图像,并独立计算它们的 VLAD 向量。首先,我们完全按照教程中的描述创建分配矩阵。然后,我们可以使用 vl_vlad
函数对 SIFT 描述符进行编码。
生成的 VLAD 向量的大小为 NumberOfClusters * SiftDescriptorSize,即我们示例中的 64*128..
enc = zeros(64*128, numel(sift_descr));
for k=1:numel(sift_descr)
% Create assignment matrix
nn = vl_kdtreequery(kdtree, centroids, single(sift_descr{k}));
assignments = zeros(64, numel(nn), 'single');
assignments(sub2ind(size(assignments)), nn, 1:numel(nn))) = 1;
% Encode using VLAD
enc(:, k) = vl_vlad(single(sift_descr{k}), centroids, assignments);
end
最后,我们得到了数据库中所有图像的 high-dimensional VLAD 向量。通常,您会想要减少 VLAD 描述符的维数,例如使用 PCA。
现在,给定不在数据库中的新图像,您可以使用 vl_sift
提取 SIFT 特征,使用 vl_kdtreequery
创建分配矩阵,并使用vl_vlad
。因此,您不必寻找新的质心或创建新的 kd-tree:
% Load image and extract SIFT features
new_image = imread('filename.jpg');
new_image = single(rgb2gray(new_image));
[~, new_sift] = vl_sift(new_image);
% Create assignment matrix
nn = vl_kdtreequery(kdtree, centroids, single(new_sift));
assignments = zeros(64, numel(nn), 'single');
assignments(sub2ind(size(assignments)), nn, 1:numel(nn))) = 1;
% Encode using VLAD
new_vlad = vl_vlad(single(new_sift), centroids, assignments);
[1] Arandjelovic, R., & Zisserman, A. (2013)。关于 VLAD。 IEEE 计算机视觉和模式识别会议 (CVPR),1578–1585。 https://doi.org/10.1109/CVPR.2013.207
我有一个图片文件夹。我想计算每个图像的 VLAD 特征。
我遍历每个图像,加载它,并按如下方式获取 SIFT 描述符:
repo = '/media/data/images/';
filelist = dir([repo '*.jpg']);
sift_descr = {}
for i = 1:size(filelist, 1)
I = imread([repo filelist(i).name]) ;
I = single(rgb2gray(I)) ;
[f,d] = vl_sift(I) ;
sift_descr{i} = d
end
但是,VLAD 要求描述符矩阵是二维的。参见 here。在 VLAD 编码之前,处理我的 SIFT 描述符的正确方法是什么?谢谢。
首先,你需要获得一个视觉词词典,或者更具体地说:使用k-均值聚类对所有图像的SIFT特征进行聚类。在 [1] 中,粗聚类使用例如建议使用 64 或 256 个簇。
为此,我们必须将所有描述符连接成一个矩阵,然后我们可以将其传递给 vl_kmeans
函数。此外,我们将描述符从 uint8
转换为 single
,因为 vl_kmeans
函数要求输入为 single
或 double
.
all_descr = single([sift_descr{:}]);
centroids = vl_kmeans(all_descr, 64);
其次,您必须创建一个分配矩阵,其维度为 NumberOfClusters-by-NumberOfDescriptors,它将每个描述符分配给一个集群。您在创建此分配矩阵时有很大的灵活性:您可以进行软分配或硬分配,您可以自行决定使用简单的最近邻搜索或 kd-trees 或其他近似或分层最近邻方案。
在教程中,他们使用 kd-trees,所以让我们坚持这一点:首先,必须构建一个 kd-tree。此操作属于在找到 centroids
:
kdtree = vl_kdtreebuild(centroids);
然后,我们准备为每个图像构建 VLAD 向量。因此,我们必须再次遍历所有图像,并独立计算它们的 VLAD 向量。首先,我们完全按照教程中的描述创建分配矩阵。然后,我们可以使用 vl_vlad
函数对 SIFT 描述符进行编码。
生成的 VLAD 向量的大小为 NumberOfClusters * SiftDescriptorSize,即我们示例中的 64*128..
enc = zeros(64*128, numel(sift_descr));
for k=1:numel(sift_descr)
% Create assignment matrix
nn = vl_kdtreequery(kdtree, centroids, single(sift_descr{k}));
assignments = zeros(64, numel(nn), 'single');
assignments(sub2ind(size(assignments)), nn, 1:numel(nn))) = 1;
% Encode using VLAD
enc(:, k) = vl_vlad(single(sift_descr{k}), centroids, assignments);
end
最后,我们得到了数据库中所有图像的 high-dimensional VLAD 向量。通常,您会想要减少 VLAD 描述符的维数,例如使用 PCA。
现在,给定不在数据库中的新图像,您可以使用 vl_sift
提取 SIFT 特征,使用 vl_kdtreequery
创建分配矩阵,并使用vl_vlad
。因此,您不必寻找新的质心或创建新的 kd-tree:
% Load image and extract SIFT features
new_image = imread('filename.jpg');
new_image = single(rgb2gray(new_image));
[~, new_sift] = vl_sift(new_image);
% Create assignment matrix
nn = vl_kdtreequery(kdtree, centroids, single(new_sift));
assignments = zeros(64, numel(nn), 'single');
assignments(sub2ind(size(assignments)), nn, 1:numel(nn))) = 1;
% Encode using VLAD
new_vlad = vl_vlad(single(new_sift), centroids, assignments);
[1] Arandjelovic, R., & Zisserman, A. (2013)。关于 VLAD。 IEEE 计算机视觉和模式识别会议 (CVPR),1578–1585。 https://doi.org/10.1109/CVPR.2013.207