如何在MATLAB中绘制基于内容的图像检索的Precision-Recall图?

nik*_*ilk 6 matlab image-processing cbir

我正在从文件夹"c1"访问10个图像,我有查询图像.我已经实现了在单元格数组中加载图像的代码,然后我将逐个计算查询图像与文件夹"c1"中每个图像之间的直方图交集.现在我想绘制精确回忆曲线,但我不知道如何编写代码以使用从直方图交叉点获得的数据获得"精确回忆曲线".我的代码:

Inp1=rgb2gray(imread('D:\visionImages\c1\1.ppm'));
figure, imshow(Inp1), title('Input image 1');

srcFiles = dir('D:\visionImages\c1\*.ppm');  % the folder in which images exists
for i = 1 : length(srcFiles)
    filename = strcat('D:\visionImages\c1\',srcFiles(i).name);
    I = imread(filename);
    I=rgb2gray(I);
    Seq{i}=I;


end
for i = 1 : length(srcFiles)  % loop for calculating histogram intersections
    A=Seq{i};
    B=Inp1;
    a = size(A,2); b = size(B,2); 
    K = zeros(a, b);
    for j = 1:a
    Va = repmat(A(:,j),1,b);
    K(j,:) = 0.5*sum(Va + B - abs(Va - B));
    end  
end
Run Code Online (Sandbox Code Playgroud)

ray*_*ica 11

Precision-Recall图表可以测量图像检索系统的准确性.它们也用于任何搜索引擎的性能,如文本或文档.它们也用于机器学习评估和性能,尽管ROC曲线是更常用的.

Precision-Recall图更适合文档和数据检索.对于此处的图像,给定查询图像,您将测量此图像与数据库中其余图像的相似程度.然后,您可以为每个与查询图像相关的数据库图像建立相似性度量,然后按降序这些相似性进行排序.对于一个好的检索系统,您可能希望所有最相关的图像(即您要搜索的内容)都出现在开头,而不相关的图像将出现在之后.

精确

精度的定义是您检索的相关图像的数量与检索到的不相关和相关图像的总数之比.换句话说,假设这A是检索到的相关图像的数量,并且B是检索到的不相关图像的总数.在计算精度时,您可以查看前几个图像,这个数量是A + B,相关和不相关图像的总数是您此时正在考虑的图像数量.因此,另一个定义Precision定义为您从目前为止检索到的相关图像的数量与您抓取的数量之比:

Precision = A / (A + B)
Run Code Online (Sandbox Code Playgroud)

召回

Recall的定义略有不同.这将评估到目前为止已检索到的已知总数中有多少相关图像,即已存在的相关图像的总数.因此,让我们再次看一下前几张图片.然后,您可以确定有多少相关图像,然后计算到目前为止从数据库中的所有相关图像中检索到的相关图像数量.这被定义为您总体检索的相关图像的比例.假设这A又是您从数据库中获取的一堆相关图像C总数,并表示数据库中相关图像的总数.召回因此定义为:

Recall = A / C
Run Code Online (Sandbox Code Playgroud)

你如何在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
Run Code Online (Sandbox Code Playgroud)

另外,我知道图像[1 5 7 9 12]是我的相关图像.

relevant_IDs = [1 5 7 9 12];
num_relevant_images = numel(relevant_IDs);
Run Code Online (Sandbox Code Playgroud)

现在让我们按降序对相似度值进行排序,因为更高的值意味着更高的相似度.如果计算相异度度量,则可以反转此项:

[sorted_sims, locs] = sort(sims, 'descend');
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

因此,第7个图像是排名最高的图像,其次是第16个图像是第二个最高的图像,依此类推.您现在需要做的是对于您知道相关的每个图像,您需要在排序后确定这些图像的位置.我们将浏览我们知道相关的每个图像ID,并找出它们在上述位置数组中的位置:

locations_final = arrayfun(@(x) find(locs == x, 1), relevant_IDs)

locations_final =

  5     4     1    10     3
Run Code Online (Sandbox Code Playgroud)

让我们对它们进行排序,以便更好地理解这是在说什么:

locations_sorted = sort(locations_final)

locations_sorted = 

 1     3     4     5    10
Run Code Online (Sandbox Code Playgroud)

上面的这些位置现在告诉您相关图像的显示顺序.这样,第一相关图像将首先出现,第二相关图像将出现在第三位置,第三相关图像出现在第四位置,依此类推.这些精确对应于Precision的部分定义.例如,在最后一个位置locations_sorted,将需要10张图像来检索我们数据库中的所有相关图像(5).同样,它需要五个图像来检索数据库中的四个相关图像.因此,您可以像这样计算精度:

precision = (1:num_relevant_images) ./ locations_sorted;
Run Code Online (Sandbox Code Playgroud)

同样地,对于召回来说,它只是到目前为止从总数中检索到的图像的比例,因此它只是:

recall = (1:num_relevant_images) / num_relevant_images;
Run Code Online (Sandbox Code Playgroud)

您的Precision-Recall图现在如下所示,其中x轴为Recall,y轴为Precision:

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;
Run Code Online (Sandbox Code Playgroud)

这是我得到的图表:

在此输入图像描述

您会注意到,在召回率为0.4到0.8之间,精度会有所增加.这是因为您已设法检索连续的图像链而不触及任何不相关的图像,因此您的精度自然会增加.在最后一张图像之后,它会向下移动,因为在最终击中相关图像之前,您必须检索这么多不相关的图像.

您还会注意到精确度和召回率是反向相关的.因此,如果精度增加,则召回减少.同样,如果精度降低,则召回率会增加.

  • 第一部分是有意义的,因为如果您在开始时没有检索到那么多图像,那么您更有可能在结果中不包含不相关的图像,但同时相关图像的数量相当小.这就是为什么在精度会提高时召回会减少的原因
  • 第二部分也有意义,因为当你不断尝试在数据库中检索更多图像时,你将不可避免地能够检索所有相关的图像,但你很可能会开始包含更多不相关的图像,这会驱动你的精确度下降.

在理想的世界中,如果您N的数据库中有相关图像,您可能希望在N最相似的位置看到所有这些图像.因此,这将使您的精确回忆图形成为一条平坦的水平线y = 1,这意味着您已设法检索所有顶部位置的所有图像,而无需访问任何不相关的图像.不幸的是,这种情况永远不会发生(或至少现在不是......),因为试图找出CBIR的最佳功能仍然是一项持续的调查,而且我见过的图像搜索引擎都没有设法得到这个完善.这仍然是当今存在的最广泛和最未解决的计算机视觉问题之一!


编辑

您检索此代码以计算此帖子的直方图交集.他们有一种计算直方图交集的简洁方法:

在此输入图像描述

n是直方图中的总箱数.您必须使用它来获得良好的结果,但我们可以将其作为代码中的参数.上面的代码假定您有两个矩阵AB其中各列是一个直方图.你会产生一个矩阵,是的a x b,这里a是列数Ab为列的数量b.该矩阵的行和列(i,j)告诉你我之间的相似度列在AbĴ B.在您的情况下,A将是一个单独的列,表示您的查询图像的直方图. B将是10列矩阵,表示每个数据库图像的直方图.因此,我们将1 x 10通过直方图交集获得一系列相似性度量.

因此,我们需要修改您的代码,以便您可以使用imhist每个图像.我们还可以指定一个附加参数,该参数可以为您提供每个直方图将具有的箱数.因此,您的代码将如下所示.我放置的每个新行都会%// 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));
Run Code Online (Sandbox Code Playgroud)

请注意,我已经从网站上复制了代码,但我修改了它,因为只有一个图像A,因此有一些代码是不必要的.

K现在应该是1 x 10直方图交叉点相似性的数组.然后K,您将在我上面编写的代码中使用并分配sims给此变量(即sims = K;),然后运行您的图像.您还需要知道哪些图像是相关图像,并且您必须更改我编写的代码以反映这些图像.

希望这可以帮助!