Precision-Recall 图测量图像检索系统的准确性。它们还用于任何搜索引擎的性能,例如文本或文档。它们也用于机器学习评估和性能,尽管ROC 曲线是更常用的。
Precision-Recall 图更适合文档和数据检索。对于此处的图像情况,给定您的查询图像,您正在测量该图像与数据库中其余图像的相似程度。然后,您可以针对与查询图像相关的每个数据库图像进行相似性度量,然后按降序对这些相似性进行排序。对于一个好的检索系统,您会希望最相关的图像(即您正在搜索的内容)都出现在开头,而不相关的图像会出现在后面。
精确
精度的定义是你检索到的相关图像的数量与检索到的不相关和相关图像的总数之比。换句话说,假设这A
是检索到的相关图像的数量,并且B
是检索到的不相关图像的总数。在计算精度时,您查看前几张图像,这个数量是A + B
,因为相关和不相关图像的总数是您此时正在考虑的图像数量。因此,另一个定义精度定义为到目前为止,您从抓取的一堆图像中检索到多少相关图像的比率:
Precision = A / (A + B)
记起
召回的定义略有不同。这会评估到目前为止您在已知总数中检索到的相关图像的数量,这是存在的相关图像的总数。因此,假设您再次查看前几张图像。然后确定有多少相关图像,然后计算到目前为止从数据库中的所有相关图像中检索到的相关图像的数量。这被定义为您已检索到的相关图像总数的比率。假设这A
又是您从数据库中抓取的一堆相关图像中检索到的总数量,并C
代表总数数据库中相关图像的数量。因此,召回率定义为:
Recall = A / C
在 MATLAB 中如何计算它实际上非常简单。您首先需要知道数据库中有多少相关图像。之后,您需要知道分配给每个数据库图像相对于查询图像的相似性度量。计算完这些后,您需要知道哪些相似性度量映射到数据库中的哪些相关图像。我在你的代码中没有看到,所以我把它留给你。完成此操作后,您可以对相似度值进行排序,然后查看这些相关图像在排序后的相似度值中出现的位置。然后,您可以使用这些来计算您的准确率和召回率。
我将提供一个玩具示例,以便向您展示图表的外观,因为您在这里如何计算相似度还不是很清楚。假设我在 20 个数据库中有 5 个图像,并且我在它们和查询图像之间有一堆相似度值:
rng(123); %// Set seed for reproducibility
num_images = 20;
sims = rand(1,num_images);
sims =
Columns 1 through 13
0.6965 0.2861 0.2269 0.5513 0.7195 0.4231 0.9808 0.6848 0.4809 0.3921 0.3432 0.7290 0.4386
Columns 14 through 20
0.0597 0.3980 0.7380 0.1825 0.1755 0.5316 0.5318
另外,我知道图像[1 5 7 9 12]
是我的相关图像。
relevant_IDs = [1 5 7 9 12];
num_relevant_images = numel(relevant_IDs);
现在让我们按降序对相似度值进行排序,因为值越高意味着相似度越高。如果您正在计算相异性度量,您会颠倒这个:
[sorted_sims, locs] = sort(sims, 'descend');
locs
现在将包含每个图像排名的图像等级。具体来说,这些会告诉您图像属于哪个相似位置。 sorted_sims
将按降序排列相似性:
sorted_sims =
Columns 1 through 13
0.9808 0.7380 0.7290 0.7195 0.6965 0.6848 0.5513 0.5318 0.5316 0.4809 0.4386 0.4231 0.3980
Columns 14 through 20
0.3921 0.3432 0.2861 0.2269 0.1825 0.1755 0.0597
locs =
7 16 12 5 1 8 4 20 19 9 13 6 15 10 11 2 3 17 18 14
因此,第 7 幅图像是排名最高的图像,第 16 幅图像是第二高的图像,依此类推。您现在需要做的是,对于您知道的每个相关图像,您需要在排序后找出它们的位置。我们将遍历我们知道相关的每个图像 ID,并找出它们在上述位置数组中的位置:
locations_final = arrayfun(@(x) find(locs == x, 1), relevant_IDs)
locations_final =
5 4 1 10 3
让我们对这些进行排序,以更好地理解这是在说什么:
locations_sorted = sort(locations_final)
locations_sorted =
1 3 4 5 10
上面的这些位置现在告诉您相关图像出现的顺序。因此,第一个相关图像将首先出现,第二个相关图像将出现在第三个位置,第三个相关图像将出现在第四个位置,依此类推。这些恰好对应于 Precision 的部分定义。例如,在 的最后一个位置locations_sorted
,需要十张图像来检索我们数据库中的所有相关图像 (5)。同样,在数据库中检索四张相关图像需要五张图像。因此,您将像这样计算精度:
precision = (1:num_relevant_images) ./ locations_sorted;
同样对于召回,它只是到目前为止检索到的图像数量与总数的比率,因此它只是:
recall = (1:num_relevant_images) / num_relevant_images;
您的 Precision-Recall 图表现在如下所示,Recall 在 x 轴上,Precision 在 y 轴上:
plot(recall, precision, 'b.-');
xlabel('Recall');
ylabel('Precision');
title('Precision-Recall Graph - Toy Example');
axis([0 1 0 1.05]); %// Adjust axes for better viewing
grid;
这是我得到的图表:

您会注意到,在 0.4 到 0.8 的召回率之间,精度略有增加。这是因为您已经成功地检索了连续的图像链而没有触及任何不相关的图像,因此您的精度自然会提高。在最后一张图像之后它会下降很多,因为您必须在最终找到相关图像之前检索这么多不相关的图像。
您还会注意到准确率和召回率是负相关的。因此,如果精度提高,那么召回率就会降低。同样,如果精度降低,那么召回率就会增加。
- 第一部分是有道理的,因为如果您一开始没有检索到那么多图像,那么您就有更大的机会在结果中不包括不相关的图像,但与此同时,相关图像的数量相当少。这就是为什么当精确度增加时召回率会降低
- 第二部分也很有意义,因为当您不断尝试在数据库中检索更多图像时,您将不可避免地能够检索所有相关的图像,但您很可能会开始包含更多不相关的图像,从而推动你的精度下降。
在理想情况下,如果您N
的数据库中有相关图像,您会希望在N
最相似的位置看到所有这些图像。因此,这将使您的精确召回图成为一条悬停在 的水平线y = 1
,这意味着您已经成功地检索了所有顶部位置的所有图像,而无需访问任何不相关的图像。不幸的是,这永远不会发生(或者至少现在不会……)因为试图找出 CBIR 的最佳功能仍然是一项持续的调查,而且我所见过的任何图像搜索引擎都无法做到这一点完美的。这仍然是当今存在的最广泛和未解决的计算机视觉问题之一!
编辑
您从这篇文章中检索了这段代码来计算直方图的交集。他们有一种计算直方图交集的简洁方法:

n
是直方图中的 bin 总数。您必须尝试使用它才能获得良好的结果,但我们可以将其作为参数保留在您的代码中。上面的代码假设您有两个矩阵A
,并且B
每列都是直方图。您将生成一个 的矩阵a x b
,其中a
是 中的列数,A
是b
中的列数b
。该矩阵的行和列(i,j)
告诉您 中的第 i列与A
中的第jb
列之间的相似性。在您的情况下,将是一个表示查询图像的直方图的列。 B
A
B
将是一个 10 列矩阵,表示每个数据库图像的直方图。因此,我们将1 x 10
通过直方图交集得到一系列相似度度量。
因此,我们需要修改您的代码,以便您imhist
用于每个图像。我们还可以指定一个附加参数,为您提供每个直方图将有多少个 bin。因此,您的代码将如下所示。我放置的每一行都会%// NEW
在每一行旁边有一个注释。
Inp1=rgb2gray(imread('D:\visionImages\c1\1.ppm'));
figure, imshow(Inp1), title('Input image 1');
num_bins = 32; %// NEW - I'm specifying 32 bins here. Play around with this yourself
A = imhist(Inp1, num_bins); %// NEW - Calculate histogram
srcFiles = dir('D:\visionImages\c1\*.ppm'); % the folder in which images exists
B = zeros(num_bins, length(srcFiles)); %// NEW - Store histograms of database images
for i = 1 : length(srcFiles)
filename = strcat('D:\visionImages\c1\',srcFiles(i).name);
I = imread(filename);
I=rgb2gray(I);
B(:,i) = imhist(I, num_bins); %// NEW - Put each histogram in a separate
%// column
end
%// NEW - Taken directly from the website
%// but modified for only one histogram in `A`
b = size(B,2);
Va = repmat(A, 1, b);
K = 0.5*sum(Va + B - abs(Va - B));
请注意,我从网站上复制了代码,但我修改了它,因为里面只有一张图片,A
所以有些代码是不必要的。
K
现在应该是1 x 10
直方图相交相似度的数组。然后,您将在我上面编写的代码中使用K
并分配sims
给这个变量(即sims = K;
),然后运行您的图像。您还需要知道哪些图像是相关图像,并且您必须更改我编写的代码以反映这一点。
希望这可以帮助!