运行voc_eval__.m:

path = '/home/user3/CODE/fast-rcnn-loc/data/OPTdevkit2017';
comp_id = 'comp4-17304';
test_set = 'val';
output_dir = '/home/user3/CODE/fast-rcnn-loc/output/loc/opt_2017_val';
rm_res = 0;

res = voc_eval__(path, comp_id, test_set, output_dir, rm_res);

1. voc_eval__.m

先读取VOCopts,便于处理:

function res = voc_eval__(path, comp_id, test_set, output_dir, rm_res)

VOCopts = get_voc_opts(path);
VOCopts.testset = test_set;
VOCopts.detrespath=[VOCopts.resdir 'Main/%s_det_' VOCopts.testset '_%s.txt'];

然后对每个类别,分别进行分析:

for i = 1:length(VOCopts.classes)
  cls = VOCopts.classes{i};
  cls = lower(cls);
  res(i) = voc_eval_loc__(cls, VOCopts, comp_id, output_dir, rm_res);
end

2. voc_eval_loc__.m

准备工作:

function res = voc_eval_loc__(cls, VOCopts, comp_id, output_dir, rm_res)

addpath(fullfile(VOCopts.datadir, 'VOCcode'));
res = VOCevalloc(VOCopts, comp_id, cls);

3. VOCevalloc.m

加载真实结果,测试样本N个:

function res = VOCevalloc(VOCopts,id,cls)

% load test set, gtids: Nx1 cell
[gtids,~]=textread(sprintf(VOCopts.imgsetpath,VOCopts.testset),'%s %d');

% load ground truth objects
tic;
npos=0;
gt(length(gtids))=struct('BB',[],'diff',[],'det',[]);
for i=1:length(gtids)
    % display progress
    if toc>1
        fprintf('%s: pr: load: %d/%d\n',cls,i,length(gtids));
        drawnow;
        tic;
    end
    
    % read annotation
    rec=PASreadrecord(sprintf(VOCopts.annopath,gtids{i}));
    
    % extract objects of class
    clsinds=strmatch(cls,{rec.objects(:).class},'exact');
    gt(i).BB=cat(1,rec.objects(clsinds).bbox)';
    gt(i).diff=[rec.objects(clsinds).difficult];
    gt(i).det=false(length(clsinds),1);
    npos=npos+sum(~gt(i).diff);
end

加载检测结果:

% load results
[ids,confidence,b1,b2,b3,b4]=textread(sprintf(VOCopts.detrespath,id,cls),'%s %f %f %f %f %f');
BB=[b1 b2 b3 b4]';

检测结果排序:

% sort detections by decreasing confidence
[sc,si]=sort(-confidence);
ids=ids(si);
BB=BB(:,si);

首先,了解数据结构:
ids: 所有bndbox所在图像的id,数量nd远超图像数量;
BB: 4行M列;
注意,这里的nd对所有类别都是一样的数值。即每个bndbox对所有类别都有这样一组数据。

3.1 给真实目标分配检测结果

首先来看原始的代码(VOCevaldet.m):

% assign detections to ground truth objects
% nd: 所有bndbox的数量;
% tp: false positive;
% fp: true positive;
nd=length(confidence);
tp=zeros(nd,1);
fp=zeros(nd,1);
tic;

% 对每个bndbox做一次
for d=1:nd
    % display progress
    if toc>1
        fprintf('%s: pr: compute: %d/%d\n',cls,d,nd);
        drawnow;
        tic;
    end
    
    % find ground truth image
    % i 是检测到的bndbox对应的gt集中图像的id,需要验证存在性
    i=strmatch(ids{d},gtids,'exact');
    if isempty(i)
        error('unrecognized image "%s"',ids{d});
    elseif length(i)>1
        error('multiple image "%s"',ids{d});
    end

    % assign detection to ground truth object if any
    % 在检测结果和gt之间匹配
    % bb是检测结果,ids是对应的图像id;gtbb、gtids为对应gt
    bb=BB(:,d);
    ovmax=-inf;
    for j=1:size(gt(i).BB,2)
        bbgt=gt(i).BB(:,j);
        bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))];
        iw=bi(3)-bi(1)+1;
        ih=bi(4)-bi(2)+1;
        if iw>0 & ih>0                
            % compute overlap as area of intersection / area of union
            % ovmax: 与gt的最大重叠IoU
            % jmax: 最大重叠bndbox的对应图象id
            ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+...
               (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-...
               iw*ih;
            ov=iw*ih/ua;
            if ov>ovmax
                ovmax=ov;
                jmax=j;
            end
        end
    end

    % assign detection as true positive/don't care/false positive
    % 重叠大于等于0.5
    if ovmax>=VOCopts.minoverlap
        if ~gt(i).diff(jmax)
            if ~gt(i).det(jmax)
                tp(d)=1;            % true positive
				gt(i).det(jmax)=true;
            else
                fp(d)=1;            % false positive (multiple detection)
            end
        end
    else
        fp(d)=1;                    % false positive
    end
end

大意:
从一个bb出发,和同图像中所有gtbb进行位置对比。
如果IOU不小于0.5,且该gtbb之前没有被其他bb标记过,则对应的tp(d)记为1;
如果gtbb被其他bb标记过,说明有更好的bb和gtbb对应(按照得分排序),则fp(d)记为1;
如果IOU小于0.5,则直接将fp(d)记为1;


之后的代码:

% compute precision/recall
% cumsum 是累积和向量,由此可以得出pr曲线
fp=cumsum(fp);
tp=cumsum(tp);
rec=tp/npos;
prec=tp./(fp+tp);

% compute average precision
% 求mAP
ap=0;
for t=0:0.1:1
    p=max(prec(rec>=t));
    if isempty(p)
        p=0;
    end
    ap=ap+p/11;
end

3.2 实现VOCevalloc的关键部分

需求:
• Correct: correct class and IOU > .5
• Localization: correct class, .1 < IOU < .5
• Similar: class is similar, IOU > .1
• Other: class is wrong, IOU > .1
• Background: IOU < .1 for any object
这五类如果全部划分出来比较麻烦,因为之前代码里给出的相当于只考虑类别正确的bndbox,所以Similar、Other都不好处理。

简化需求:
• A.Correct: correct class and IOU > .5
• B.Localization: correct class, .1 < IOU < .5
• C.Other: left

设计思路:
1.对每个类别计算一个定位误差百分比;
2.并且计算一个正确率百分比;
3.从gtbb出发;
4.注意每个gtbb对应的bb只选择头一个。

由于我们这里代码整体的前提为——只考虑类别正确的,所以伪代码为:

if IOU >= 0.5
	if first% 防止重复计数一个Correct bbgt,这里用gt.det来分辨
		Correct += 1
elif IOU >= 0.1
	if first % 防止重复计数一个Localization bbgt,这里同样用gt.det来分辨
		Localization += 1

关于这里为什么都用gt.det来区分,因为我们考虑的是对bbgt的分类计数,所以一个bbgt只能被计数一次。因此一个bbgt不管被分到A/B哪一个类别,之后如果有其他bb是A/B,都不再参与计数。

修改代码:

% assign detections to ground truth objects
nd=length(confidence);
tic;

res.crct = 0;
res.lclz = 0;
res.ozrs = 0;
for d=1:nd
    % display progress
    if toc>1
        fprintf('%s: loc: compute: %d/%d bndboxes\n',cls,d,nd);
        drawnow;
        tic;
    end
    
    % find ground truth image
    i=strmatch(ids{d},gtids,'exact');
    if isempty(i)
        error('unrecognized image "%s"',ids{d});
    elseif length(i)>1
        error('multiple image "%s"',ids{d});
    end

    % assign detection to ground truth object if any
    bb=BB(:,d);
    ovmax=-inf;
    for j=1:size(gt(i).BB,2)
        bbgt=gt(i).BB(:,j);
        bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))];
        iw=bi(3)-bi(1)+1;
        ih=bi(4)-bi(2)+1;
        if iw>0 & ih>0                
            % compute overlap as area of intersection / area of union
            ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+...
               (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-...
               iw*ih;
            ov=iw*ih/ua;
            if ov>ovmax
                ovmax=ov;
                jmax=j;
            end
        end
    end
	% assign detection as true Correct/ Localization/ Other 
	if ovmax >= 0.1
		if ovmax >= 0.5
			if ~gt(i).det(jmax)
				res.crct = res.crct + 1; 
				gt(i).det(jmax) = true;
			end
		else
			if ~gt(i).det(jmax)
				res.lclz = res.lclz + 1; 
				gt(i).det(jmax) = true;
			end
		end
	end
end

% compute results
res.ozrs = npos - res.crct - res.lclz;
res.npos = npos;
res.ratio = [res.crct/npos, res.lclz/npos, res.ozrs/npos];

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐