我想在MATLAB中实现一堆视觉词。我使用SURF功能从图像中提取特征,并使用k-means将这些特征聚类到k
个聚类中。我现在有k
个质心,我想通过将每个图像特征分配给它的壁橱邻居来了解每个群集的使用次数。最后,我想为每个图像创建一个这样的直方图。
我尝试使用knnsearch
功能,但在这种情况下它不起作用。
这是我的MATLAB代码:
clc;
clear;
close all;
folder = 'CarData/TrainImages/cars';
filePattern = fullfile(folder, '*.pgm');
f=dir(filePattern);
files={f.name};
for k=1:numel(files)
fullFileName = fullfile(folder, files{k});
H = fspecial('log');
image=imfilter(imread(fullFileName),H);
temp = detectSURFFeatures(image);
[im_features, temp] = extractFeatures(image, temp);
features{k}= im_features;
end
features = vertcat(features{:});
image_feats = [];
[assignments,centers] = kmeans(double(features),500);
vocab = centers';
我在要素数组中具有所有图像功能,并且在质心数组中具有聚类中心
答案 0 :(得分:1)
你几乎就在那里。你根本不需要使用knnsearch
。 assignments
变量告诉您哪个输入要素映射到哪个群集。 assignments
将为您提供N x 1
向量,其中N
是您拥有的示例总数,或输入矩阵features
中的要素总数。每个值assignments(i)
都会告诉您映射到i
的示例i
(或行features
)的群集。由assignments(i)
指定的群集质心将以centers(i, :)
的形式给出。
因此,根据您调用kmeans
的方式,它将是N x 1
向量,其中每个元素从1到500,其中500是所需群集的总数。
让我们做一个简单的情况,我们的代码簿中只有一个图像。如果是这种情况,您只需要创建{{1}的直方图。变量。输出直方图assignments
将是h
向量,每个元素500 x 1
是示例使用质心h(i)
作为其在代码簿中的表示的次数。
只需使用histcounts
功能,并确保指定bin范围,以便它们与每个群集ID重合。您必须确保考虑到结束箱,因为箱子范围在右边缘是独占的,所以只需在末尾添加一个额外的箱子。
这样的事情会起作用:
i
如果您想要更简单的事情并且不想担心指定结束文件夹,可以使用accumarray
来获得相同的结果:
h = histcounts(assignments, 1 : 501);
我们分配键值对的h = accumarray(assignments, 1);
的效果,其中键是示例映射到的质心,而值对于所有键都是1。 accumarray
会将accumarray
中共享相同密钥的所有值合并,并对这些值执行某些操作。 assignments
的默认行为是对所有值求和,这有效地计算直方图。
但是,您希望对多个图像执行此操作,而不仅仅是单个图像。
对于Bag of Visual Words问题,我们的数据库中肯定会有多个训练图像。因此,您需要找到每个图像的要素的直方图。我们仍然可以使用上述概念,但我可以建议的一件事是你维护一个单独的变量来告诉你每个图像检测到多少个特征,然后你可以索引到accumarray
变量以帮助提取出正确的分配质心ID,然后单独构建那些直方图。我们可以构建一个2D矩阵,其中每一行描绘每个图像的直方图。请记住,在assignments
中,每行都会告诉您每个示例分配给哪个群集,而与数据中的其他示例无关。使用它,您可以在整个训练数据集上使用kmeans
,然后明智地了解您如何访问kmeans
变量以提取每个输入图像的指定群集。
因此,请修改您的代码,使其看起来像这样:
assignments
clc;
clear;
close all;
folder = 'CarData/TrainImages/cars';
filePattern = fullfile(folder, '*.pgm');
f=dir(filePattern);
files={f.name};
num_features = zeros(numel(files), 1); % New - for keeping track of # of features per image
for k=1:numel(files)
fullFileName = fullfile(folder, files{k});
H = fspecial('log');
image=imfilter(imread(fullFileName),H);
temp = detectSURFFeatures(image);
[im_features, temp] = extractFeatures(image, temp);
num_features(k) = size(im_features, 1); % New - # of features per image
features{k}= im_features;
end
features = vertcat(features{:});
num_clusters = 500; % Added to make the code adaptive
[assignments,centers] = kmeans(double(features), num_clusters);
counter = 1; % Keeps track of where we need to slice in assignments
% Go through each image and find their histograms
features_hist = zeros(numel(files), num_clusters); % Records the per image histograms
for k = 1 : numel(files)
a = assignments(counter : counter + num_features(k) - 1); % Get the assignments
h = histcounts(a, 1 : num_clusters + 1);
% Or:
% h = accumarray(a, 1).'; % Transpose to make it a row
% Place in final output
features_hist(k, :) = h;
% Increment counter
counter = counter + num_features(k);
end
现在将成为features_hist
矩阵,其中每一行都是您要搜索的每张图片的直方图。最后的工作是使用有监督的机器学习算法(SVM,神经网络等),其中期望的标签是您分配给图像的每个图像的描述,伴随着每个图像的直方图作为输入特征。最终结果将是一个学习模型,以便当您有一个新图像时,计算SURF特征,在我们上面所做的特征直方图中表示它们,然后将其输入分类模型,为您提供预期的类或标签图像代表。
P.S。深度学习/ CNN在这方面做得更好,但需要更多的时间来训练。如果您正在考虑性能方面,请不要使用Bag of Visual Words,但这是很快实现的,并且已知其表现适度,但这当然取决于图像的种类你想分类。