├── .gitignore ├── LICENSE ├── README.md ├── VOCcode ├── PASemptyobject.m ├── PASemptyrecord.m ├── PASerrmsg.m ├── PASreadrecord.m ├── PASreadrectxt.m ├── VOCap.m ├── VOCevalaction.m ├── VOCevalcls.m ├── VOCevaldet.m ├── VOCevallayout_pr.m ├── VOCevalseg.m ├── VOChash_init.m ├── VOChash_lookup.m ├── VOCinit.m ├── VOClabelcolormap.m ├── VOCreadrecxml.m ├── VOCreadxml.m ├── VOCwritexml.m └── VOCxml2struct.m ├── create_segmentations_from_detections.m ├── devkit_doc.pdf ├── example_action.m ├── example_action_nobb.m ├── example_classifier.m ├── example_detector.m ├── example_layout.m ├── example_segmenter.m ├── local └── VOC2012 │ └── _dummy ├── results └── VOC2012 │ ├── Action │ └── _dummy │ ├── Layout │ └── _dummy │ ├── Main │ └── _dummy │ └── Segmentation │ └── _dummy ├── viewanno.m └── viewdet.m /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | *~ 3 | 4 | # Dataset directory 5 | VOC20* 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Wei Liu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VOCdevkit 2 | http://host.robots.ox.ac.uk/pascal/VOC/index.html 3 | -------------------------------------------------------------------------------- /VOCcode/PASemptyobject.m: -------------------------------------------------------------------------------- 1 | function object=PASemptyobject 2 | object.label=''; 3 | object.orglabel=''; 4 | object.bbox=[]; 5 | object.polygon=[]; 6 | object.mask=''; 7 | object.class=''; 8 | object.view=''; 9 | object.truncated=false; 10 | object.difficult=false; 11 | return -------------------------------------------------------------------------------- /VOCcode/PASemptyrecord.m: -------------------------------------------------------------------------------- 1 | function record=PASemptyrecord 2 | record.imgname=''; 3 | record.imgsize=[]; 4 | record.database=''; 5 | record.objects=PASemptyobject; 6 | return -------------------------------------------------------------------------------- /VOCcode/PASerrmsg.m: -------------------------------------------------------------------------------- 1 | function PASerrmsg(PASerr,SYSerr) 2 | fprintf('Pascal Error Message: %s\n',PASerr); 3 | fprintf('System Error Message: %s\n',SYSerr); 4 | k=input('Enter K for keyboard, any other key to continue or ^C to quit ...','s'); 5 | if (~isempty(k)), if (lower(k)=='k'), keyboard; end; end; 6 | fprintf('\n'); 7 | return -------------------------------------------------------------------------------- /VOCcode/PASreadrecord.m: -------------------------------------------------------------------------------- 1 | function rec = PASreadrecord(path) 2 | 3 | if length(path)<4 4 | error('unable to determine format: %s',path); 5 | end 6 | 7 | if strcmp(path(end-3:end),'.txt') 8 | rec=PASreadrectxt(path); 9 | else 10 | rec=VOCreadrecxml(path); 11 | end 12 | -------------------------------------------------------------------------------- /VOCcode/PASreadrectxt.m: -------------------------------------------------------------------------------- 1 | function record=PASreadrectxt(filename) 2 | [fd,syserrmsg]=fopen(filename,'rt'); 3 | if (fd==-1), 4 | PASmsg=sprintf('Could not open %s for reading',filename); 5 | PASerrmsg(PASmsg,syserrmsg); 6 | end; 7 | 8 | matchstrs=initstrings; 9 | record=PASemptyrecord; 10 | notEOF=1; 11 | while (notEOF), 12 | line=fgetl(fd); 13 | notEOF=ischar(line); 14 | if (notEOF), 15 | matchnum=match(line,matchstrs); 16 | switch matchnum, 17 | case 1, [imgname]=strread(line,matchstrs(matchnum).str); 18 | record.imgname=char(imgname); 19 | case 2, [x,y,c]=strread(line,matchstrs(matchnum).str); 20 | record.imgsize=[x y c]; 21 | case 3, [database]=strread(line,matchstrs(matchnum).str); 22 | record.database=char(database); 23 | case 4, [obj,lbl,xmin,ymin,xmax,ymax]=strread(line,matchstrs(matchnum).str); 24 | record.objects(obj).label=char(lbl); 25 | record.objects(obj).bbox=[min(xmin,xmax),min(ymin,ymax),max(xmin,xmax),max(ymin,ymax)]; 26 | case 5, tmp=findstr(line,' : '); 27 | [obj,lbl]=strread(line(1:tmp),matchstrs(matchnum).str); 28 | record.objects(obj).label=char(lbl); 29 | record.objects(obj).polygon=sscanf(line(tmp+3:end),'(%d, %d) ')'; 30 | case 6, [obj,lbl,mask]=strread(line,matchstrs(matchnum).str); 31 | record.objects(obj).label=char(lbl); 32 | record.objects(obj).mask=char(mask); 33 | case 7, [obj,lbl,orglbl]=strread(line,matchstrs(matchnum).str); 34 | lbl=char(lbl); 35 | record.objects(obj).label=lbl; 36 | record.objects(obj).orglabel=char(orglbl); 37 | if strcmp(lbl(max(end-8,1):end),'Difficult') 38 | record.objects(obj).difficult=true; 39 | lbl(end-8:end)=[]; 40 | else 41 | record.objects(obj).difficult=false; 42 | end 43 | if strcmp(lbl(max(end-4,1):end),'Trunc') 44 | record.objects(obj).truncated=true; 45 | lbl(end-4:end)=[]; 46 | else 47 | record.objects(obj).truncated=false; 48 | end 49 | t=find(lbl>='A'&lbl<='Z'); 50 | t=t(t>=4); 51 | if ~isempty(t) 52 | record.objects(obj).view=lbl(t(1):end); 53 | lbl(t(1):end)=[]; 54 | else 55 | record.objects(obj).view=''; 56 | end 57 | record.objects(obj).class=lbl(4:end); 58 | 59 | otherwise, %fprintf('Skipping: %s\n',line); 60 | end; 61 | end; 62 | end; 63 | fclose(fd); 64 | return 65 | 66 | function matchnum=match(line,matchstrs) 67 | for i=1:length(matchstrs), 68 | matched(i)=strncmp(line,matchstrs(i).str,matchstrs(i).matchlen); 69 | end; 70 | matchnum=find(matched); 71 | if isempty(matchnum), matchnum=0; end; 72 | if (length(matchnum)~=1), 73 | PASerrmsg('Multiple matches while parsing',''); 74 | end; 75 | return 76 | 77 | function s=initstrings 78 | s(1).matchlen=14; 79 | s(1).str='Image filename : %q'; 80 | 81 | s(2).matchlen=10; 82 | s(2).str='Image size (X x Y x C) : %d x %d x %d'; 83 | 84 | s(3).matchlen=8; 85 | s(3).str='Database : %q'; 86 | 87 | s(4).matchlen=8; 88 | s(4).str='Bounding box for object %d %q (Xmin, Ymin) - (Xmax, Ymax) : (%d, %d) - (%d, %d)'; 89 | 90 | s(5).matchlen=7; 91 | s(5).str='Polygon for object %d %q (X, Y)'; 92 | 93 | s(6).matchlen=5; 94 | s(6).str='Pixel mask for object %d %q : %q'; 95 | 96 | s(7).matchlen=8; 97 | s(7).str='Original label for object %d %q : %q'; 98 | 99 | return -------------------------------------------------------------------------------- /VOCcode/VOCap.m: -------------------------------------------------------------------------------- 1 | function ap = VOCap(rec,prec) 2 | 3 | mrec=[0 ; rec ; 1]; 4 | mpre=[0 ; prec ; 0]; 5 | for i=numel(mpre)-1:-1:1 6 | mpre(i)=max(mpre(i),mpre(i+1)); 7 | end 8 | i=find(mrec(2:end)~=mrec(1:end-1))+1; 9 | ap=sum((mrec(i)-mrec(i-1)).*mpre(i)); 10 | 11 | -------------------------------------------------------------------------------- /VOCcode/VOCevalaction.m: -------------------------------------------------------------------------------- 1 | function [rec,prec,ap] = VOCevalaction(VOCopts,id,cls,draw) 2 | 3 | % load test set 4 | [gtimg,gtobj,gt]=textread(sprintf(VOCopts.action.clsimgsetpath,cls,VOCopts.testset),'%s %d %d'); 5 | 6 | % hash image/object ids 7 | gtid=cell(numel(gtimg),1); 8 | for i=1:numel(gtimg); 9 | gtid{i}=sprintf('%s/%d',gtimg{i},gtobj(i)); 10 | end 11 | hash=VOChash_init(gtid); 12 | 13 | % load results 14 | [img,obj,confidence]=textread(sprintf(VOCopts.action.respath,id,cls),'%s %d %f'); 15 | 16 | % map results to ground truth objects 17 | out=ones(size(gt))*-inf; 18 | tic; 19 | for i=1:length(img) 20 | % display progress 21 | if toc>1 22 | fprintf('%s: pr: %d/%d\n',cls,i,length(img)); 23 | drawnow; 24 | tic; 25 | end 26 | 27 | % find ground truth object 28 | k=sprintf('%s/%d',img{i},obj(i)); 29 | j=VOChash_lookup(hash,k); 30 | if isempty(j) 31 | error('unrecognized object "%s"',k); 32 | elseif length(j)>1 33 | error('multiple image "%s"',k); 34 | else 35 | out(j)=confidence(i); 36 | end 37 | end 38 | 39 | % compute precision/recall 40 | 41 | [so,si]=sort(-out); 42 | tp=gt(si)>0; 43 | fp=gt(si)<0; 44 | 45 | fp=cumsum(fp); 46 | tp=cumsum(tp); 47 | rec=tp/sum(gt>0); 48 | prec=tp./(fp+tp); 49 | 50 | ap=VOCap(rec,prec); 51 | 52 | if draw 53 | % plot precision/recall 54 | plot(rec,prec,'-'); 55 | grid; 56 | xlabel 'recall' 57 | ylabel 'precision' 58 | title(sprintf('class: %s, subset: %s, AP = %.3f',cls,VOCopts.testset,ap)); 59 | end 60 | -------------------------------------------------------------------------------- /VOCcode/VOCevalcls.m: -------------------------------------------------------------------------------- 1 | function [rec,prec,ap] = VOCevalcls(VOCopts,id,cls,draw) 2 | 3 | % load test set 4 | [gtids,gt]=textread(sprintf(VOCopts.clsimgsetpath,cls,VOCopts.testset),'%s %d'); 5 | 6 | % hash image ids 7 | hash=VOChash_init(gtids); 8 | 9 | % load results 10 | [ids,confidence]=textread(sprintf(VOCopts.clsrespath,id,cls),'%s %f'); 11 | 12 | % map results to ground truth images 13 | out=ones(size(gt))*-inf; 14 | tic; 15 | for i=1:length(ids) 16 | % display progress 17 | if toc>1 18 | fprintf('%s: pr: %d/%d\n',cls,i,length(ids)); 19 | drawnow; 20 | tic; 21 | end 22 | 23 | % find ground truth image 24 | j=VOChash_lookup(hash,ids{i}); 25 | if isempty(j) 26 | error('unrecognized image "%s"',ids{i}); 27 | elseif length(j)>1 28 | error('multiple image "%s"',ids{i}); 29 | else 30 | out(j)=confidence(i); 31 | end 32 | end 33 | 34 | % compute precision/recall 35 | 36 | [so,si]=sort(-out); 37 | tp=gt(si)>0; 38 | fp=gt(si)<0; 39 | 40 | fp=cumsum(fp); 41 | tp=cumsum(tp); 42 | rec=tp/sum(gt>0); 43 | prec=tp./(fp+tp); 44 | 45 | ap=VOCap(rec,prec); 46 | 47 | if draw 48 | % plot precision/recall 49 | plot(rec,prec,'-'); 50 | grid; 51 | xlabel 'recall' 52 | ylabel 'precision' 53 | title(sprintf('class: %s, subset: %s, AP = %.3f',cls,VOCopts.testset,ap)); 54 | end 55 | -------------------------------------------------------------------------------- /VOCcode/VOCevaldet.m: -------------------------------------------------------------------------------- 1 | function [rec,prec,ap] = VOCevaldet(VOCopts,id,cls,draw) 2 | 3 | % load test set 4 | 5 | cp=sprintf(VOCopts.annocachepath,VOCopts.testset); 6 | if exist(cp,'file') 7 | fprintf('%s: pr: loading ground truth\n',cls); 8 | load(cp,'gtids','recs'); 9 | else 10 | [gtids,t]=textread(sprintf(VOCopts.imgsetpath,VOCopts.testset),'%s %d'); 11 | for i=1:length(gtids) 12 | % display progress 13 | if toc>1 14 | fprintf('%s: pr: load: %d/%d\n',cls,i,length(gtids)); 15 | drawnow; 16 | tic; 17 | end 18 | 19 | % read annotation 20 | recs(i)=PASreadrecord(sprintf(VOCopts.annopath,gtids{i})); 21 | end 22 | save(cp,'gtids','recs'); 23 | end 24 | 25 | fprintf('%s: pr: evaluating detections\n',cls); 26 | 27 | % hash image ids 28 | hash=VOChash_init(gtids); 29 | 30 | % extract ground truth objects 31 | 32 | npos=0; 33 | gt(length(gtids))=struct('BB',[],'diff',[],'det',[]); 34 | for i=1:length(gtids) 35 | % extract objects of class 36 | clsinds=strmatch(cls,{recs(i).objects(:).class},'exact'); 37 | gt(i).BB=cat(1,recs(i).objects(clsinds).bbox)'; 38 | gt(i).diff=[recs(i).objects(clsinds).difficult]; 39 | gt(i).det=false(length(clsinds),1); 40 | npos=npos+sum(~gt(i).diff); 41 | end 42 | 43 | % load results 44 | [ids,confidence,b1,b2,b3,b4]=textread(sprintf(VOCopts.detrespath,id,cls),'%s %f %f %f %f %f'); 45 | BB=[b1 b2 b3 b4]'; 46 | 47 | % sort detections by decreasing confidence 48 | [sc,si]=sort(-confidence); 49 | ids=ids(si); 50 | BB=BB(:,si); 51 | 52 | % assign detections to ground truth objects 53 | nd=length(confidence); 54 | tp=zeros(nd,1); 55 | fp=zeros(nd,1); 56 | tic; 57 | for d=1:nd 58 | % display progress 59 | if toc>1 60 | fprintf('%s: pr: compute: %d/%d\n',cls,d,nd); 61 | drawnow; 62 | tic; 63 | end 64 | 65 | % find ground truth image 66 | i=VOChash_lookup(hash,ids{d}); 67 | if isempty(i) 68 | error('unrecognized image "%s"',ids{d}); 69 | elseif length(i)>1 70 | error('multiple image "%s"',ids{d}); 71 | end 72 | 73 | % assign detection to ground truth object if any 74 | bb=BB(:,d); 75 | ovmax=-inf; 76 | for j=1:size(gt(i).BB,2) 77 | bbgt=gt(i).BB(:,j); 78 | bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))]; 79 | iw=bi(3)-bi(1)+1; 80 | ih=bi(4)-bi(2)+1; 81 | if iw>0 & ih>0 82 | % compute overlap as area of intersection / area of union 83 | ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+... 84 | (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-... 85 | iw*ih; 86 | ov=iw*ih/ua; 87 | if ov>ovmax 88 | ovmax=ov; 89 | jmax=j; 90 | end 91 | end 92 | end 93 | % assign detection as true positive/don't care/false positive 94 | if ovmax>=VOCopts.minoverlap 95 | if ~gt(i).diff(jmax) 96 | if ~gt(i).det(jmax) 97 | tp(d)=1; % true positive 98 | gt(i).det(jmax)=true; 99 | else 100 | fp(d)=1; % false positive (multiple detection) 101 | end 102 | end 103 | else 104 | fp(d)=1; % false positive 105 | end 106 | end 107 | 108 | % compute precision/recall 109 | fp=cumsum(fp); 110 | tp=cumsum(tp); 111 | rec=tp/npos; 112 | prec=tp./(fp+tp); 113 | 114 | ap=VOCap(rec,prec); 115 | 116 | if draw 117 | % plot precision/recall 118 | plot(rec,prec,'-'); 119 | grid; 120 | xlabel 'recall' 121 | ylabel 'precision' 122 | title(sprintf('class: %s, subset: %s, AP = %.3f',cls,VOCopts.testset,ap)); 123 | end 124 | -------------------------------------------------------------------------------- /VOCcode/VOCevallayout_pr.m: -------------------------------------------------------------------------------- 1 | function [rec,prec,ap] = VOCevallayout_pr(VOCopts,id,draw) 2 | 3 | % load test set 4 | [imgids,objids]=textread(sprintf(VOCopts.layout.imgsetpath,VOCopts.testset),'%s %d'); 5 | 6 | % hash image ids 7 | hash=VOChash_init(imgids); 8 | 9 | % load ground truth objects 10 | 11 | tic; 12 | n=0; 13 | np=zeros(VOCopts.nparts,1); 14 | for i=1:length(imgids) 15 | % display progress 16 | if toc>1 17 | fprintf('layout pr: load %d/%d\n',i,length(imgids)); 18 | drawnow; 19 | tic; 20 | end 21 | 22 | % read annotation 23 | r=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 24 | 25 | % extract object 26 | n=n+1; 27 | o=r.objects(objids(i)); 28 | gt(n)=o; 29 | 30 | for j=1:numel(o.part) 31 | c=strmatch(o.part(j).class,VOCopts.parts,'exact'); 32 | np(c)=np(c)+1; 33 | end 34 | end 35 | 36 | % load results 37 | 38 | fprintf('layout pr: loading results\n'); 39 | xml=VOCreadxml(sprintf(VOCopts.layout.respath,id)); 40 | 41 | % test detections by decreasing confidence 42 | 43 | [t,si]=sort(-str2double({xml.results.layout.confidence})); 44 | nd=numel(si); 45 | 46 | det=false(n,1); 47 | 48 | ptp=[]; 49 | pfp=[]; 50 | pc=[]; 51 | 52 | for di=1:nd 53 | 54 | % display progress 55 | if toc>1 56 | fprintf('layout pr: compute: %d/%d\n',di,nd); 57 | drawnow; 58 | tic; 59 | end 60 | 61 | % match result to ground truth object 62 | d=xml.results.layout(si(di)); 63 | ii=VOChash_lookup(hash,d.image); 64 | oi=ii(objids(ii)==str2num(d.object)); 65 | 66 | if isempty(oi) 67 | warning('unrecognized layout: image %s, object %s',d.image,d.object); 68 | continue 69 | end 70 | 71 | if det(oi) 72 | warning('duplicate layout: image %s, object %s',d.image,d.object); 73 | continue 74 | end 75 | det(oi)=true; 76 | o=gt(oi); 77 | 78 | % assign parts to ground truth parts 79 | 80 | gtd=false(numel(o.part),1); 81 | da=zeros(numel(d.part),1); 82 | dc=zeros(numel(d.part),1); 83 | for i=1:numel(d.part) 84 | dc(i)=strmatch(d.part(i).class,VOCopts.parts,'exact'); 85 | bb=str2double({d.part(i).bndbox.xmin d.part(i).bndbox.ymin ... 86 | d.part(i).bndbox.xmax d.part(i).bndbox.ymax}); 87 | 88 | ovmax=-inf; 89 | for j=1:numel(o.part) 90 | if strcmp(d.part(i).class,o.part(j).class) 91 | bbgt=o.part(j).bbox; 92 | bi=[max(bb(1),bbgt(1)) 93 | max(bb(2),bbgt(2)) 94 | min(bb(3),bbgt(3)) 95 | min(bb(4),bbgt(4))]; 96 | iw=bi(3)-bi(1)+1; 97 | ih=bi(4)-bi(2)+1; 98 | if iw>0 & ih>0 99 | % compute overlap as area of intersection / area of union 100 | ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+... 101 | (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-... 102 | iw*ih; 103 | ov=iw*ih/ua; 104 | if ov>ovmax 105 | ovmax=ov; 106 | jmax=j; 107 | end 108 | end 109 | end 110 | end 111 | if ovmax>=VOCopts.minoverlap && ~gtd(jmax) 112 | da(i)=jmax; 113 | gtd(jmax)=true; 114 | end 115 | end 116 | 117 | ptp=[ptp ; da~=0]; 118 | pfp=[pfp ; da==0]; 119 | pc=[pc ; dc]; 120 | end 121 | 122 | % evaluate each part type 123 | 124 | for i=1:VOCopts.nparts 125 | 126 | % compute precision/recall 127 | 128 | fpi=cumsum(pfp(pc==i)); 129 | tpi=cumsum(ptp(pc==i)); 130 | v=tpi+fpi>0; 131 | rec{i}=tpi(v)/np(i); 132 | prec{i}=tpi(v)./(fpi(v)+tpi(v)); 133 | 134 | ap{i}=VOCap(rec{i},prec{i}); 135 | 136 | if draw 137 | % plot precision/recall 138 | subplot(VOCopts.nparts,1,i); 139 | plot(rec{i},prec{i},'-'); 140 | grid; 141 | xlabel 'recall' 142 | ylabel 'precision' 143 | title(sprintf('subset: %s, part: %s, AP = %.3f',VOCopts.testset,VOCopts.parts{i},ap{i})); 144 | end 145 | end 146 | -------------------------------------------------------------------------------- /VOCcode/VOCevalseg.m: -------------------------------------------------------------------------------- 1 | %VOCEVALSEG Evaluates a set of segmentation results. 2 | % VOCEVALSEG(VOCopts,ID); prints out the per class and overall 3 | % segmentation accuracies. Accuracies are given using the intersection/union 4 | % metric: 5 | % true positives / (true positives + false positives + false negatives) 6 | % 7 | % [ACCURACIES,AVACC,CONF] = VOCEVALSEG(VOCopts,ID) returns the per class 8 | % percentage ACCURACIES, the average accuracy AVACC and the confusion 9 | % matrix CONF. 10 | % 11 | % [ACCURACIES,AVACC,CONF,RAWCOUNTS] = VOCEVALSEG(VOCopts,ID) also returns 12 | % the unnormalised confusion matrix, which contains raw pixel counts. 13 | function [accuracies,avacc,conf,rawcounts] = VOCevalseg(VOCopts,id) 14 | 15 | % image test set 16 | [gtids,t]=textread(sprintf(VOCopts.seg.imgsetpath,VOCopts.testset),'%s %d'); 17 | 18 | % number of labels = number of classes plus one for the background 19 | num = VOCopts.nclasses+1; 20 | confcounts = zeros(num); 21 | count=0; 22 | tic; 23 | for i=1:length(gtids) 24 | % display progress 25 | if toc>1 26 | fprintf('test confusion: %d/%d\n',i,length(gtids)); 27 | drawnow; 28 | tic; 29 | end 30 | 31 | imname = gtids{i}; 32 | 33 | % ground truth label file 34 | gtfile = sprintf(VOCopts.seg.clsimgpath,imname); 35 | [gtim,map] = imread(gtfile); 36 | gtim = double(gtim); 37 | 38 | % results file 39 | resfile = sprintf(VOCopts.seg.clsrespath,id,VOCopts.testset,imname); 40 | [resim,map] = imread(resfile); 41 | resim = double(resim); 42 | 43 | % Check validity of results image 44 | maxlabel = max(resim(:)); 45 | if (maxlabel>VOCopts.nclasses), 46 | error('Results image ''%s'' has out of range value %d (the value should be <= %d)',imname,maxlabel,VOCopts.nclasses); 47 | end 48 | 49 | szgtim = size(gtim); szresim = size(resim); 50 | if any(szgtim~=szresim) 51 | error('Results image ''%s'' is the wrong size, was %d x %d, should be %d x %d.',imname,szresim(1),szresim(2),szgtim(1),szgtim(2)); 52 | end 53 | 54 | %pixel locations to include in computation 55 | locs = gtim<255; 56 | 57 | % joint histogram 58 | sumim = 1+gtim+resim*num; 59 | hs = histc(sumim(locs),1:num*num); 60 | count = count + numel(find(locs)); 61 | confcounts(:) = confcounts(:) + hs(:); 62 | end 63 | 64 | % confusion matrix - first index is true label, second is inferred label 65 | %conf = zeros(num); 66 | conf = 100*confcounts./repmat(1E-20+sum(confcounts,2),[1 size(confcounts,2)]); 67 | rawcounts = confcounts; 68 | 69 | % Percentage correct labels measure is no longer being used. Uncomment if 70 | % you wish to see it anyway 71 | %overall_acc = 100*sum(diag(confcounts)) / sum(confcounts(:)); 72 | %fprintf('Percentage of pixels correctly labelled overall: %6.3f%%\n',overall_acc); 73 | 74 | accuracies = zeros(VOCopts.nclasses,1); 75 | fprintf('Accuracy for each class (intersection/union measure)\n'); 76 | for j=1:num 77 | 78 | gtj=sum(confcounts(j,:)); 79 | resj=sum(confcounts(:,j)); 80 | gtjresj=confcounts(j,j); 81 | % The accuracy is: true positive / (true positive + false positive + false negative) 82 | % which is equivalent to the following percentage: 83 | accuracies(j)=100*gtjresj/(gtj+resj-gtjresj); 84 | 85 | clname = 'background'; 86 | if (j>1), clname = VOCopts.classes{j-1};end; 87 | fprintf(' %14s: %6.3f%%\n',clname,accuracies(j)); 88 | end 89 | accuracies = accuracies(1:end); 90 | avacc = mean(accuracies); 91 | fprintf('-------------------------\n'); 92 | fprintf('Average accuracy: %6.3f%%\n',avacc); 93 | -------------------------------------------------------------------------------- /VOCcode/VOChash_init.m: -------------------------------------------------------------------------------- 1 | function hash = VOChash_init(strs) 2 | 3 | hsize=4999; 4 | hash.key=cell(hsize,1); 5 | hash.val=cell(hsize,1); 6 | 7 | for i=1:numel(strs) 8 | s=strs{i}; 9 | h=mod(str2double(s([3:4 6:11 13:end])),hsize)+1; 10 | j=numel(hash.key{h})+1; 11 | hash.key{h}{j}=strs{i}; 12 | hash.val{h}(j)=i; 13 | end 14 | 15 | -------------------------------------------------------------------------------- /VOCcode/VOChash_lookup.m: -------------------------------------------------------------------------------- 1 | function ind = VOChash_lookup(hash,s) 2 | 3 | hsize=numel(hash.key); 4 | h=mod(str2double(s([3:4 6:11 13:end])),hsize)+1; 5 | ind=hash.val{h}(strmatch(s,hash.key{h},'exact')); 6 | -------------------------------------------------------------------------------- /VOCcode/VOCinit.m: -------------------------------------------------------------------------------- 1 | clear VOCopts 2 | 3 | % dataset 4 | % 5 | % Note for experienced users: the VOC2008-11 test sets are subsets 6 | % of the VOC2012 test set. You don't need to do anything special 7 | % to submit results for VOC2008-11. 8 | 9 | VOCopts.dataset='VOC2012'; 10 | 11 | % get devkit directory with forward slashes 12 | devkitroot=strrep(fileparts(fileparts(mfilename('fullpath'))),'\','/'); 13 | 14 | % change this path to point to your copy of the PASCAL VOC data 15 | VOCopts.datadir=[devkitroot '/']; 16 | 17 | % change this path to a writable directory for your results 18 | VOCopts.resdir=[devkitroot '/results/' VOCopts.dataset '/']; 19 | 20 | % change this path to a writable local directory for the example code 21 | VOCopts.localdir=[devkitroot '/local/' VOCopts.dataset '/']; 22 | 23 | % initialize the training set 24 | 25 | VOCopts.trainset='train'; % use train for development 26 | % VOCopts.trainset='trainval'; % use train+val for final challenge 27 | 28 | % initialize the test set 29 | 30 | VOCopts.testset='val'; % use validation data for development test set 31 | % VOCopts.testset='test'; % use test set for final challenge 32 | 33 | % initialize main challenge paths 34 | 35 | VOCopts.annopath=[VOCopts.datadir VOCopts.dataset '/Annotations/%s.xml']; 36 | VOCopts.imgpath=[VOCopts.datadir VOCopts.dataset '/JPEGImages/%s.jpg']; 37 | VOCopts.imgsetpath=[VOCopts.datadir VOCopts.dataset '/ImageSets/Main/%s.txt']; 38 | VOCopts.clsimgsetpath=[VOCopts.datadir VOCopts.dataset '/ImageSets/Main/%s_%s.txt']; 39 | VOCopts.clsrespath=[VOCopts.resdir 'Main/%s_cls_' VOCopts.testset '_%s.txt']; 40 | VOCopts.detrespath=[VOCopts.resdir 'Main/%s_det_' VOCopts.testset '_%s.txt']; 41 | 42 | % initialize segmentation task paths 43 | 44 | VOCopts.seg.clsimgpath=[VOCopts.datadir VOCopts.dataset '/SegmentationClass/%s.png']; 45 | VOCopts.seg.instimgpath=[VOCopts.datadir VOCopts.dataset '/SegmentationObject/%s.png']; 46 | 47 | VOCopts.seg.imgsetpath=[VOCopts.datadir VOCopts.dataset '/ImageSets/Segmentation/%s.txt']; 48 | 49 | VOCopts.seg.clsresdir=[VOCopts.resdir 'Segmentation/%s_%s_cls']; 50 | VOCopts.seg.instresdir=[VOCopts.resdir 'Segmentation/%s_%s_inst']; 51 | VOCopts.seg.clsrespath=[VOCopts.seg.clsresdir '/%s.png']; 52 | VOCopts.seg.instrespath=[VOCopts.seg.instresdir '/%s.png']; 53 | 54 | % initialize layout task paths 55 | 56 | VOCopts.layout.imgsetpath=[VOCopts.datadir VOCopts.dataset '/ImageSets/Layout/%s.txt']; 57 | VOCopts.layout.respath=[VOCopts.resdir 'Layout/%s_layout_' VOCopts.testset '.xml']; 58 | 59 | % initialize action task paths 60 | 61 | VOCopts.action.imgsetpath=[VOCopts.datadir VOCopts.dataset '/ImageSets/Action/%s.txt']; 62 | VOCopts.action.clsimgsetpath=[VOCopts.datadir VOCopts.dataset '/ImageSets/Action/%s_%s.txt']; 63 | VOCopts.action.respath=[VOCopts.resdir 'Action/%s_action_' VOCopts.testset '_%s.txt']; 64 | 65 | % initialize the VOC challenge options 66 | 67 | % classes 68 | 69 | VOCopts.classes={... 70 | 'aeroplane' 71 | 'bicycle' 72 | 'bird' 73 | 'boat' 74 | 'bottle' 75 | 'bus' 76 | 'car' 77 | 'cat' 78 | 'chair' 79 | 'cow' 80 | 'diningtable' 81 | 'dog' 82 | 'horse' 83 | 'motorbike' 84 | 'person' 85 | 'pottedplant' 86 | 'sheep' 87 | 'sofa' 88 | 'train' 89 | 'tvmonitor'}; 90 | 91 | VOCopts.nclasses=length(VOCopts.classes); 92 | 93 | % poses 94 | 95 | VOCopts.poses={... 96 | 'Unspecified' 97 | 'Left' 98 | 'Right' 99 | 'Frontal' 100 | 'Rear'}; 101 | 102 | VOCopts.nposes=length(VOCopts.poses); 103 | 104 | % layout parts 105 | 106 | VOCopts.parts={... 107 | 'head' 108 | 'hand' 109 | 'foot'}; 110 | 111 | VOCopts.nparts=length(VOCopts.parts); 112 | 113 | VOCopts.maxparts=[1 2 2]; % max of each of above parts 114 | 115 | % actions 116 | 117 | VOCopts.actions={... 118 | 'other' % skip this when training classifiers 119 | 'jumping' 120 | 'phoning' 121 | 'playinginstrument' 122 | 'reading' 123 | 'ridingbike' 124 | 'ridinghorse' 125 | 'running' 126 | 'takingphoto' 127 | 'usingcomputer' 128 | 'walking'}; 129 | 130 | VOCopts.nactions=length(VOCopts.actions); 131 | 132 | % overlap threshold 133 | 134 | VOCopts.minoverlap=0.5; 135 | 136 | % annotation cache for evaluation 137 | 138 | VOCopts.annocachepath=[VOCopts.localdir '%s_anno.mat']; 139 | 140 | % options for example implementations 141 | 142 | VOCopts.exfdpath=[VOCopts.localdir '%s_fd.mat']; 143 | -------------------------------------------------------------------------------- /VOCcode/VOClabelcolormap.m: -------------------------------------------------------------------------------- 1 | % VOCLABELCOLORMAP Creates a label color map such that adjacent indices have different 2 | % colors. Useful for reading and writing index images which contain large indices, 3 | % by encoding them as RGB images. 4 | % 5 | % CMAP = VOCLABELCOLORMAP(N) creates a label color map with N entries. 6 | function cmap = labelcolormap(N) 7 | 8 | if nargin==0 9 | N=256 10 | end 11 | cmap = zeros(N,3); 12 | for i=1:N 13 | id = i-1; r=0;g=0;b=0; 14 | for j=0:7 15 | r = bitor(r, bitshift(bitget(id,1),7 - j)); 16 | g = bitor(g, bitshift(bitget(id,2),7 - j)); 17 | b = bitor(b, bitshift(bitget(id,3),7 - j)); 18 | id = bitshift(id,-3); 19 | end 20 | cmap(i,1)=r; cmap(i,2)=g; cmap(i,3)=b; 21 | end 22 | cmap = cmap / 255; 23 | -------------------------------------------------------------------------------- /VOCcode/VOCreadrecxml.m: -------------------------------------------------------------------------------- 1 | function rec = VOCreadrecxml(path) 2 | 3 | x=VOCreadxml(path); 4 | x=x.annotation; 5 | 6 | rec.folder=x.folder; 7 | rec.filename=x.filename; 8 | rec.source.database=x.source.database; 9 | rec.source.annotation=x.source.annotation; 10 | rec.source.image=x.source.image; 11 | 12 | rec.size.width=str2double(x.size.width); 13 | rec.size.height=str2double(x.size.height); 14 | rec.size.depth=str2double(x.size.depth); 15 | 16 | rec.segmented=strcmp(x.segmented,'1'); 17 | 18 | rec.imgname=[x.folder '/JPEGImages/' x.filename]; 19 | rec.imgsize=str2double({x.size.width x.size.height x.size.depth}); 20 | rec.database=rec.source.database; 21 | 22 | for i=1:length(x.object) 23 | rec.objects(i)=xmlobjtopas(x.object(i)); 24 | end 25 | 26 | function p = xmlobjtopas(o) 27 | 28 | p.class=o.name; 29 | 30 | if isfield(o,'pose') 31 | if strcmp(o.pose,'Unspecified') 32 | p.view=''; 33 | else 34 | p.view=o.pose; 35 | end 36 | else 37 | p.view=''; 38 | end 39 | 40 | if isfield(o,'truncated') 41 | p.truncated=strcmp(o.truncated,'1'); 42 | else 43 | p.truncated=false; 44 | end 45 | 46 | if isfield(o,'occluded') 47 | p.occluded=strcmp(o.occluded,'1'); 48 | else 49 | p.occluded=false; 50 | end 51 | 52 | if isfield(o,'difficult') 53 | p.difficult=strcmp(o.difficult,'1'); 54 | else 55 | p.difficult=false; 56 | end 57 | 58 | p.label=['PAS' p.class p.view]; 59 | if p.truncated 60 | p.label=[p.label 'Trunc']; 61 | end 62 | if p.occluded 63 | p.label=[p.label 'Occ']; 64 | end 65 | if p.difficult 66 | p.label=[p.label 'Diff']; 67 | end 68 | 69 | p.orglabel=p.label; 70 | 71 | p.bbox=str2double({o.bndbox.xmin o.bndbox.ymin o.bndbox.xmax o.bndbox.ymax}); 72 | 73 | p.bndbox.xmin=str2double(o.bndbox.xmin); 74 | p.bndbox.ymin=str2double(o.bndbox.ymin); 75 | p.bndbox.xmax=str2double(o.bndbox.xmax); 76 | p.bndbox.ymax=str2double(o.bndbox.ymax); 77 | 78 | if isfield(o,'polygon') 79 | warning('polygon unimplemented'); 80 | p.polygon=[]; 81 | else 82 | p.polygon=[]; 83 | end 84 | 85 | if isfield(o,'mask') 86 | warning('mask unimplemented'); 87 | p.mask=[]; 88 | else 89 | p.mask=[]; 90 | end 91 | 92 | if isfield(o,'part')&&~isempty(o.part) 93 | p.hasparts=true; 94 | for i=1:length(o.part) 95 | p.part(i)=xmlobjtopas(o.part(i)); 96 | end 97 | else 98 | p.hasparts=false; 99 | p.part=[]; 100 | end 101 | 102 | if isfield(o,'point') 103 | p.haspoint=true; 104 | p.point.x=str2double(o.point.x); 105 | p.point.y=str2double(o.point.y); 106 | else 107 | p.point=[]; 108 | end 109 | 110 | if isfield(o,'actions') 111 | p.hasactions=true; 112 | fn=fieldnames(o.actions); 113 | for i=1:numel(fn) 114 | p.actions.(fn{i})=strcmp(o.actions.(fn{i}),'1'); 115 | end 116 | else 117 | p.hasactions=false; 118 | p.actions=[]; 119 | end 120 | -------------------------------------------------------------------------------- /VOCcode/VOCreadxml.m: -------------------------------------------------------------------------------- 1 | function rec = VOCreadxml(path) 2 | 3 | if length(path)>5&&strcmp(path(1:5),'http:') 4 | xml=urlread(path)'; 5 | else 6 | f=fopen(path,'r'); 7 | xml=fread(f,'*char')'; 8 | fclose(f); 9 | end 10 | rec=VOCxml2struct(xml); 11 | -------------------------------------------------------------------------------- /VOCcode/VOCwritexml.m: -------------------------------------------------------------------------------- 1 | function VOCwritexml(rec, path) 2 | 3 | fid=fopen(path,'w'); 4 | writexml(fid,rec,0); 5 | fclose(fid); 6 | 7 | function xml = writexml(fid,rec,depth) 8 | 9 | fn=fieldnames(rec); 10 | for i=1:length(fn) 11 | f=rec.(fn{i}); 12 | if ~isempty(f) 13 | if isstruct(f) 14 | for j=1:length(f) 15 | fprintf(fid,'%s',repmat(char(9),1,depth)); 16 | fprintf(fid,'<%s>\n',fn{i}); 17 | writexml(fid,rec.(fn{i})(j),depth+1); 18 | fprintf(fid,'%s',repmat(char(9),1,depth)); 19 | fprintf(fid,'\n',fn{i}); 20 | end 21 | else 22 | if ~iscell(f) 23 | f={f}; 24 | end 25 | for j=1:length(f) 26 | fprintf(fid,'%s',repmat(char(9),1,depth)); 27 | fprintf(fid,'<%s>',fn{i}); 28 | if ischar(f{j}) 29 | fprintf(fid,'%s',f{j}); 30 | elseif isnumeric(f{j})&&numel(f{j})==1 31 | fprintf(fid,'%s',num2str(f{j})); 32 | else 33 | error('unsupported type'); 34 | end 35 | fprintf(fid,'\n',fn{i}); 36 | end 37 | end 38 | end 39 | end 40 | 41 | -------------------------------------------------------------------------------- /VOCcode/VOCxml2struct.m: -------------------------------------------------------------------------------- 1 | function res = VOCxml2struct(xml) 2 | 3 | xml(xml==9|xml==10|xml==13)=[]; 4 | 5 | [res,xml]=parse(xml,1,[]); 6 | 7 | function [res,ind]=parse(xml,ind,parent) 8 | 9 | res=[]; 10 | if ~isempty(parent)&&xml(ind)~='<' 11 | i=findchar(xml,ind,'<'); 12 | res=trim(xml(ind:i-1)); 13 | ind=i; 14 | [tag,ind]=gettag(xml,i); 15 | if ~strcmp(tag,['/' parent]) 16 | error('<%s> closed with <%s>',parent,tag); 17 | end 18 | else 19 | while ind<=length(xml) 20 | [tag,ind]=gettag(xml,ind); 21 | if strcmp(tag,['/' parent]) 22 | return 23 | else 24 | [sub,ind]=parse(xml,ind,tag); 25 | if isstruct(sub) 26 | if isfield(res,tag) 27 | n=length(res.(tag)); 28 | fn=fieldnames(sub); 29 | for f=1:length(fn) 30 | res.(tag)(n+1).(fn{f})=sub.(fn{f}); 31 | end 32 | else 33 | res.(tag)=sub; 34 | end 35 | else 36 | if isfield(res,tag) 37 | if ~iscell(res.(tag)) 38 | res.(tag)={res.(tag)}; 39 | end 40 | res.(tag){end+1}=sub; 41 | else 42 | res.(tag)=sub; 43 | end 44 | end 45 | end 46 | end 47 | end 48 | 49 | function i = findchar(str,ind,chr) 50 | 51 | i=[]; 52 | while ind<=length(str) 53 | if str(ind)==chr 54 | i=ind; 55 | break 56 | else 57 | ind=ind+1; 58 | end 59 | end 60 | 61 | function [tag,ind]=gettag(xml,ind) 62 | 63 | if ind>length(xml) 64 | tag=[]; 65 | elseif xml(ind)=='<' 66 | i=findchar(xml,ind,'>'); 67 | if isempty(i) 68 | error('incomplete tag'); 69 | end 70 | tag=xml(ind+1:i-1); 71 | ind=i+1; 72 | else 73 | error('expected tag'); 74 | end 75 | 76 | function s = trim(s) 77 | 78 | for i=1:numel(s) 79 | if ~isspace(s(i)) 80 | s=s(i:end); 81 | break 82 | end 83 | end 84 | for i=numel(s):-1:1 85 | if ~isspace(s(i)) 86 | s=s(1:i); 87 | break 88 | end 89 | end 90 | 91 | -------------------------------------------------------------------------------- /create_segmentations_from_detections.m: -------------------------------------------------------------------------------- 1 | % Creates segmentation results from detection results. 2 | % CREATE_SEGMENTATIONS_FROM_DETECTIONS(ID) creates segmentations from 3 | % the detection results with identifier ID e.g. 'comp3'. All detections 4 | % will be used, no matter what their confidence level. Detections are 5 | % ranked by increasing confidence, so more confident detections occlude 6 | % less confident detections. 7 | % 8 | % CREATE_SEGMENTATIONS_FROM_DETECTIONS(ID, CONFIDENCE) as above, but only 9 | % detections above the specified confidence will be used. 10 | function create_segmentations_from_detections(id,confidence) 11 | 12 | if nargin<2 13 | confidence = -inf; 14 | end 15 | 16 | % change this path if you install the VOC code elsewhere 17 | addpath([cd '/VOCcode']); 18 | 19 | % initialize VOC options 20 | VOCinit; 21 | 22 | % load detection results 23 | 24 | n=0; 25 | for clsnum = 1:VOCopts.nclasses 26 | % display progress 27 | fprintf('class %d/%d: load detections\n',clsnum,VOCopts.nclasses); 28 | drawnow; 29 | 30 | resultsfile = sprintf(VOCopts.detrespath,id,VOCopts.classes{clsnum}); 31 | if ~exist(resultsfile,'file') 32 | error('Could not find detection results file to use to create segmentations (%s not found)',resultsfile); 33 | end 34 | [ids,confs,xmin,ymin,xmax,ymax]=textread(resultsfile,'%s %f %f %f %f %f'); 35 | t=[ids num2cell(ones(numel(ids),1)*clsnum) num2cell(confs) num2cell([xmin ymin xmax ymax],2)]; 36 | dets(n+(1:numel(ids)))=cell2struct(t,{'id' 'clsnum' 'conf' 'bbox'},2); 37 | n=n+numel(ids); 38 | end 39 | 40 | % Write out the segmentations 41 | 42 | segid=sprintf('comp%d',sscanf(id,'comp%d')+2); 43 | 44 | resultsdir = sprintf(VOCopts.seg.clsresdir,segid,VOCopts.testset); 45 | resultsdirinst = sprintf(VOCopts.seg.instresdir,segid,VOCopts.testset); 46 | 47 | if ~exist(resultsdir,'dir') 48 | mkdir(resultsdir); 49 | end 50 | 51 | if ~exist(resultsdirinst,'dir') 52 | mkdir(resultsdirinst); 53 | end 54 | 55 | % load test set 56 | 57 | imgids=textread(sprintf(VOCopts.seg.imgsetpath,VOCopts.testset),'%s'); 58 | 59 | cmap = VOClabelcolormap(255); 60 | detids={dets.id}; 61 | tic; 62 | for j=1:numel(imgids) 63 | % display progress 64 | if toc>1 65 | fprintf('make segmentation: %d/%d\n',j,numel(imgids)); 66 | drawnow; 67 | tic; 68 | end 69 | imname = imgids{j}; 70 | 71 | classlabelfile = sprintf(VOCopts.seg.clsrespath,segid,VOCopts.testset,imname); 72 | instlabelfile = sprintf(VOCopts.seg.instrespath,segid,VOCopts.testset,imname); 73 | 74 | imgfile = sprintf(VOCopts.imgpath,imname); 75 | imginfo = imfinfo(imgfile); 76 | 77 | vdets=dets(strmatch(imname,detids,'exact')); 78 | 79 | [instim,classim]= convert_dets_to_image(imginfo.Width, imginfo.Height,vdets,confidence); 80 | imwrite(instim,cmap,instlabelfile); 81 | imwrite(classim,cmap,classlabelfile); 82 | 83 | % Copy in ground truth - uncomment to copy ground truth segmentations in 84 | % for comparison 85 | % gtlabelfile = [VOCopts.root '/Segmentations(class)/' imname '.png']; 86 | % gtclasslabelfile = sprintf('%s/%d_gt.png',resultsdir,imnums(j)); 87 | % copyfile(gtlabelfile,gtclasslabelfile); 88 | end 89 | 90 | % Converts a set of detected bounding boxes into an instance-labelled image 91 | % and a class-labelled image 92 | function [instim,classim]=convert_dets_to_image(W,H,dets,confidence) 93 | 94 | instim = uint8(zeros([H W])); 95 | classim = uint8(zeros([H W])); 96 | [sc,si]=sort([dets.conf]); 97 | si(sc1 35 | fprintf('%s: train: %d/%d\n',cls,i,length(imgids)); 36 | drawnow; 37 | tic; 38 | end 39 | 40 | rec=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 41 | obj=rec.objects(objids(i)); 42 | 43 | fd=extractfd(VOCopts,obj); 44 | classifier.FD(1:length(fd),i)=fd; 45 | end 46 | 47 | % run classifier on test images 48 | function test(VOCopts,cls,classifier) 49 | 50 | % load test set ('val' for development kit) 51 | [imgids,objids,gt]=textread(sprintf(VOCopts.action.clsimgsetpath,cls,VOCopts.testset),'%s %d %d'); 52 | 53 | % create results file 54 | fid=fopen(sprintf(VOCopts.action.respath,'comp9',cls),'w'); 55 | 56 | % classify each person 57 | tic; 58 | for i=1:length(imgids) 59 | % display progress 60 | if toc>1 61 | fprintf('%s: test: %d/%d\n',cls,i,length(imgids)); 62 | drawnow; 63 | tic; 64 | end 65 | 66 | rec=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 67 | obj=rec.objects(objids(i)); 68 | 69 | fd=extractfd(VOCopts,obj); 70 | 71 | % compute confidence of positive classification 72 | c=classify(VOCopts,classifier,fd); 73 | 74 | % write to results file 75 | fprintf(fid,'%s %d %f\n',imgids{i},objids(i),c); 76 | end 77 | 78 | % close results file 79 | fclose(fid); 80 | 81 | % trivial feature extractor: bounding box aspect ratio 82 | function fd = extractfd(VOCopts,obj) 83 | 84 | w=obj.bndbox.xmax-obj.bndbox.xmin+1; 85 | h=obj.bndbox.ymax-obj.bndbox.ymin+1; 86 | fd=w/h; 87 | 88 | % trivial classifier: compute ratio of L2 distance betweeen 89 | % nearest positive (class) feature vector and nearest negative (non-class) 90 | % feature vector 91 | function c = classify(VOCopts,classifier,fd) 92 | 93 | d=sum(fd.*fd,1)+sum(classifier.FD.*classifier.FD,1)-2*fd'*classifier.FD; 94 | dp=min(d(classifier.gt>0)); 95 | dn=min(d(classifier.gt<0)); 96 | c=dn/(dp+eps); 97 | -------------------------------------------------------------------------------- /example_action_nobb.m: -------------------------------------------------------------------------------- 1 | function example_action_nobb 2 | 3 | % change this path if you install the VOC code elsewhere 4 | addpath([cd '/VOCcode']); 5 | 6 | % initialize VOC options 7 | VOCinit; 8 | 9 | % train and test classifier for each action 10 | for i=2:VOCopts.nactions % skip "other" 11 | cls=VOCopts.actions{i}; 12 | classifier=train(VOCopts,cls); % train classifier 13 | test(VOCopts,cls,classifier); % test classifier 14 | [recall,prec,ap]=VOCevalaction(VOCopts,'comp9',cls,true); % compute and display PR 15 | 16 | if i1 35 | fprintf('%s: train: %d/%d\n',cls,i,length(imgids)); 36 | drawnow; 37 | tic; 38 | end 39 | 40 | rec=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 41 | obj=rec.objects(objids(i)); 42 | 43 | fd=extractfd(VOCopts,obj); 44 | classifier.FD(1:length(fd),i)=fd; 45 | end 46 | 47 | % run classifier on test images 48 | function test(VOCopts,cls,classifier) 49 | 50 | % load test set ('val' for development kit) 51 | [imgids,objids,gt]=textread(sprintf(VOCopts.action.clsimgsetpath,cls,VOCopts.testset),'%s %d %d'); 52 | 53 | % create results file 54 | fid=fopen(sprintf(VOCopts.action.respath,'comp11',cls),'w'); 55 | 56 | % classify each person 57 | tic; 58 | for i=1:length(imgids) 59 | % display progress 60 | if toc>1 61 | fprintf('%s: test: %d/%d\n',cls,i,length(imgids)); 62 | drawnow; 63 | tic; 64 | end 65 | 66 | rec=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 67 | obj=rec.objects(objids(i)); 68 | 69 | fd=extractfd(VOCopts,obj); 70 | 71 | % compute confidence of positive classification 72 | c=classify(VOCopts,classifier,fd); 73 | 74 | % write to results file 75 | fprintf(fid,'%s %d %f\n',imgids{i},objids(i),c); 76 | end 77 | 78 | % close results file 79 | fclose(fid); 80 | 81 | % trivial feature extractor: reference point of person in image (!) 82 | function fd = extractfd(VOCopts,obj) 83 | 84 | fd=[obj.point.x ; obj.point.y]; 85 | 86 | % trivial classifier: compute ratio of L2 distance betweeen 87 | % nearest positive (class) feature vector and nearest negative (non-class) 88 | % feature vector 89 | function c = classify(VOCopts,classifier,fd) 90 | 91 | d=sum(fd.*fd,1)+sum(classifier.FD.*classifier.FD,1)-2*fd'*classifier.FD; 92 | dp=min(d(classifier.gt>0)); 93 | dn=min(d(classifier.gt<0)); 94 | c=dn/(dp+eps); 95 | -------------------------------------------------------------------------------- /example_classifier.m: -------------------------------------------------------------------------------- 1 | function example_classifier 2 | 3 | % change this path if you install the VOC code elsewhere 4 | addpath([cd '/VOCcode']); 5 | 6 | % initialize VOC options 7 | VOCinit; 8 | 9 | % train and test classifier for each class 10 | for i=1:VOCopts.nclasses 11 | cls=VOCopts.classes{i}; 12 | classifier=train(VOCopts,cls); % train classifier 13 | test(VOCopts,cls,classifier); % test classifier 14 | [recall,prec,ap]=VOCevalcls(VOCopts,'comp1',cls,true); % compute and display PR 15 | 16 | if i1 35 | fprintf('%s: train: %d/%d\n',cls,i,length(ids)); 36 | drawnow; 37 | tic; 38 | end 39 | 40 | fdp=sprintf(VOCopts.exfdpath,ids{i}); 41 | if exist(fdp,'file') 42 | % load features 43 | load(fdp,'fd'); 44 | else 45 | % compute and save features 46 | I=imread(sprintf(VOCopts.imgpath,ids{i})); 47 | fd=extractfd(VOCopts,I); 48 | save(fdp,'fd'); 49 | end 50 | 51 | classifier.FD(1:length(fd),i)=fd; 52 | end 53 | 54 | % run classifier on test images 55 | function test(VOCopts,cls,classifier) 56 | 57 | % load test set ('val' for development kit) 58 | [ids,gt]=textread(sprintf(VOCopts.imgsetpath,VOCopts.testset),'%s %d'); 59 | 60 | % create results file 61 | fid=fopen(sprintf(VOCopts.clsrespath,'comp1',cls),'w'); 62 | 63 | % classify each image 64 | tic; 65 | for i=1:length(ids) 66 | % display progress 67 | if toc>1 68 | fprintf('%s: test: %d/%d\n',cls,i,length(ids)); 69 | drawnow; 70 | tic; 71 | end 72 | 73 | fdp=sprintf(VOCopts.exfdpath,ids{i}); 74 | if exist(fdp,'file') 75 | % load features 76 | load(fdp,'fd'); 77 | else 78 | % compute and save features 79 | I=imread(sprintf(VOCopts.imgpath,ids{i})); 80 | fd=extractfd(VOCopts,I); 81 | save(fdp,'fd'); 82 | end 83 | 84 | % compute confidence of positive classification 85 | c=classify(VOCopts,classifier,fd); 86 | 87 | % write to results file 88 | fprintf(fid,'%s %f\n',ids{i},c); 89 | end 90 | 91 | % close results file 92 | fclose(fid); 93 | 94 | % trivial feature extractor: compute mean RGB 95 | function fd = extractfd(VOCopts,I) 96 | 97 | fd=squeeze(sum(sum(double(I)))/(size(I,1)*size(I,2))); 98 | 99 | % trivial classifier: compute ratio of L2 distance betweeen 100 | % nearest positive (class) feature vector and nearest negative (non-class) 101 | % feature vector 102 | function c = classify(VOCopts,classifier,fd) 103 | 104 | d=sum(fd.*fd)+sum(classifier.FD.*classifier.FD)-2*fd'*classifier.FD; 105 | dp=min(d(classifier.gt>0)); 106 | dn=min(d(classifier.gt<0)); 107 | c=dn/(dp+eps); 108 | -------------------------------------------------------------------------------- /example_detector.m: -------------------------------------------------------------------------------- 1 | function example_detector 2 | 3 | % change this path if you install the VOC code elsewhere 4 | addpath([cd '/VOCcode']); 5 | 6 | % initialize VOC options 7 | VOCinit; 8 | 9 | % train and test detector for each class 10 | for i=1:VOCopts.nclasses 11 | cls=VOCopts.classes{i}; 12 | detector=train(VOCopts,cls); % train detector 13 | test(VOCopts,cls,detector); % test detector 14 | [recall,prec,ap]=VOCevaldet(VOCopts,'comp3',cls,true); % compute and display PR 15 | 16 | if i1 38 | fprintf('%s: load: %d/%d\n',cls,i,length(gtids)); 39 | drawnow; 40 | tic; 41 | end 42 | 43 | % read annotation 44 | recs(i)=PASreadrecord(sprintf(VOCopts.annopath,gtids{i})); 45 | end 46 | save(cp,'gtids','recs'); 47 | end 48 | 49 | % extract features and bounding boxes 50 | detector.FD=[]; 51 | detector.bbox={}; 52 | detector.gt=[]; 53 | tic; 54 | for i=1:length(gtids) 55 | % display progress 56 | if toc>1 57 | fprintf('%s: train: %d/%d\n',cls,i,length(gtids)); 58 | drawnow; 59 | tic; 60 | end 61 | 62 | % find objects of class and extract difficult flags for these objects 63 | clsinds=strmatch(cls,{recs(i).objects(:).class},'exact'); 64 | diff=[recs(i).objects(clsinds).difficult]; 65 | 66 | % assign ground truth class to image 67 | if isempty(clsinds) 68 | gt=-1; % no objects of class 69 | elseif any(~diff) 70 | gt=1; % at least one non-difficult object of class 71 | else 72 | gt=0; % only difficult objects 73 | end 74 | 75 | if gt 76 | % extract features for image 77 | fdp=sprintf(VOCopts.exfdpath,gtids{i}); 78 | if exist(fdp,'file') 79 | % load features 80 | load(fdp,'fd'); 81 | else 82 | % compute and save features 83 | I=imread(sprintf(VOCopts.imgpath,gtids{i})); 84 | fd=extractfd(VOCopts,I); 85 | save(fdp,'fd'); 86 | end 87 | 88 | detector.FD(1:length(fd),end+1)=fd; 89 | 90 | % extract bounding boxes for non-difficult objects 91 | 92 | detector.bbox{end+1}=cat(1,recs(i).objects(clsinds(~diff)).bbox)'; 93 | 94 | % mark image as positive or negative 95 | 96 | detector.gt(end+1)=gt; 97 | end 98 | end 99 | 100 | % run detector on test images 101 | function out = test(VOCopts,cls,detector) 102 | 103 | % load test set ('val' for development kit) 104 | [ids,gt]=textread(sprintf(VOCopts.imgsetpath,VOCopts.testset),'%s %d'); 105 | 106 | % create results file 107 | fid=fopen(sprintf(VOCopts.detrespath,'comp3',cls),'w'); 108 | 109 | % apply detector to each image 110 | tic; 111 | for i=1:length(ids) 112 | % display progress 113 | if toc>1 114 | fprintf('%s: test: %d/%d\n',cls,i,length(ids)); 115 | drawnow; 116 | tic; 117 | end 118 | 119 | fdp=sprintf(VOCopts.exfdpath,ids{i}); 120 | if exist(fdp,'file') 121 | % load features 122 | load(fdp,'fd'); 123 | else 124 | % compute and save features 125 | I=imread(sprintf(VOCopts.imgpath,ids{i})); 126 | fd=extractfd(VOCopts,I); 127 | save(fdp,'fd'); 128 | end 129 | 130 | % compute confidence of positive classification and bounding boxes 131 | [c,BB]=detect(VOCopts,detector,fd); 132 | 133 | % write to results file 134 | for j=1:length(c) 135 | fprintf(fid,'%s %f %f %f %f %f\n',ids{i},c(j),BB(:,j)); 136 | end 137 | end 138 | 139 | % close results file 140 | fclose(fid); 141 | 142 | % trivial feature extractor: compute mean RGB 143 | function fd = extractfd(VOCopts,I) 144 | 145 | fd=squeeze(sum(sum(double(I)))/(size(I,1)*size(I,2))); 146 | 147 | % trivial detector: confidence is computed as in example_classifier, and 148 | % bounding boxes of nearest positive training image are output 149 | function [c,BB] = detect(VOCopts,detector,fd) 150 | 151 | % compute confidence 152 | d=sum(fd.*fd)+sum(detector.FD.*detector.FD)-2*fd'*detector.FD; 153 | dp=min(d(detector.gt>0)); 154 | dn=min(d(detector.gt<0)); 155 | c=dn/(dp+eps); 156 | 157 | % copy bounding boxes from nearest positive image 158 | pinds=find(detector.gt>0); 159 | [dp,di]=min(d(pinds)); 160 | pind=pinds(di); 161 | BB=detector.bbox{pind}; 162 | 163 | % replicate confidence for each detection 164 | c=ones(size(BB,2),1)*c; -------------------------------------------------------------------------------- /example_layout.m: -------------------------------------------------------------------------------- 1 | function example_layout 2 | 3 | % change this path if you install the VOC code elsewhere 4 | addpath([cd '/VOCcode']); 5 | 6 | % initialize VOC options 7 | VOCinit; 8 | 9 | % train and test layout 10 | 11 | gtobjects=train(VOCopts); % train layout 12 | test(VOCopts,gtobjects); % test layout 13 | [recall,prec,ap]=VOCevallayout_pr(VOCopts,'comp7',true); % compute and display PR 14 | 15 | % train: extract all person objects with parts 16 | function objects = train(VOCopts) 17 | 18 | % load training set 19 | [imgids,objids]=textread(sprintf(VOCopts.layout.imgsetpath,VOCopts.trainset),'%s %d'); 20 | 21 | % extract objects 22 | n=0; 23 | tic; 24 | for i=1:length(imgids) 25 | % display progress 26 | if toc>1 27 | fprintf('train: %d/%d\n',i,length(imgids)); 28 | drawnow; 29 | tic; 30 | end 31 | 32 | % read annotation 33 | rec=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 34 | 35 | % extract object 36 | n=n+1; 37 | objects(n)=rec.objects(objids(i)); 38 | 39 | % move bounding box to origin 40 | xmin=objects(n).bbox(1); 41 | ymin=objects(n).bbox(2); 42 | objects(n).bbox=objects(n).bbox-[xmin ymin xmin ymin]; 43 | for j=1:numel(objects(n).part) 44 | objects(n).part(j).bbox=objects(n).part(j).bbox-[xmin ymin xmin ymin]; 45 | end 46 | end 47 | 48 | % run layout on test images 49 | function out = test(VOCopts,gtobjects) 50 | 51 | % load test set 52 | [imgids,objids]=textread(sprintf(VOCopts.layout.imgsetpath,VOCopts.testset),'%s %d'); 53 | 54 | % estimate layout for each object 55 | 56 | GTBB=cat(1,gtobjects.bbox)'; 57 | n=0; 58 | tic; 59 | for i=1:length(imgids) 60 | % display progress 61 | if toc>1 62 | fprintf('test: %d/%d\n',i,length(imgids)); 63 | drawnow; 64 | tic; 65 | end 66 | 67 | % read annotation 68 | rec=PASreadrecord(sprintf(VOCopts.annopath,imgids{i})); 69 | 70 | % extract bounding box 71 | bb=rec.objects(objids(i)).bbox; 72 | 73 | % move to origin 74 | xmin=bb(1); 75 | ymin=bb(2); 76 | bb=bb-[xmin ymin xmin ymin]; 77 | 78 | % find nearest ground truth bounding box 79 | 80 | d=sum(bb.*bb)+sum(GTBB.*GTBB,1)-2*bb*GTBB; 81 | [dmin,nn]=min(d); 82 | 83 | % copy layout from nearest neighbour 84 | 85 | clear l; 86 | l.image=imgids{i}; % image identifier 87 | l.object=num2str(objids(i)); % object identifier 88 | l.confidence=num2str(-dmin); % confidence 89 | nno=gtobjects(nn); 90 | for j=1:numel(nno.part) 91 | l.part(j).class=nno.part(j).class; % part class 92 | l.part(j).bndbox.xmin=num2str(nno.part(j).bbox(1)+xmin); % bounding box 93 | l.part(j).bndbox.ymin=num2str(nno.part(j).bbox(2)+ymin); 94 | l.part(j).bndbox.xmax=num2str(nno.part(j).bbox(3)+xmin); 95 | l.part(j).bndbox.ymax=num2str(nno.part(j).bbox(4)+ymin); 96 | end 97 | 98 | % add layout result 99 | n=n+1; 100 | xml.results.layout(n)=l; 101 | end 102 | 103 | % write results file 104 | 105 | fprintf('saving results\n'); 106 | VOCwritexml(xml,sprintf(VOCopts.layout.respath,'comp7')); 107 | -------------------------------------------------------------------------------- /example_segmenter.m: -------------------------------------------------------------------------------- 1 | % example_segmenter Segmentation algorithm based on detection results. 2 | % 3 | % This segmenter requires that some detection results are present in 4 | % 'Results' e.g. by running 'example_detector'. 5 | % 6 | % Segmentations are generated from detection bounding boxes. 7 | function example_segmenter 8 | 9 | % change this path if you install the VOC code elsewhere 10 | addpath([cd '/VOCcode']); 11 | 12 | % initialize VOC options 13 | VOCinit; 14 | 15 | create_segmentations_from_detections('comp3',1); 16 | VOCevalseg(VOCopts,'comp5'); 17 | -------------------------------------------------------------------------------- /local/VOC2012/_dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiliu89/VOCdevkit/6c126483af7b53c7a1da76b1620fb4c4a0fe3a7c/local/VOC2012/_dummy -------------------------------------------------------------------------------- /results/VOC2012/Action/_dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiliu89/VOCdevkit/6c126483af7b53c7a1da76b1620fb4c4a0fe3a7c/results/VOC2012/Action/_dummy -------------------------------------------------------------------------------- /results/VOC2012/Layout/_dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiliu89/VOCdevkit/6c126483af7b53c7a1da76b1620fb4c4a0fe3a7c/results/VOC2012/Layout/_dummy -------------------------------------------------------------------------------- /results/VOC2012/Main/_dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiliu89/VOCdevkit/6c126483af7b53c7a1da76b1620fb4c4a0fe3a7c/results/VOC2012/Main/_dummy -------------------------------------------------------------------------------- /results/VOC2012/Segmentation/_dummy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/weiliu89/VOCdevkit/6c126483af7b53c7a1da76b1620fb4c4a0fe3a7c/results/VOC2012/Segmentation/_dummy -------------------------------------------------------------------------------- /viewanno.m: -------------------------------------------------------------------------------- 1 | function viewanno(imgset) 2 | 3 | if nargin<1 4 | error(['usage: viewanno(imgset) e.g. viewanno(' 39 'Main/train' 39 ') ' ... 5 | 'or viewanno(' 39 'Main/car_train' 39 ')']); 6 | end 7 | 8 | % change this path if you install the VOC code elsewhere 9 | addpath([cd '/VOCcode']); 10 | 11 | % initialize VOC options 12 | VOCinit; 13 | 14 | % load image set 15 | [ids,gt]=textread(sprintf(VOCopts.imgsetpath,['../' imgset]),'%s %d'); 16 | 17 | for i=1:length(ids) 18 | 19 | % read annotation 20 | rec=PASreadrecord(sprintf(VOCopts.annopath,ids{i})); 21 | 22 | % read image 23 | I=imread(sprintf(VOCopts.imgpath,ids{i})); 24 | 25 | if rec.segmented 26 | 27 | % read segmentations 28 | 29 | [Sclass,CMclass]=imread(sprintf(VOCopts.seg.clsimgpath,ids{i})); 30 | [Sobj,CMobj]=imread(sprintf(VOCopts.seg.instimgpath,ids{i})); 31 | end 32 | 33 | % display annotation 34 | 35 | if rec.segmented 36 | subplot(311); 37 | else 38 | clf; 39 | end 40 | 41 | imagesc(I); 42 | hold on; 43 | for j=1:length(rec.objects) 44 | bb=rec.objects(j).bbox; 45 | lbl=rec.objects(j).class; 46 | if rec.objects(j).difficult 47 | ls='r'; % "difficult": red 48 | else 49 | ls='g'; % not "difficult": green 50 | end 51 | if rec.objects(j).truncated 52 | lbl=[lbl 'T']; 53 | end 54 | if rec.objects(j).occluded 55 | lbl=[lbl 'O']; 56 | end 57 | plot(bb([1 3 3 1 1]),bb([2 2 4 4 2]),ls,'linewidth',2); 58 | text(bb(1),bb(2),lbl,'color','k','backgroundcolor',ls(1),... 59 | 'verticalalignment','top','horizontalalignment','left','fontsize',8); 60 | 61 | if isfield(rec.objects(j),'actions') 62 | albl=''; 63 | for k=1:VOCopts.nactions 64 | if rec.objects(j).actions.(VOCopts.actions{k}) 65 | if ~isempty(albl) 66 | albl=[albl '+']; 67 | end 68 | albl=[albl VOCopts.actions{k}]; 69 | end 70 | end 71 | text(bb(3),bb(4),albl,'color','k','backgroundcolor',ls(1),... 72 | 'verticalalignment','bottom','horizontalalignment','right','fontsize',8); 73 | end 74 | 75 | for k=1:length(rec.objects(j).part) 76 | bb=rec.objects(j).part(k).bbox; 77 | plot(bb([1 3 3 1 1]),bb([2 2 4 4 2]),[ls ':'],'linewidth',2); 78 | text(bb(1),bb(2),rec.objects(j).part(k).class,'color','k','backgroundcolor',ls(1),... 79 | 'verticalalignment','top','horizontalalignment','left','fontsize',8); 80 | end 81 | end 82 | hold off; 83 | axis image off; 84 | title(sprintf('image: %d/%d: "%s" (red=difficult, T=truncated, O=occluded)',... 85 | i,length(ids),ids{i}),'interpreter','none'); 86 | 87 | if rec.segmented 88 | subplot(312); 89 | imshow(Sclass,CMclass); 90 | axis image; 91 | axis off; 92 | title('segmentation by class'); 93 | 94 | subplot(313); 95 | imshow(Sobj,CMobj); 96 | axis image; 97 | axis off; 98 | title('segmentation by object'); 99 | end 100 | 101 | fprintf('press any key to continue with next image\n'); 102 | pause; 103 | end 104 | -------------------------------------------------------------------------------- /viewdet.m: -------------------------------------------------------------------------------- 1 | function viewdet(id,cls,onlytp) 2 | 3 | if nargin<2 4 | error(['usage: viewdet(competition,class,onlytp) e.g. viewdet(''comp3'',''car'') or ' ... 5 | 'viewdet(''comp3'',''car'',true) to show true positives']); 6 | end 7 | 8 | if nargin<3 9 | onlytp=false; 10 | end 11 | 12 | % change this path if you install the VOC code elsewhere 13 | addpath([cd '/VOCcode']); 14 | 15 | % initialize VOC options 16 | VOCinit; 17 | 18 | % load test set 19 | cp=sprintf(VOCopts.annocachepath,VOCopts.testset); 20 | if exist(cp,'file') 21 | fprintf('%s: loading test set\n',cls); 22 | load(cp,'gtids','recs'); 23 | else 24 | gtids=textread(sprintf(VOCopts.imgsetpath,VOCopts.testset),'%s'); 25 | for i=1:length(gtids) 26 | % display progress 27 | if toc>1 28 | fprintf('%s: load: %d/%d\n',cls,i,length(gtids)); 29 | drawnow; 30 | tic; 31 | end 32 | 33 | % read annotation 34 | recs(i)=PASreadrecord(sprintf(VOCopts.annopath,gtids{i})); 35 | end 36 | save(cp,'gtids','recs'); 37 | end 38 | 39 | % extract ground truth objects 40 | 41 | npos=0; 42 | gt(length(gtids))=struct('BB',[],'diff',[],'det',[]); 43 | for i=1:length(gtids) 44 | % extract objects of class 45 | clsinds=strmatch(cls,{recs(i).objects(:).class},'exact'); 46 | gt(i).BB=cat(1,recs(i).objects(clsinds).bbox)'; 47 | gt(i).diff=[recs(i).objects(clsinds).difficult]; 48 | gt(i).det=false(length(clsinds),1); 49 | npos=npos+sum(~gt(i).diff); 50 | end 51 | 52 | % load results 53 | [ids,confidence,b1,b2,b3,b4]=textread(sprintf(VOCopts.detrespath,id,cls),'%s %f %f %f %f %f'); 54 | BB=[b1 b2 b3 b4]'; 55 | 56 | % sort detections by decreasing confidence 57 | [sc,si]=sort(-confidence); 58 | ids=ids(si); 59 | BB=BB(:,si); 60 | 61 | % view detections 62 | 63 | clf; 64 | nd=length(confidence); 65 | tic; 66 | for d=1:nd 67 | % display progress 68 | if onlytp&toc>1 69 | fprintf('%s: viewdet: find true pos: %d/%d\n',cls,i,length(gtids)); 70 | drawnow; 71 | tic; 72 | end 73 | 74 | % find ground truth image 75 | i=strmatch(ids{d},gtids,'exact'); 76 | if isempty(i) 77 | error('unrecognized image "%s"',ids{d}); 78 | elseif length(i)>1 79 | error('multiple image "%s"',ids{d}); 80 | end 81 | 82 | % assign detection to ground truth object if any 83 | bb=BB(:,d); 84 | ovmax=-inf; 85 | for j=1:size(gt(i).BB,2) 86 | bbgt=gt(i).BB(:,j); 87 | bi=[max(bb(1),bbgt(1)) ; max(bb(2),bbgt(2)) ; min(bb(3),bbgt(3)) ; min(bb(4),bbgt(4))]; 88 | iw=bi(3)-bi(1)+1; 89 | ih=bi(4)-bi(2)+1; 90 | if iw>0 & ih>0 91 | % compute overlap as area of intersection / area of union 92 | ua=(bb(3)-bb(1)+1)*(bb(4)-bb(2)+1)+... 93 | (bbgt(3)-bbgt(1)+1)*(bbgt(4)-bbgt(2)+1)-... 94 | iw*ih; 95 | ov=iw*ih/ua; 96 | if ov>ovmax 97 | ovmax=ov; 98 | jmax=j; 99 | end 100 | end 101 | end 102 | 103 | % skip false positives 104 | if onlytp&ovmax=VOCopts.minoverlap 115 | bbgt=gt(i).BB(:,jmax); 116 | plot(bbgt([1 3 3 1 1]),bbgt([2 2 4 4 2]),'y-','linewidth',2); 117 | plot(bb([1 3 3 1 1]),bb([2 2 4 4 2]),'g:','linewidth',2); 118 | else 119 | plot(bb([1 3 3 1 1]),bb([2 2 4 4 2]),'r-','linewidth',2); 120 | end 121 | hold off; 122 | axis image; 123 | axis off; 124 | title(sprintf('det %d/%d: image: "%s" (green=true pos,red=false pos,yellow=ground truth',... 125 | d,nd,gtids{i}),'interpreter','none'); 126 | 127 | fprintf('press any key to continue with next image\n'); 128 | pause; 129 | end 130 | --------------------------------------------------------------------------------