最近在做关于视觉显著性相关的算法,视觉显著性检测的算法跟大多数依靠准确率(Precision)去衡量算法(例如人脸识别,是否识别正确)优劣有一些区别,它依靠的是PR曲线去判断哪个算法更胜一筹。因为我做完显著性检测算法想要对这个算法进行对比的时候也查到了很多相关P-R曲线的代码,但似乎都不太能运行(可能很大程度上是因为我对它们输入变量和一些matlab的高级功能不了解),并且考虑到PR曲线的原理还是很容易实现的,所以自己动手写了一版我认为蛮简洁易懂的,希望有缘人能搜到也能用的方便。
PR曲线即查准率(Precision)与查全率(Recall),以查全率为坐标x轴,查准率为坐标y轴,从而画出了一条曲线。
P-R图直观地显示出学习器在样本总体上的查全率和查准率。在进行比较时,若一个学习器的P-R曲线完全被另一个学习器的曲线完全“包住”,则我们就可以断言后者的性能优于前者。
查准率和查全率的概念很简单:(拿了张图)
true class我们可以认为是图片显著性的真实情况(ground truth),hypothesized class我们可以认为是我们的算法计算出来的图片显著性情况。那么什么是真正例?假正例?通俗的说saliencymap一般都是二值图(但其实算法计算出来的是一张灰度图,我们通过阈值去将它转化为二值图,而阈值则会一直变化,后面会提及),其中一张图片中有若干个像素点,像素点的值为1则为显著区域(前景),值为0则为背景。我们定义值为1(前景)的为正例,值为0(背景)的为反例;真正例即saliencymap(算法计算出的显著图)为1,ground truth也为1,假正例即saliencymap为1,但ground truth也为0。真假反例也是如此。
我用的是MSRA-1000数据集,将显著性检测计算得出的结果放在saliencymap文件夹里,再将ground truth放在GT文件夹里(为什么会涉及文件夹名称?。。。因为代码里有文件夹路径。。。所以说一下他们的名字)。我们的saliencymap是一张灰度图,我们将它从阈值0~255计算查准率与查全率,每个阈值的查准率与查全率计算数据集里的平均值(即1000张图的查准率,查全率全部计算出来求平均),然后再画一下图plot一下。
Pre=zeros(256,1);
Rec=zeros(256,1);
imgRoot='./GT/';
imgRoot2='./saliencymap/';
imnames=dir([imgRoot '*' 'bmp']);
imnames2=dir([imgRoot2 '*' 'png']);
for i=0:255
MP=zeros(length(imnames),1);
MR=zeros(length(imnames),1);
for l=1:length(imnames)
imname=[imgRoot imnames(l).name];
imname2=[imgRoot2 imnames2(l).name];
%将groundtruth转化为二值灰度的图
GT=imread([imname(1:end-4) '.bmp']);
GT=rgb2gray(GT);
GT=(GT)>0;
k=numel(GT);
GT=reshape(GT,k,1);
%saliencymap
SAP=imread([imname2(1:end-4) '.png']);
SAP=(SAP)>=i;
SAP=reshape(SAP,k,1);
TP=0;
FP=0;
FN=0;
TN=0;
for j=1:k
if SAP(j)==1
if GT(j)==1
TP=TP+1;
else
FP=FP+1;
end
else %SAP(j)==0
if GT(j)==1
FN=FN+1;
else
TN=TN+1;
end
end
end
P=TP/(TP+FP);
MP(l)=P;
R=TP/(TP+FN);
MR(l)=R;
end
sum_MP=0;
sum_MR=0;
for k=1:length(imnames)
sum_MP=sum_MP+MP(k);
sum_MR=sum_MR+MR(k);
end
Pre(i+1)=sum_MP/length(imnames);
Rec(i+1)=sum_MR/length(imnames);
end
x=Rec;
y=Pre;
plot(x,y,'r','LineWidth',0.5);
xlabel('Recall');
ylabel('Precision');
axis([0 1 0 1])
效果图:
嗯。。。第一次写这种,好累。。。明明没写什么内容但是就是写了很久。。。这个代码运算量很大,跑起来比较慢(估计是读文件很耗费时间)。顺便希望我可以坚持学习。。。