├── utils ├── classStringToID.m ├── CLEAR_MOT_HUN.m ├── clearMOTMex.mexw64 ├── costBlockMex.mexw64 ├── MinCostMatching.mexw64 ├── external │ ├── iniconfig │ │ ├── IniConfig.m │ │ └── license.txt │ └── dollar │ │ └── toolbox │ │ └── detector │ │ ├── Contents.m │ │ ├── acfTrain.m │ │ ├── acfDetect1.mexa64 │ │ ├── models │ │ ├── AcfInriaRoc.png │ │ ├── AcfCaltechRoc.png │ │ ├── AcfInriaDetector.mat │ │ └── AcfCaltechDetector.mat │ │ ├── private │ │ ├── acfDetect1.mexa64 │ │ ├── acfDetect1.mexw64 │ │ └── acfDetect1.cpp │ │ ├── writeDets.m │ │ ├── acfTest.m │ │ ├── acfDemoCal.m │ │ ├── acfDemoInria.m │ │ ├── acfDetect.m │ │ ├── detectPeople.m │ │ ├── acfModify.m │ │ ├── evalDetections.m │ │ └── bbNms.m ├── cleanRequired.m ├── getImgExt.m ├── classIDToString.m ├── camera │ ├── distortedToUndistortedSensorCoord.m │ ├── README.md │ ├── undistortedToDistortedImageCoord.m │ ├── distortedToUndistortedImageCoord.m │ ├── worldToImage.m │ ├── getRotTrans.m │ ├── undistortedToDistortedSensorCoord.m │ ├── imageToWorld.m │ ├── calib_towncentre.m │ └── parseCameraParameters.m ├── boxiou.m ├── getClassLabels.m ├── boxUnion.m ├── boxIntersect.m ├── getROIs.m ├── getSeqInfoFromFile.m ├── ismember_mex.c ├── printMetricsDet.m ├── printMetricsExt.m ├── printMetrics.m ├── evaluateBenchmark.m ├── costFunction.m ├── IDmeasures.m ├── convertMatToStruct.m ├── convertTXTToStruct.m ├── MinCostMatching.cpp ├── costBlockMex.cpp └── preprocessResult.m ├── eval ├── createPath.m ├── findSeqList.m ├── getClassID.m ├── VOCap.m ├── nmsProcess.m ├── createIntImg.m ├── breakGts.m ├── combineTrks.m ├── classSplit.m ├── classEval.m ├── nms.m ├── selectTrackData.m ├── dropObjects.m ├── calcAP.m ├── evaluateTendMark.m └── runTrackerAllClass.m ├── trackers └── GOG │ ├── utils │ ├── readPLS.m │ ├── distortedToUndistortedSensorCoord.m │ ├── greedy_gt_generator.m │ ├── projectToGroundPlane.m │ ├── greedy_detect_generator.m │ ├── worldToImage.m │ ├── read_gt_dp.m │ ├── getRotTrans.m │ ├── greedy_Pets_detct_generator.m │ ├── cutDetections.m │ ├── imageToWorld.m │ ├── undistortedToDistortedSensorCoord.m │ ├── parseDetections.m │ ├── greedy_Pets_gt_generator.m │ ├── parseCameraParameters.m │ └── xmlwrite_xerces.m │ ├── sub.m │ ├── distortedToUndistortedSensorCoord.m │ ├── add.m │ ├── dres2bboxes.m │ ├── nms_aggressive.m │ ├── frames_to_video.m │ ├── bboxes2dres.m │ ├── saveResTxt.m │ ├── projectToGroundPlane.m │ ├── cs2_func.m │ ├── build_graph.m │ ├── worldToImage.m │ ├── text_to_image.m │ ├── getRotTrans.m │ ├── mydetect_objects.m │ ├── run_tracker.m │ ├── find_overlap.m │ ├── calc_overlap.m │ ├── README.txt │ ├── detect_objects.m │ ├── show_bbox_on_image.m │ ├── saveStateInfo.m │ ├── score.m │ ├── imageToWorld.m │ ├── tracking_dp.m │ ├── undistortedToDistortedSensorCoord.m │ ├── show_bboxes_on_video.m │ ├── parseCameraParameters.m │ └── tracking_push_relabel.m ├── display ├── reopenFig.m ├── clampBBox.m ├── getColorSet.m ├── showResults.m ├── displayTrackingResult.m └── displayBBoxes.m ├── evalMOT.m ├── evaluateTrackB.m └── README.md /utils/classStringToID.m: -------------------------------------------------------------------------------- 1 | find(strcmp(labels,'occluder')) -------------------------------------------------------------------------------- /utils/CLEAR_MOT_HUN.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/CLEAR_MOT_HUN.m -------------------------------------------------------------------------------- /eval/createPath.m: -------------------------------------------------------------------------------- 1 | function createPath(newPath) 2 | 3 | if(~isdir(newPath)) 4 | mkdir(newPath); 5 | end -------------------------------------------------------------------------------- /utils/clearMOTMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/clearMOTMex.mexw64 -------------------------------------------------------------------------------- /utils/costBlockMex.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/costBlockMex.mexw64 -------------------------------------------------------------------------------- /trackers/GOG/utils/readPLS.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/trackers/GOG/utils/readPLS.m -------------------------------------------------------------------------------- /utils/MinCostMatching.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/MinCostMatching.mexw64 -------------------------------------------------------------------------------- /utils/external/iniconfig/IniConfig.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/iniconfig/IniConfig.m -------------------------------------------------------------------------------- /utils/cleanRequired.m: -------------------------------------------------------------------------------- 1 | function cl=cleanRequired(seqFolder) 2 | 3 | cl = ~isempty(strfind(seqFolder,'MOT16')) || ~isempty(strfind(seqFolder,'MOT17')); -------------------------------------------------------------------------------- /eval/findSeqList.m: -------------------------------------------------------------------------------- 1 | function nameSeqs = findSeqList(seqPath) 2 | 3 | d = dir(seqPath); 4 | nameSeqs = {d.name}'; 5 | nameSeqs(ismember(nameSeqs,{'.','..'})) = []; -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/Contents.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/Contents.m -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/acfTrain.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/acfTrain.m -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/acfDetect1.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/acfDetect1.mexa64 -------------------------------------------------------------------------------- /utils/getImgExt.m: -------------------------------------------------------------------------------- 1 | function imgExt = getImgExt(seqFolder) 2 | % return image extension including the dot 3 | % e.g. '.jpg' 4 | 5 | imgExt = '.jpg'; 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/models/AcfInriaRoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/models/AcfInriaRoc.png -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/models/AcfCaltechRoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/models/AcfCaltechRoc.png -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/private/acfDetect1.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/private/acfDetect1.mexa64 -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/private/acfDetect1.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/private/acfDetect1.mexw64 -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/models/AcfInriaDetector.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/models/AcfInriaDetector.mat -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/models/AcfCaltechDetector.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VisDrone/VisDrone2018-MOT-toolkit/HEAD/utils/external/dollar/toolbox/detector/models/AcfCaltechDetector.mat -------------------------------------------------------------------------------- /utils/classIDToString.m: -------------------------------------------------------------------------------- 1 | function classString = classIDToString(classID) 2 | 3 | labels = getClassLabels; 4 | 5 | if classID<1 || classID>length(labels) 6 | classString='unknown'; 7 | else 8 | classString = char(labels{classID}); 9 | end 10 | 11 | end -------------------------------------------------------------------------------- /trackers/GOG/sub.m: -------------------------------------------------------------------------------- 1 | function s = sub(s,I), 2 | % s = sub(s,I) 3 | % Returns a subset of the structure s 4 | 5 | if ~isempty(s), 6 | n = fieldnames(s); 7 | for i = 1:length(n), 8 | f = n{i}; 9 | s.(f) = s.(f)(I,:); 10 | end 11 | end 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /trackers/GOG/distortedToUndistortedSensorCoord.m: -------------------------------------------------------------------------------- 1 | function [Xu Yu]=distortedToUndistortedSensorCoord (Xd, Yd, mKappa1) 2 | % /* convert from distorted to undistorted sensor plane coordinates */ 3 | distortion_factor = 1 + mKappa1 * (Xd*Xd + Yd*Yd); 4 | Xu = Xd * distortion_factor; 5 | Yu = Yd * distortion_factor; 6 | end -------------------------------------------------------------------------------- /utils/camera/distortedToUndistortedSensorCoord.m: -------------------------------------------------------------------------------- 1 | function [Xu Yu]=distortedToUndistortedSensorCoord (Xd, Yd, mKappa1) 2 | % /* convert from distorted to undistorted sensor plane coordinates */ 3 | distortion_factor = 1 + mKappa1 * (Xd*Xd + Yd*Yd); 4 | Xu = Xd * distortion_factor; 5 | Yu = Yd * distortion_factor; 6 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/distortedToUndistortedSensorCoord.m: -------------------------------------------------------------------------------- 1 | function [Xu Yu]=distortedToUndistortedSensorCoord (Xd, Yd, mKappa1) 2 | % /* convert from distorted to undistorted sensor plane coordinates */ 3 | distortion_factor = 1 + mKappa1 * (Xd*Xd + Yd*Yd); 4 | Xu = Xd * distortion_factor; 5 | Yu = Yd * distortion_factor; 6 | end -------------------------------------------------------------------------------- /trackers/GOG/add.m: -------------------------------------------------------------------------------- 1 | function s = add(s1,s2), 2 | % s = add(s1,s2) 3 | % Appends structures s2 to the end of s1 4 | 5 | if isempty(s1) 6 | s = s2; 7 | elseif isempty(s2), 8 | s = s1; 9 | else 10 | n = fieldnames(s1); 11 | for i = 1:length(n), 12 | f = n{i}; 13 | s.(f) = cat(1,s1.(f),s2.(f)); 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /eval/getClassID.m: -------------------------------------------------------------------------------- 1 | function classID = getClassID(className) 2 | 3 | fullClassSet = {'ignored','pedestrian','person','bicycle','car','van','truck','tricycle','awning-tricyle','bus','motor', 'others'}; 4 | 5 | [flag, id] = ismember(className, fullClassSet); 6 | 7 | if(flag) 8 | classID = id - 1; 9 | else 10 | error('error in class name!'); 11 | end -------------------------------------------------------------------------------- /eval/VOCap.m: -------------------------------------------------------------------------------- 1 | % This code was originally written and distributed as part of the 2 | % PASCAL VOC challenge 3 | function ap = VOCap(rec,prec) 4 | 5 | mrec=[0 ; rec ; 1]; 6 | mpre=[0 ; prec ; 0]; 7 | for i=numel(mpre)-1:-1:1 8 | mpre(i)=max(mpre(i),mpre(i+1)); 9 | end 10 | i=find(mrec(2:end)~=mrec(1:end-1))+1; 11 | ap=sum((mrec(i)-mrec(i-1)).*mpre(i)); 12 | 13 | -------------------------------------------------------------------------------- /trackers/GOG/dres2bboxes.m: -------------------------------------------------------------------------------- 1 | function bboxes = dres2bboxes(dres, fnum) 2 | for i = 1:fnum 3 | bboxes(i).bbox = []; 4 | end 5 | 6 | for i = 1:length(dres.x) 7 | % bbox = [dres.x(i) dres.y(i) dres.w(i) dres.h(i) dres.r(i)]; 8 | bbox = [dres.x(i) dres.y(i) dres.x(i)+dres.w(i) dres.y(i)+dres.h(i) dres.id(i)]; 9 | bboxes(dres.fr(i)).bbox = [bboxes(dres.fr(i)).bbox; bbox]; 10 | end -------------------------------------------------------------------------------- /eval/nmsProcess.m: -------------------------------------------------------------------------------- 1 | function detections = nmsProcess(det, isNMS, nmsThre) 2 | if(isNMS) 3 | detections = []; 4 | numFr = max(det(:,1)); 5 | for i = 1:numFr 6 | idx = det(:,1) == i; 7 | curdet = det(idx,:); 8 | pick = nms(curdet(:,3:7), nmsThre); 9 | detections = cat(1, detections, curdet(pick,:)); 10 | end 11 | else 12 | detections = det; 13 | end -------------------------------------------------------------------------------- /utils/boxiou.m: -------------------------------------------------------------------------------- 1 | function iou=boxiou(x1,y1,w1,h1,x2,y2,w2,h2) 2 | % compute intersection over union of two bboxes 3 | % 4 | 5 | bisect=boxIntersect(x1,x1+w1,y1+h1,y1,x2,x2+w2,y2+h2,y2); 6 | iou=0; 7 | if ~bisect, return; end 8 | 9 | bunion=boxUnion(x1,x1+w1,y1+h1,y1,x2,x2+w2,y2+h2,y2,bisect); 10 | 11 | assert(bunion>0,'something wrong with union computation'); 12 | iou=bisect/bunion; 13 | 14 | end -------------------------------------------------------------------------------- /utils/camera/README.md: -------------------------------------------------------------------------------- 1 | # Camera Utility Files 2 | 3 | This folder contains scripts for computing image-to-world and world-to-image projections. 4 | 5 | `calib_towncentre.m` is to be used with the AVG-TownCentre sequence. 6 | 7 | The rest is for the PETS sequence, which follows the Tsai camera model. parseCameraParameters can be used to read the camera xml file and the two scripts `imageToWorld.m` and `worldToImage.m` contain the projection routines. -------------------------------------------------------------------------------- /eval/createIntImg.m: -------------------------------------------------------------------------------- 1 | function intImg = createIntImg(img) 2 | 3 | [height, width] = size(img); 4 | intImg = img; 5 | for i = 2:height 6 | intImg(i, 1) = intImg(i, 1) + intImg(i-1, 1); 7 | end 8 | for j = 2:width 9 | intImg(1, j) = intImg(1, j) + intImg(1, j-1); 10 | end 11 | 12 | for i = 2:height 13 | for j = 2:width 14 | intImg(i, j) = intImg(i, j) + intImg(i-1, j) + intImg(i, j-1) - intImg(i-1, j-1); 15 | end 16 | end -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/writeDets.m: -------------------------------------------------------------------------------- 1 | function writeDets(bbx,outfile) 2 | % write out Dollar's detections to our format 3 | 4 | F=length(bbx); 5 | 6 | alldets=zeros(0,10); 7 | for t=1:F 8 | ndets=size(bbx{t},1); 9 | dets=[repmat(t,ndets,1) repmat(-1,ndets,1) bbx{t} repmat(-1,ndets,1) repmat(-1,ndets,1) repmat(-1,ndets,1)]; 10 | alldets=[alldets; dets]; 11 | end 12 | dlmwrite(outfile,alldets); 13 | 14 | end 15 | -------------------------------------------------------------------------------- /utils/getClassLabels.m: -------------------------------------------------------------------------------- 1 | function labels = getClassLabels() 2 | 3 | labels={'ped', ... % 1 4 | 'person_on_vhcl', ... % 2 5 | 'car', ... % 3 6 | 'bicycle', ... % 4 7 | 'mbike', ... % 5 8 | 'non_mot_vhcl', ... % 6 9 | 'static_person', ... % 7 10 | 'distractor', ... % 8 11 | 'occluder', ... % 9 12 | 'occluder_on_grnd', ... %10 13 | 'occluder_full', ... % 11 14 | 'reflection', ... % 12 15 | 'crowd' ... % 13 16 | }; 17 | 18 | 19 | end -------------------------------------------------------------------------------- /display/reopenFig.m: -------------------------------------------------------------------------------- 1 | function reopenFig(figname) 2 | % 3 | % (C) Anton Andriyenko, 2012 4 | % 5 | % The code may be used free of charge for non-commercial and 6 | % educational purposes, the only requirement is that this text is 7 | % preserved within the derivative work. For any other purpose you 8 | % must contact the authors for permission. This code may not be 9 | % redistributed without written permission from the authors. 10 | 11 | close(findobj('type','figure','name',figname)) 12 | figure('name',figname); 13 | 14 | end -------------------------------------------------------------------------------- /trackers/GOG/nms_aggressive.m: -------------------------------------------------------------------------------- 1 | function inds_out = nms_aggressive(dres, inds, thr) 2 | 3 | inds_out = zeros(length(dres.x),1); 4 | k = 0; 5 | for i=1:length(inds) 6 | f1 = inds(i); %% index of this detetion 7 | f2 = find(dres.fr == dres.fr(f1)); %% indices of all detections on the same frame 8 | 9 | [ovs ovs_n1] = calc_overlap(dres,f1,dres,f2); 10 | f3 = f2(find((ovs > thr) + (ovs_n1 > 0.9))); 11 | inds_out(k+1:k+length(f3)) = f3; 12 | k = k + length(f3); 13 | end 14 | inds_out = inds_out(1:k); 15 | -------------------------------------------------------------------------------- /trackers/GOG/frames_to_video.m: -------------------------------------------------------------------------------- 1 | % converts bunch of frames to a video file 2 | function frames_to_video(frames_path, video_fname, frame_rate) 3 | if ~exist('frame_rate') 4 | frame_rate = 5; 5 | end 6 | % unix(['ffmpeg -y -i ' frames_path '%6d.jpg -ar 22050 -b 50000 -vtag DIVX 7 | % -f avi ' video_fname]); 8 | % unix(['ffmpeg -y -r ' num2str(frame_rate) ' -i ' frames_path '%6d.jpg -ar 22050 -b 50000 -r 24 -vtag DIVX -f avi ' video_fname]); 9 | unix(['ffmpeg -y -r ' num2str(frame_rate) ' -i ' frames_path '%8d.jpg -b 1000000 -vtag DIVX -f avi ' video_fname]); -------------------------------------------------------------------------------- /utils/boxUnion.m: -------------------------------------------------------------------------------- 1 | function union=boxUnion(bboxleft1, bboxright1, bboxbottom1, bboxup1, bboxleft2, bboxright2, bboxbottom2, bboxup2,isect) 2 | % Compute union of two bounding boxes 3 | 4 | a1=bboxright1-bboxleft1; 5 | b1=bboxbottom1-bboxup1; 6 | a2=bboxright2-bboxleft2; 7 | b2=bboxbottom2-bboxup2; 8 | union=a1*b1+a2*b2; 9 | if nargin>8 10 | bisect=isect; 11 | else 12 | bisect=boxIntersect(bboxleft1, bboxright1, bboxbottom1, bboxup1, bboxleft2, bboxright2, bboxbottom2, bboxup2); 13 | end 14 | union=union-bisect; 15 | 16 | 17 | end 18 | -------------------------------------------------------------------------------- /utils/camera/undistortedToDistortedImageCoord.m: -------------------------------------------------------------------------------- 1 | function [Xfd Yfd]=undistortedToDistortedImageCoord (Xfu, Yfu, mDpx, mDpy, mCx, mCy, mSx, mKappa1) 2 | 3 | 4 | % /* convert from image to sensor coordinates */ 5 | Xu = mDpx * (Xfu - mCx) / mSx; 6 | Yu = mDpy * (Yfu - mCy); 7 | 8 | % /* convert from undistorted sensor to distorted sensor plane coordinates */ 9 | [Xd Yd]=undistortedToDistortedSensorCoord(Xu, Yu, mKappa1); 10 | 11 | % /* convert from sensor to image coordinates */ 12 | Xfd = Xd * mSx / mDpx + mCx; 13 | Yfd = Yd / mDpy + mCy; 14 | end -------------------------------------------------------------------------------- /utils/camera/distortedToUndistortedImageCoord.m: -------------------------------------------------------------------------------- 1 | function [Xfu Yfu]=distortedToUndistortedImageCoord (Xfd, Yfd, mDpx, mDpy, mCx, mCy, mSx, mKappa1) 2 | 3 | 4 | % /* convert from image to sensor coordinates */ 5 | Xd = mDpx * (Xfd - mCx) / mSx; 6 | Yd = mDpy * (Yfd - mCy); 7 | 8 | % /* convert from distorted sensor to undistorted sensor plane coordinates */ 9 | [Xu Yu]=distortedToUndistortedSensorCoord(Xd, Yd, mKappa1); 10 | 11 | % /* convert from sensor to image coordinates */ 12 | Xfu = Xu * mSx / mDpx + mCx; 13 | Yfu = Yu / mDpy + mCy; 14 | 15 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/greedy_gt_generator.m: -------------------------------------------------------------------------------- 1 | function gt = greedy_gt_generator(gtInfo) 2 | 3 | count = 1; 4 | [r, c] = size(gtInfo.X); 5 | for i = 1:r 6 | for j = 1:c 7 | if(gtInfo.W(i,j) ~= 0 && gtInfo.H(i,j) ~= 0) 8 | gt.x(count,1) = gtInfo.X(i,j)-0.5*gtInfo.W(i,j); 9 | gt.y(count,1) = gtInfo.Y(i,j)-gtInfo.H(i,j); 10 | gt.w(count,1) = gtInfo.W(i,j); 11 | gt.h(count,1) = gtInfo.H(i,j); 12 | gt.fr(count,1) = i; 13 | gt.vid(count,1) = 3; 14 | count = count+1; 15 | end 16 | end 17 | end -------------------------------------------------------------------------------- /eval/breakGts.m: -------------------------------------------------------------------------------- 1 | function gtdata = breakGts(gtdata) 2 | % normalize IDs 3 | [~, ~, ic] = unique(gtdata(:,2)); 4 | gtdata(:,2) = ic; 5 | % break the groundtruth trajetory with multiple object categories 6 | tracks = unique(ic); 7 | newtrack_id = max(tracks) + 1; 8 | for i = 1:numel(tracks) 9 | idx = gtdata(:, 2) == tracks(i); 10 | cls = gtdata(idx, 8); 11 | allcls = unique(cls); 12 | if(numel(allcls) > 1) 13 | for j = 2:numel(allcls) 14 | idxCls = idx & gtdata(:, 8) == allcls(j); 15 | gtdata(idxCls, 2) = newtrack_id; 16 | newtrack_id = newtrack_id + 1; 17 | end 18 | end 19 | end -------------------------------------------------------------------------------- /utils/boxIntersect.m: -------------------------------------------------------------------------------- 1 | function isect=boxIntersect(bboxleft1, bboxright1, bboxbottom1, bboxup1, bboxleft2, bboxright2, bboxbottom2, bboxup2) 2 | % Compute intersection area of two bouding boxes A,B 3 | % A=[bboxleft1 bboxbottom1 abs(bboxright1-bboxleft1) abs(bboxbottom1-bboxup1)]; 4 | % B=[bboxleft2 bboxbottom2 abs(bboxright2-bboxleft2) abs(bboxbottom2-bboxup2)]; 5 | % 6 | % isect=rectint(A,B); 7 | isect=0; 8 | 9 | hor= max(0,min(bboxright1,bboxright2) - max(bboxleft1,bboxleft2)); 10 | 11 | if ~hor, return; end 12 | ver= max(0,min(bboxbottom1,bboxbottom2) - max(bboxup1,bboxup2)); 13 | if ~ver, return; end 14 | 15 | isect = hor*ver; 16 | 17 | end -------------------------------------------------------------------------------- /trackers/GOG/bboxes2dres.m: -------------------------------------------------------------------------------- 1 | function dres = bboxes2dres(bboxes) 2 | k=0; 3 | 4 | dres.x = []; 5 | dres.y = []; 6 | dres.w = []; 7 | dres.h = []; 8 | dres.r = []; 9 | dres.fr = []; 10 | 11 | for i=1:length(bboxes) 12 | bbox = bboxes(i).bbox; 13 | if isempty(bbox) 14 | continue 15 | end 16 | dres.x = [dres.x; bbox(:,1)]; 17 | dres.y = [dres.y; bbox(:,2)]; 18 | % dres.w = [dres.w; bbox(:,3)]; 19 | % dres.h = [dres.h; bbox(:,4)]; 20 | dres.w = [dres.w; bbox(:,3) - bbox(:,1)+1]; 21 | dres.h = [dres.h; bbox(:,4) - bbox(:,2)+1]; 22 | dres.r = [dres.r; bbox(:,5)]; 23 | dres.fr = [dres.fr; repmat(i, [size(bbox,1) 1])]; 24 | end 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /utils/getROIs.m: -------------------------------------------------------------------------------- 1 | function ROI = getROIs() 2 | 3 | ROI{1} = [214 553;1904 411;1897 1055;216 1051]; 4 | ROI{2} = [35 423;574 413;624 300;1075 284;1150 341;1153 396;1260 393;1610 492;1608 460;1614 446;1771 440;1777 485;1894 483;1894 1048;29 1051]; 5 | ROI{3} = [65 659;926 662;798 592;827 574;1201 573;1500 671;1888 673;1882 1047;68 1044]; 6 | ROI{4} = [1189 1043;1664 1043;1434 240;1267 240]; 7 | ROI{5} = [28 1054;1897 1054;1893 202;410 211;397 313;311 320;104 369;71 449;107 567;27 750]; 8 | ROI{6} = [154 646;957 626;1863 886;1866 1050;40 1059;56 775;103 682]; 9 | ROI{7} = [40 751;40 1049;1862 1050;1862 875;862 817;1004 730;667 710;445 779]; 10 | ROI{8} = [1867 637;1806 1066;53 1047;455 807;457 729;824 531]; -------------------------------------------------------------------------------- /trackers/GOG/saveResTxt.m: -------------------------------------------------------------------------------- 1 | function res = saveResTxt(bboxes_tracked) 2 | 3 | frame_num = size(bboxes_tracked, 2); 4 | track_bbox = zeros(1, 6); 5 | res = []; 6 | for frame = 1:frame_num 7 | bboxes = bboxes_tracked(1,frame).bbox; 8 | id_num = size(bboxes, 1); 9 | for id = 1:id_num 10 | track_bbox(1) = frame; 11 | track_bbox(2) = bboxes(id, 5); 12 | track_bbox(3) = bboxes(id, 1); 13 | track_bbox(4) = bboxes(id, 2); 14 | track_bbox(5) = bboxes(id, 3) - bboxes(id, 1); 15 | track_bbox(6) = bboxes(id, 4) - bboxes(id, 2); 16 | res = cat(1, res, [track_bbox, 1, -1, -1, -1]); 17 | end 18 | end 19 | 20 | if(~isempty(res)) 21 | res = sortrows(res,1); 22 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/projectToGroundPlane.m: -------------------------------------------------------------------------------- 1 | function [Xgp Ygp]=projectToGroundPlane(Xi, Yi, sceneInfo) 2 | % 3 | % (C) Anton Andriyenko, 2012 4 | % 5 | % The code may be used free of charge for non-commercial and 6 | % educational purposes, the only requirement is that this text is 7 | % preserved within the derivative work. For any other purpose you 8 | % must contact the authors for permission. This code may not be 9 | % redistributed without written permission from the authors. 10 | 11 | [F N]=size(Xi); 12 | Xgp=zeros(size(Xi)); 13 | Ygp=zeros(size(Xi)); 14 | 15 | for t=1:F 16 | extar=find(Xi(t,:)); 17 | for id=extar 18 | [Xgp(t,id) Ygp(t,id) zw]=imageToWorld(Xi(t,id), Yi(t,id), sceneInfo.camPar); 19 | end 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /trackers/GOG/projectToGroundPlane.m: -------------------------------------------------------------------------------- 1 | function [Xgp Ygp]=projectToGroundPlane(Xi, Yi, sceneInfo) 2 | % 3 | % (C) Anton Andriyenko, 2012 4 | % 5 | % The code may be used free of charge for non-commercial and 6 | % educational purposes, the only requirement is that this text is 7 | % preserved within the derivative work. For any other purpose you 8 | % must contact the authors for permission. This code may not be 9 | % redistributed without written permission from the authors. 10 | 11 | [F, N]=size(Xi); 12 | Xgp=zeros(size(Xi)); 13 | Ygp=zeros(size(Xi)); 14 | 15 | 16 | for t=1:F 17 | extar=find(Xi(t,:)); 18 | for id=extar 19 | [Xgp(t,id), Ygp(t,id), zw]=imageToWorld(Xi(t,id), Yi(t,id), sceneInfo.camPar); 20 | end 21 | end 22 | 23 | 24 | end 25 | -------------------------------------------------------------------------------- /display/clampBBox.m: -------------------------------------------------------------------------------- 1 | function [bleft bright btop bbottom]= clampBBox(bleft, bright, btop, bbottom, imgWidth, imHeight) 2 | % 3 | % (C) Anton Andriyenko, 2012 4 | % 5 | % The code may be used free of charge for non-commercial and 6 | % educational purposes, the only requirement is that this text is 7 | % preserved within the derivative work. For any other purpose you 8 | % must contact the authors for permission. This code may not be 9 | % redistributed without written permission from the authors. 10 | 11 | 12 | % clamp bounding box to [1, imageDim] 13 | 14 | bleft=max(1,bleft); bleft=min(imgWidth,bleft); 15 | bright=max(1,bright); bright=min(imgWidth,bright); 16 | btop=max(1,btop); btop=min(imHeight,btop); 17 | bbottom=max(1,bbottom); bbottom=min(imHeight,bbottom); 18 | 19 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/greedy_detect_generator.m: -------------------------------------------------------------------------------- 1 | function dres = greedy_detect_generator(detections, numFrames) 2 | 3 | detections = parseDetections(detections, numFrames); 4 | 5 | count = 1; 6 | for i = numFrames 7 | numTargets = size(detections(i).xi, 2); 8 | for j = 1:numTargets 9 | dres.w(count,1) = detections(i).wd(1,j); 10 | dres.h(count,1) = detections(i).ht(1,j); 11 | w = dres.w(count,1); 12 | h = dres.h(count,1); 13 | dres.x(count,1) = detections(i).xi(1,j) - 0.5*w; 14 | dres.y(count,1) = detections(i).yi(1,j) - h; 15 | dres.fr(count,1) = i; 16 | dres.r(count,1) = detections(i).sc(1,j)*3-1.5; 17 | count = count+1; 18 | end 19 | end 20 | 21 | dres = build_graph(dres); -------------------------------------------------------------------------------- /utils/getSeqInfoFromFile.m: -------------------------------------------------------------------------------- 1 | function [seqName, seqFolder, imgFolder, frameRate, F, imWidth, imHeight, imgExt] ... 2 | = getSeqInfoFromFile(seq, dataDir) 3 | % construct variables with relevant information about the sequence 'seq' 4 | % 5 | 6 | seqName=char(seq); 7 | seqFolder= [dataDir,seqName,filesep]; 8 | 9 | 10 | seqInfoFile = [dataDir,seqName,filesep,'seqinfo.ini']; 11 | ini = IniConfig(); 12 | ini.ReadFile(seqInfoFile); 13 | 14 | imgFolder = ini.GetValues('Sequence','imDir'); 15 | frameRate = ini.GetValues('Sequence','frameRate'); 16 | F=ini.GetValues('Sequence','seqLength'); 17 | imWidth=ini.GetValues('Sequence','imWidth'); 18 | imHeight=ini.GetValues('Sequence','imHeight'); 19 | imgExt = ini.GetValues('Sequence','imExt'); 20 | 21 | end 22 | -------------------------------------------------------------------------------- /trackers/GOG/cs2_func.m: -------------------------------------------------------------------------------- 1 | % This function calls c implementation of push-relabel algorithm. It is downloaded from http://www.igsystems.com/cs2/index.html and then we mex'ed it to run faster in matlab. 2 | % dat_in = [tail head cost lb ub]; 3 | % dat_out = [frail fhead flow]; 4 | % excess_node = [source_num sink_num]; 5 | % excess_flow = [sourec_flow sink_flow]; 6 | 7 | function [cost, dat_out] = cs2_func(dat_in, excess_node, excess_flow) 8 | 9 | num_arc = size(dat_in,1); 10 | 11 | tail = dat_in(:,1)'; 12 | head = dat_in(:,2)'; 13 | cost = dat_in(:,3)'; 14 | 15 | low = dat_in(:,4)'; 16 | acap = dat_in(:,5)'; 17 | 18 | num_node = max([tail head]); 19 | scale = 12; 20 | [cost,ftail,fhead,flow] = cs2mex(scale, num_node, num_arc, excess_node, excess_flow, tail, head, low, acap, cost); 21 | 22 | dat_out = [ftail fhead flow]; 23 | -------------------------------------------------------------------------------- /display/getColorSet.m: -------------------------------------------------------------------------------- 1 | function colors = getColorSet(numObjs) 2 | % get rgb [0,1] values from id 3 | colors=[ 4 | 128 255 255; % 5 | 255 0 0; % red 1 6 | 0 255 0; % green 2 7 | 0 0 255; % blue 3 8 | 0 255 255; % cyan 4 9 | 255 0 255; % magenta 5 10 | 212 212 0; % yellow 6 11 | 25 25 25; % black 7 12 | 34,139,34; % forestgreen 8 13 | 0,191,255; % deepskyblue 9 14 | 139,0,0 ; % darkred 10 15 | 218,112,214; % orchid 11 16 | 244,164,96 ;]/255; % sandybrown 12 17 | colors = colors / 255; 18 | if(numObjs >= 13) 19 | morecolors = rand(max(1,numObjs-13), 3); 20 | colors = cat(1,colors,morecolors); 21 | end -------------------------------------------------------------------------------- /eval/combineTrks.m: -------------------------------------------------------------------------------- 1 | function res = combineTrks(evalClassSet, allRes) 2 | % combine tracks of multiple object categories 3 | maxID = 0; 4 | res = []; 5 | for idClass = 1:length(evalClassSet) 6 | if(~isempty(allRes{idClass})) 7 | resClass = allRes{idClass}; 8 | resClass(:,2) = resClass(:,2) + maxID; 9 | maxID = maxID + max(resClass(:,2)) + 1; 10 | res = cat(1, res, resClass); 11 | end 12 | end 13 | 14 | % check the tracking results 15 | cls = unique(res(:,8)); 16 | allids = []; 17 | for i = 1:length(cls) 18 | idx = res(:,8) == cls(i); 19 | ids = unique(res(idx, 2)); 20 | if(~nnz(ismember(ids, allids))) 21 | allids = cat(1, allids, ids); 22 | else 23 | error('The objects of multiple object categories use the same track_id.'); 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /trackers/GOG/build_graph.m: -------------------------------------------------------------------------------- 1 | function dres = build_graph(dres) 2 | ov_thresh = 0.3; %original = 0.5 3 | dnum = length(dres.x); 4 | len1 = max(dres.fr); 5 | for fr = 2:max(dres.fr) 6 | f1 = find(dres.fr == fr); %% indices for detections on this frame 7 | f2 = find(dres.fr == fr-1); %% indices for detections on the previous frame 8 | for i = 1:length(f1) 9 | ovs1 = calc_overlap(dres, f1(i), dres, f2); 10 | inds1 = find(ovs1 > ov_thresh); %% find overlapping bounding boxes. 11 | 12 | ratio1 = dres.h(f1(i))./dres.h(f2(inds1)); 13 | inds2 = (min(ratio1, 1./ratio1) > 0.8); %% we ignore transitions with large change in the size of bounding boxes. 14 | 15 | dres.nei(f1(i),1).inds = f2(inds1(inds2))'; %% each detction window will have a list of indices pointing to its neighbors in the previous frame. 16 | end 17 | end -------------------------------------------------------------------------------- /eval/classSplit.m: -------------------------------------------------------------------------------- 1 | function sorttrackData = classSplit(trackData) 2 | % object category: 3 | % ignored |pedestrian| person| bicycle| car| van| truck| tricycle| awning-tricycle | bus| motor| others 4 | % 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 5 | 6 | sorttrackData.pedestrian = trackData(trackData(:,8)==1,:); 7 | sorttrackData.person = trackData(trackData(:,8)==2,:); 8 | sorttrackData.bicycle = trackData(trackData(:,8)==3,:); 9 | sorttrackData.car = trackData(trackData(:,8)==4,:); 10 | sorttrackData.van = trackData(trackData(:,8)==5,:); 11 | sorttrackData.truck = trackData(trackData(:,8)==6,:); 12 | sorttrackData.tricycle = trackData(trackData(:,8)==7,:); 13 | sorttrackData.awningtricycle = trackData(trackData(:,8)==8,:); 14 | sorttrackData.bus = trackData(trackData(:,8)==9,:); 15 | sorttrackData.motor = trackData(trackData(:,8)==10,:); -------------------------------------------------------------------------------- /trackers/GOG/worldToImage.m: -------------------------------------------------------------------------------- 1 | function [Xi Yi]=worldToImage(Xw,Yw,Zw,mR,mT,mInt,mGeo) 2 | 3 | 4 | % /* convert from world coordinates to camera coordinates */ 5 | x=[mR mT]*[Xw;Yw;Zw;1]; 6 | xc = x(1); 7 | yc = x(2); 8 | zc = x(3); 9 | 10 | % /* convert from camera coordinates to undistorted sensor plane coordinates */ 11 | Xu = mInt.mFocal * xc / zc; 12 | Yu = mInt.mFocal * yc / zc; 13 | 14 | % /* convert from undistorted to distorted sensor plane coordinates */ 15 | [Xd Yd]=undistortedToDistortedSensorCoord (Xu, Yu, mInt.mKappa1); 16 | % Xd=Xu; 17 | % Yd=Yu; 18 | 19 | % Rusq=Xu*Xu+Yu*Yu; 20 | % Ru=sqrt(Xu*Xu+Yu*Yu); 21 | % Xd=Xu*(1+mInt.mKappa1*Rusq); 22 | % Yd=Yu*(1+mInt.mKappa1*Rusq); 23 | 24 | 25 | % /* convert from distorted sensor plane coordinates to image coordinates */ 26 | Xi = Xd * mInt.mSx / mGeo.mDpx + mInt.mCx; 27 | Yi = Yd / mGeo.mDpy + mInt.mCy; 28 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/worldToImage.m: -------------------------------------------------------------------------------- 1 | function [Xi Yi]=worldToImage(Xw,Yw,Zw,mR,mT,mInt,mGeo) 2 | 3 | 4 | % /* convert from world coordinates to camera coordinates */ 5 | x=[mR mT]*[Xw;Yw;Zw;1]; 6 | xc = x(1); 7 | yc = x(2); 8 | zc = x(3); 9 | 10 | % /* convert from camera coordinates to undistorted sensor plane coordinates */ 11 | Xu = mInt.mFocal * xc / zc; 12 | Yu = mInt.mFocal * yc / zc; 13 | 14 | % /* convert from undistorted to distorted sensor plane coordinates */ 15 | [Xd Yd]=undistortedToDistortedSensorCoord (Xu, Yu, mInt.mKappa1); 16 | % Xd=Xu; 17 | % Yd=Yu; 18 | 19 | % Rusq=Xu*Xu+Yu*Yu; 20 | % Ru=sqrt(Xu*Xu+Yu*Yu); 21 | % Xd=Xu*(1+mInt.mKappa1*Rusq); 22 | % Yd=Yu*(1+mInt.mKappa1*Rusq); 23 | 24 | 25 | % /* convert from distorted sensor plane coordinates to image coordinates */ 26 | Xi = Xd * mInt.mSx / mGeo.mDpx + mInt.mCx; 27 | Yi = Yd / mGeo.mDpy + mInt.mCy; 28 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/read_gt_dp.m: -------------------------------------------------------------------------------- 1 | close all 2 | clear all 3 | 4 | save_path = 'H:\dataset\ETHZ\bahnhof\gt\bahnhof_ground_truth.mat'; 5 | load('H:\dataset\ETHZ\bahnhof\gt\bahnhof_gt.mat'); 6 | idNum = size(bahnhof.Trajectory, 1); 7 | allNum = 999; 8 | posNum = 0; 9 | 10 | for i = 1:allNum 11 | for j = 1:idNum 12 | frameNum = size(bahnhof.Trajectory(j,1).Frame, 1); 13 | for k = 1:frameNum 14 | frame = bahnhof.Trajectory(j,1).Frame(k,1).ATTRIBUTE.frame_no+1; 15 | if (frame == i) 16 | posNum = posNum + 1; 17 | gt.x(posNum, 1) = bahnhof.Trajectory(j,1).Frame(k,1).ATTRIBUTE.x; 18 | gt.y(posNum, 1) = bahnhof.Trajectory(j,1).Frame(k,1).ATTRIBUTE.y; 19 | gt.w(posNum, 1) = bahnhof.Trajectory(j,1).Frame(k,1).ATTRIBUTE.width; 20 | gt.h(posNum, 1) = bahnhof.Trajectory(j,1).Frame(k,1).ATTRIBUTE.height; 21 | gt.fr(posNum, 1) = i; 22 | gt.vid(posNum, 1) = 3; 23 | end 24 | end 25 | end 26 | end 27 | 28 | save(save_path, 'gt'); 29 | 30 | -------------------------------------------------------------------------------- /trackers/GOG/text_to_image.m: -------------------------------------------------------------------------------- 1 | % this function write contents of "txt" on an image and then returns its image. 2 | % "h" is the texyt height in pixels 3 | % "figNum" is the number for figure. 4 | % note that you may not interacti with matlab while running this command since the figure window should be on the top. 5 | 6 | function bw = text_to_image(txt, h, figNum) 7 | f = h/1.2; 8 | sz1 = round(f*4); 9 | sz2 = round(length(txt)*f*1.5); 10 | r = 1; 11 | if sz2 > 800 12 | r = sz2/800; 13 | sz2 = round(sz2/r); 14 | f = round(f/r); 15 | end 16 | 17 | im1 = ones(sz1, sz2, 3); 18 | flag1 = 0; 19 | if ~exist('figNum') 20 | figNum = ceil((rand*1000)+1); 21 | flag1 = 1; 22 | end 23 | 24 | figure(figNum); 25 | imshow(im1); 26 | text(10,f*3, txt, 'fontsize', f,'color', 'b'); 27 | im2 = getframe; 28 | if flag1 29 | close(figNum); 30 | end 31 | 32 | im2 = im2.cdata; 33 | bw2 = im2bw(im2); 34 | f1 = find(sum(~bw2)); 35 | f2 = find(sum(~bw2')); 36 | x1 = f1(1); 37 | y1 = f2(1); 38 | x2 = f1(end); 39 | y2 = f2(end); 40 | bw = ~bw2(y1:y2, x1:x2); 41 | 42 | if r~=1 43 | bw = im2bw(imresize(double(bw), h/size(bw,1))); 44 | end 45 | 46 | -------------------------------------------------------------------------------- /trackers/GOG/getRotTrans.m: -------------------------------------------------------------------------------- 1 | function [mR mT]=getRotTrans(camPar) 2 | % 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | %%% Rotation Translation %%% 13 | mT=[camPar.mExt.mTx;camPar.mExt.mTy;camPar.mExt.mTz]; 14 | sa = sin(camPar.mExt.mRx); 15 | ca = cos(camPar.mExt.mRx); 16 | sb = sin(camPar.mExt.mRy); 17 | cb = cos(camPar.mExt.mRy); 18 | sg = sin(camPar.mExt.mRz); 19 | cg = cos(camPar.mExt.mRz); 20 | 21 | mR11 = cb * cg; 22 | mR12 = cg * sa * sb - ca * sg; 23 | mR13 = sa * sg + ca * cg * sb; 24 | mR21 = cb * sg; 25 | mR22 = sa * sb * sg + ca * cg; 26 | mR23 = ca * sb * sg - cg * sa; 27 | mR31 = -sb; 28 | mR32 = cb * sa; 29 | mR33 = ca * cb; 30 | 31 | mR=[mR11 mR12 mR13; 32 | mR21 mR22 mR23; 33 | mR31 mR32 mR33]; 34 | end -------------------------------------------------------------------------------- /display/showResults.m: -------------------------------------------------------------------------------- 1 | function showResults(isSeqDisplay, res, sequence) 2 | 3 | if(isSeqDisplay) 4 | sceneInfo.imgFolder = sequence.seqPath; 5 | sceneInfo.imgFileFormat = '%07d.jpg'; 6 | sceneInfo.frameNums = 1:length(sequence.dataset); 7 | sceneInfo.imgHeight = sequence.imgHeight; 8 | sceneInfo.imgWidth = sequence.imgWidth; 9 | 10 | %% Display parameters 11 | sceneInfo.defaultColor = [.1 .2 .9]; 12 | sceneInfo.grey = 0.7*ones(1,3); 13 | 14 | sceneInfo.traceLength = 20; % overlay track from past n frames 15 | sceneInfo.dotSize = 20; 16 | sceneInfo.boxLineWidth = 3; 17 | sceneInfo.traceWidth = 2; 18 | 19 | % what to display 20 | sceneInfo.displayDots = true; % display the trajectory dots 21 | sceneInfo.displayBoxes = true; % display the bounding box of the target 22 | sceneInfo.displayID = true; % display the ID of the target 23 | sceneInfo.displayCropouts = false; % display the border cropouts 24 | sceneInfo.displayConnections = false; % display the connection of the sample target 25 | 26 | displayTrackingResult(sceneInfo, res, sequence.seqName); 27 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/getRotTrans.m: -------------------------------------------------------------------------------- 1 | function [mR mT]=getRotTrans(camPar) 2 | % 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | %%% Rotation Translation %%% 13 | mT=[camPar.mExt.mTx;camPar.mExt.mTy;camPar.mExt.mTz]; 14 | sa = sin(camPar.mExt.mRx); 15 | ca = cos(camPar.mExt.mRx); 16 | sb = sin(camPar.mExt.mRy); 17 | cb = cos(camPar.mExt.mRy); 18 | sg = sin(camPar.mExt.mRz); 19 | cg = cos(camPar.mExt.mRz); 20 | 21 | mR11 = cb * cg; 22 | mR12 = cg * sa * sb - ca * sg; 23 | mR13 = sa * sg + ca * cg * sb; 24 | mR21 = cb * sg; 25 | mR22 = sa * sb * sg + ca * cg; 26 | mR23 = ca * sb * sg - cg * sa; 27 | mR31 = -sb; 28 | mR32 = cb * sa; 29 | mR33 = ca * cb; 30 | 31 | mR=[mR11 mR12 mR13; 32 | mR21 mR22 mR23; 33 | mR31 mR32 mR33]; 34 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/greedy_Pets_detct_generator.m: -------------------------------------------------------------------------------- 1 | clear;clc; 2 | addpath('../../input_trans'); 3 | 4 | outPath1 = '.\pls_detect\PETS\'; 5 | video_name = 'PETS2009-S2L1'; 6 | outName1 = [video_name '_pls_detect.mat']; 7 | out1 = [outPath1 outName1]; 8 | 9 | global sceneInfo opt detections nPoints; 10 | frames=1:795; 11 | sceneInfo=getSceneInfoDCDemo; 12 | opt.cutToTA=0; 13 | [detections, nPoints]=parseDetections(sceneInfo,frames); 14 | [detections, nPoints]=cutDetections(detections,nPoints); 15 | 16 | frameNum = size(detections,2); 17 | count = 1; 18 | 19 | for i = 1:frameNum 20 | i 21 | obj_num = size(detections(i).xi, 2); 22 | for j=1:obj_num 23 | dres.w(count,1) = detections(i).wd(1,j); 24 | dres.h(count,1) = detections(i).ht(1,j); 25 | w = dres.w(count,1); 26 | h = dres.h(count,1); 27 | dres.x(count,1) = detections(i).xi(1,j) - 0.5*w; 28 | dres.y(count,1) = detections(i).yi(1,j) - h; 29 | dres.fr(count,1) = i; 30 | dres.r(count,1) = detections(i).sc(1,j)*3-1.5; 31 | count = count+1; 32 | end 33 | end 34 | 35 | save(out1,'dres'); -------------------------------------------------------------------------------- /eval/classEval.m: -------------------------------------------------------------------------------- 1 | function tendMets = classEval(gtsortdata, ressortdata, allMets, ind, evalClassSet, sequenceName) 2 | 3 | threshold = 0.5; 4 | world = 0; 5 | 6 | for k = 1:length(evalClassSet) 7 | className = evalClassSet{k}; 8 | classID = getClassID(className); 9 | [gtdata, resdata] = selectTrackData(gtsortdata, ressortdata, classID); 10 | if(~isempty(gtdata)) 11 | [metsCLEAR, ~, additionalInfo] = CLEAR_MOT_HUN(gtdata, resdata, threshold, world); 12 | metsID = IDmeasures(gtdata, resdata, threshold, world); 13 | mets = [metsID.IDF1, metsID.IDP, metsID.IDR, metsCLEAR]; 14 | allMets(ind).name = strcat(sequenceName, '(', className, ')'); 15 | allMets(ind).m = mets; 16 | allMets(ind).IDmeasures = metsID; 17 | allMets(ind).additionalInfo = additionalInfo; 18 | tendMets(k) = allMets(ind); 19 | else 20 | allMets(ind).name = strcat(sequenceName, '(', className, ')'); 21 | allMets(ind).m = []; 22 | allMets(ind).IDmeasures = []; 23 | allMets(ind).additionalInfo = []; 24 | tendMets(k) = allMets(ind); 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /utils/camera/worldToImage.m: -------------------------------------------------------------------------------- 1 | function [Xi Yi]=worldToImage(Xw,Yw,Zw,mR,mT,mInt,mGeo) 2 | 3 | % if scalar, just up/downscale = orthographic 4 | if length(mR)==1 5 | Xi=Xw/mR; 6 | Yi=Yw/mR; 7 | else 8 | 9 | % /* convert from world coordinates to camera coordinates */ 10 | x=[mR mT]*[Xw;Yw;Zw;1]; 11 | xc = x(1); 12 | yc = x(2); 13 | zc = x(3); 14 | 15 | % /* convert from camera coordinates to undistorted sensor plane coordinates */ 16 | Xu = mInt.mFocal * xc / zc; 17 | Yu = mInt.mFocal * yc / zc; 18 | 19 | % /* convert from undistorted to distorted sensor plane coordinates */ 20 | [Xd Yd]=undistortedToDistortedSensorCoord (Xu, Yu, mInt.mKappa1); 21 | % Xd=Xu; 22 | % Yd=Yu; 23 | 24 | % Rusq=Xu*Xu+Yu*Yu; 25 | % Ru=sqrt(Xu*Xu+Yu*Yu); 26 | % Xd=Xu*(1+mInt.mKappa1*Rusq); 27 | % Yd=Yu*(1+mInt.mKappa1*Rusq); 28 | 29 | 30 | % /* convert from distorted sensor plane coordinates to image coordinates */ 31 | Xi = Xd * mInt.mSx / mGeo.mDpx + mInt.mCx; 32 | Yi = Yd / mGeo.mDpy + mInt.mCy; 33 | end 34 | end -------------------------------------------------------------------------------- /trackers/GOG/mydetect_objects.m: -------------------------------------------------------------------------------- 1 | function [dres, bboxes] = mydetect_objects(sceneInfo, vid_path) 2 | 3 | n_cores = 4; %% number of cores to use. Matlab doesn't let you use more that 8 cores on a single machine. decrese it if you have less than 8 cores. 4 | n_cores = min(8, n_cores); 5 | if matlabpool('size') ~= n_cores 6 | if matlabpool('size') > 0 7 | matlabpool('close'); 8 | end 9 | matlabpool(n_cores); 10 | end 11 | 12 | dirlist = dir([vid_path '*.jpg']); 13 | 14 | frames=1:length(sceneInfo.frameNums); 15 | [detections nPoints]=parseDetections(sceneInfo, frames); 16 | 17 | parfor i=1:length(dirlist) 18 | display(['frame ' num2str(i)]); 19 | im = imread([vid_path dirlist(i).name]); 20 | 21 | boxes = detect(im, model, thresh); %% running the detector 22 | bbox = getboxes(model, boxes); 23 | bbox 24 | bboxes(i).bbox = nms(bbox, 0.5); %% running non-max-suppression to suppress overlaping weak detections. 25 | end 26 | 27 | dres = bboxes2dres(bboxes); %% converting the data format. 28 | dres.x = dres.x/2; %% compensate doubling image size. 29 | dres.y = dres.y/2; 30 | dres.w = dres.w/2; 31 | dres.h = dres.h/2; 32 | 33 | matlabpool('size'); 34 | 35 | -------------------------------------------------------------------------------- /utils/camera/getRotTrans.m: -------------------------------------------------------------------------------- 1 | function [mR, mT]=getRotTrans(camPar) 2 | % 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | if camPar.ortho 13 | mR=camPar.mR; mT=camPar.mT; 14 | else 15 | %%% Rotation Translation %%% 16 | mT=[camPar.mExt.mTx;camPar.mExt.mTy;camPar.mExt.mTz]; 17 | sa = sin(camPar.mExt.mRx); 18 | ca = cos(camPar.mExt.mRx); 19 | sb = sin(camPar.mExt.mRy); 20 | cb = cos(camPar.mExt.mRy); 21 | sg = sin(camPar.mExt.mRz); 22 | cg = cos(camPar.mExt.mRz); 23 | 24 | mR11 = cb * cg; 25 | mR12 = cg * sa * sb - ca * sg; 26 | mR13 = sa * sg + ca * cg * sb; 27 | mR21 = cb * sg; 28 | mR22 = sa * sb * sg + ca * cg; 29 | mR23 = ca * sb * sg - cg * sa; 30 | mR31 = -sb; 31 | mR32 = cb * sa; 32 | mR33 = ca * cb; 33 | 34 | mR=[mR11 mR12 mR13; 35 | mR21 mR22 mR23; 36 | mR31 mR32 mR33]; 37 | end 38 | end -------------------------------------------------------------------------------- /trackers/GOG/run_tracker.m: -------------------------------------------------------------------------------- 1 | function [res, runTime] = run_tracker(sequence, detections) 2 | 3 | %% setting parameters for tracking 4 | c_en = 12; %% 10 birth cost, has no influence on the result 5 | c_ex = 9; %% 10 death cost, has no influence on the result 6 | c_ij = 0; %% 0 transition cost 7 | betta = 0.2; %% 0.2 betta, increase will have less tracks, for every single detection 8 | max_it = inf; %% inf max number of iterations (max number of tracks) 9 | thr_cost = 15; %% 18 max acceptable cost for a track (increase it to have more tracks.), for every tracklet 19.8 10 | 11 | time_start = tic; 12 | %% Run object/human detector on all frames. 13 | frameNums = 1:length(sequence.dataset); 14 | dres = greedy_detect_generator(detections, frameNums); 15 | 16 | %% Running tracking algorithms 17 | dres_dp_nms = tracking_dp(dres, c_en, c_ex, c_ij, betta, thr_cost, max_it, 1); 18 | dres_dp_nms.r = -dres_dp_nms.id; 19 | runTime = toc(time_start); 20 | 21 | %% save the tracking result 22 | bboxes_tracked = dres2bboxes(dres_dp_nms, numel(frameNums)); %% we are visualizing the "DP with NMS in the lop" results. Can be changed to show the results of DP or push relabel algorithm. 23 | res = saveResTxt(bboxes_tracked); -------------------------------------------------------------------------------- /trackers/GOG/find_overlap.m: -------------------------------------------------------------------------------- 1 | function [ov ov_n1 ov_n2] = find_overlap(dres1, f1, dres2, f2) 2 | %%f2 can be an array and f1 should be a scalar. 3 | %%% this will find the overlap between dres1(f1) (only one) and all detection windows in dres2(f2(:)) 4 | 5 | f2=f2(:)'; 6 | n = length(f2); 7 | 8 | cx1 = dres1.x(f1); 9 | cx2 = dres1.x(f1)+dres1.w(f1)-1; 10 | cy1 = dres1.y(f1); 11 | cy2 = dres1.y(f1)+dres1.h(f1)-1; 12 | 13 | gx1 = dres2.x(f2); 14 | gx2 = dres2.x(f2)+dres2.w(f2)-1; 15 | gy1 = dres2.y(f2); 16 | gy2 = dres2.y(f2)+dres2.h(f2)-1; 17 | 18 | ca = dres1.h(f1).*dres1.w(f1); %% area 19 | ga = dres2.h(f2).*dres2.w(f2); 20 | 21 | %%% find the overlapping area 22 | xx1 = max(cx1, gx1); 23 | yy1 = max(cy1, gy1); 24 | xx2 = min(cx2, gx2); 25 | yy2 = min(cy2, gy2); 26 | w = xx2-xx1+1; 27 | h = yy2-yy1+1; 28 | 29 | inds = find((w > 0) .* (h > 0)); %% real overlap 30 | ov = zeros(1, n); 31 | ov_n1 = zeros(1, n); 32 | ov_n2 = zeros(1, n); 33 | inter = w(ff).*h(inds); %% area of overlap 34 | u = ca + ga(inds) - w(inds).*h(inds); %% area of union 35 | ov(ff) = inter ./ u; %% intersection / union 36 | ov_n1(ff) = inter / ca; %% intersection / area in dres1 37 | ov_n2(ff) = inter ./ ga(ff); %% intersection / area in dres2 38 | 39 | -------------------------------------------------------------------------------- /trackers/GOG/calc_overlap.m: -------------------------------------------------------------------------------- 1 | function [ov ov_n1 ov_n2] = calc_overlap(dres1, f1, dres2, f2) 2 | %%f2 can be an array and f1 should be a scalar. 3 | %%% this will find the overlap between dres1(f1) (only one) and all detection windows in dres2(f2(:)) 4 | 5 | f2=f2(:)'; 6 | n = length(f2); 7 | 8 | cx1 = dres1.x(f1); 9 | cx2 = dres1.x(f1)+dres1.w(f1)-1; 10 | cy1 = dres1.y(f1); 11 | cy2 = dres1.y(f1)+dres1.h(f1)-1; 12 | 13 | gx1 = dres2.x(f2); 14 | gx2 = dres2.x(f2)+dres2.w(f2)-1; 15 | gy1 = dres2.y(f2); 16 | gy2 = dres2.y(f2)+dres2.h(f2)-1; 17 | 18 | ca = dres1.h(f1).*dres1.w(f1); %% area 19 | ga = dres2.h(f2).*dres2.w(f2); 20 | 21 | %%% find the overlapping area 22 | xx1 = max(cx1, gx1); 23 | yy1 = max(cy1, gy1); 24 | xx2 = min(cx2, gx2); 25 | yy2 = min(cy2, gy2); 26 | w = xx2-xx1+1; 27 | h = yy2-yy1+1; 28 | 29 | inds = find((w > 0) .* (h > 0)); %% real overlap 30 | ov = zeros(1, n); 31 | ov_n1 = zeros(1, n); 32 | ov_n2 = zeros(1, n); 33 | inter = w(inds).*h(inds); %% area of overlap 34 | u = ca + ga(inds) - w(inds).*h(inds); %% area of union 35 | ov(inds) = inter ./ u; %% intersection / union 36 | ov_n1(inds) = inter / ca; %% intersection / area in dres1 37 | ov_n2(inds) = inter ./ ga(inds); %% intersection / area in dres2 38 | 39 | -------------------------------------------------------------------------------- /utils/ismember_mex.c: -------------------------------------------------------------------------------- 1 | /* 2 | *Expects two sorted arrays !!! 3 | * 4 | *Example: 5 | * >>ismember_mex( [1 3 5], [1 2 3 4 6 7 8] ) 6 | *ans = 7 | 8 | 1 9 | 1 10 | 0 11 | */ 12 | 13 | #include 14 | #include "mex.h" 15 | 16 | #include 17 | 18 | void mexFunction(int nlhs, mxArray *plhs[], 19 | int nrhs, const mxArray *prhs[]) 20 | { 21 | double *in1, *in2, *locb; 22 | mxLogical *out; 23 | int N,M; 24 | 25 | in1 = mxGetPr(prhs[0]); 26 | in2 = mxGetPr(prhs[1]); 27 | 28 | N = (int)mxGetNumberOfElements(prhs[0]); 29 | M = (int)mxGetNumberOfElements(prhs[1]); 30 | 31 | plhs[0] = mxCreateLogicalMatrix(N, 1); 32 | out = mxGetLogicals(plhs[0]); 33 | plhs[1] = mxCreateDoubleMatrix(N, 1, mxREAL); 34 | locb = mxGetPr(plhs[1]); 35 | int pos = 0; 36 | int i = 0; 37 | while (i < N && pos < M) 38 | { 39 | while (pos < M) 40 | { 41 | if (in1[i] == in2[pos]) 42 | { 43 | out[i] = true; 44 | locb[i] = pos + 1; 45 | pos++; 46 | i++; 47 | break; 48 | } 49 | else if (in1[i] < in2[pos]) 50 | { 51 | out[i] = false; 52 | locb[i] = 0; 53 | i++; 54 | if (i == N) break; 55 | } 56 | else 57 | { 58 | pos++; 59 | } 60 | } 61 | 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /trackers/GOG/utils/cutDetections.m: -------------------------------------------------------------------------------- 1 | function [detections nDets]=cutDetections(detections,nDets) 2 | % remove all detections that are 3 | % outside the tracking area 4 | % 5 | % (C) Anton Andriyenko, 2012 6 | % 7 | % The code may be used free of charge for non-commercial and 8 | % educational purposes, the only requirement is that this text is 9 | % preserved within the derivative work. For any other purpose you 10 | % must contact the authors for permission. This code may not be 11 | % redistributed without written permission from the authors. 12 | % 13 | 14 | global sceneInfo opt 15 | if opt.track3d && opt.cutToTA 16 | F=length(detections); 17 | Field = fieldnames(detections); 18 | nDets=0; 19 | for t=1:F 20 | tokeep=find(detections(t).xw>=sceneInfo.trackingArea(1) & ... 21 | detections(t).xw<=sceneInfo.trackingArea(2) & ... 22 | detections(t).yw>=sceneInfo.trackingArea(3) & ... 23 | detections(t).yw<=sceneInfo.trackingArea(4)); 24 | 25 | nDets=nDets+length(tokeep); 26 | 27 | for iField = 1:length(Field) 28 | fcontent=detections(t).(char(Field(iField))); 29 | fcontent=fcontent(tokeep); 30 | detections(t).(char(Field(iField)))=fcontent; 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /eval/nms.m: -------------------------------------------------------------------------------- 1 | function pick = nms(boxes, threshold) 2 | % boxes: m x 5, indicates m detections with the format [left top w h score] 3 | % threshold: the threshold of IOU score 4 | 5 | if isempty(boxes) 6 | pick = []; 7 | return; 8 | end 9 | 10 | % get the detections 11 | x1 = boxes(:,1); 12 | y1 = boxes(:,2); 13 | x2 = boxes(:,1) + boxes(:,3) - 1; 14 | y2 = boxes(:,2) + boxes(:,4) - 1; 15 | s = boxes(:,5); 16 | 17 | % calculate the area of detections 18 | area = (x2-x1+1) .* (y2-y1+1); 19 | 20 | % sort the detections 21 | [~, I] = sort(s); 22 | 23 | % init 24 | pick = s*0; 25 | counter = 1; 26 | 27 | % remove the redundant detections 28 | while ~isempty(I) 29 | last = length(I); % the number of left detections 30 | i = I(last);% pick the detection with the maximal confidense score 31 | pick(counter) = i; 32 | counter = counter + 1; 33 | 34 | % calculate IOU score 35 | xx1 = max(x1(i), x1(I(1:last-1))); 36 | yy1 = max(y1(i), y1(I(1:last-1))); 37 | xx2 = min(x2(i), x2(I(1:last-1))); 38 | yy2 = min(y2(i), y2(I(1:last-1))); 39 | w = max(0.0, xx2-xx1+1); 40 | h = max(0.0, yy2-yy1+1); 41 | inter = w.*h; 42 | o = inter ./ (area(i) + area(I(1:last-1)) - inter); 43 | 44 | % keep the detections if the IOU score is less than the threshold 45 | I = I(o<=threshold); 46 | end 47 | pick = pick(1:(counter-1)); 48 | -------------------------------------------------------------------------------- /eval/selectTrackData.m: -------------------------------------------------------------------------------- 1 | function [gtdata, resdata] = selectTrackData(gtsortdata, ressortdata, classID) 2 | 3 | % object category: 4 | % ignored |pedestrian| person| bicycle| car| van| truck| tricycle| awning-tricycle | bus| motor| others 5 | % 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 6 | 7 | switch(classID) 8 | case 1 9 | gtdata = gtsortdata.pedestrian; 10 | resdata = ressortdata.pedestrian; 11 | case 2 12 | gtdata = gtsortdata.person; 13 | resdata = ressortdata.person; 14 | case 3 15 | gtdata = gtsortdata.bicycle; 16 | resdata = ressortdata.bicycle; 17 | case 4 18 | gtdata = gtsortdata.car; 19 | resdata = ressortdata.car; 20 | case 5 21 | gtdata = gtsortdata.van; 22 | resdata = ressortdata.van; 23 | case 6 24 | gtdata = gtsortdata.truck; 25 | resdata = ressortdata.truck; 26 | case 7 27 | gtdata = gtsortdata.tricycle; 28 | resdata = ressortdata.tricycle; 29 | case 8 30 | gtdata = gtsortdata.awningtricycle; 31 | resdata = ressortdata.awningtricycle; 32 | case 9 33 | gtdata = gtsortdata.bus; 34 | resdata = ressortdata.bus; 35 | case 10 36 | gtdata = gtsortdata.motor; 37 | resdata = ressortdata.motor; 38 | end -------------------------------------------------------------------------------- /utils/external/iniconfig/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2010, Evgeny Prilepin aka Iroln 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | * Redistributions in binary form must reproduce the above copyright 11 | notice, this list of conditions and the following disclaimer in 12 | the documentation and/or other materials provided with the distribution 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 18 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | POSSIBILITY OF SUCH DAMAGE. 25 | -------------------------------------------------------------------------------- /trackers/GOG/README.txt: -------------------------------------------------------------------------------- 1 | This is an implementation of our CVPR 2011 paper: 2 | 3 | Hamed Pirsiavash, Deva Ramanan, Charless C. Fowlkes, "Globally-Optimal Greedy Algorithms for Tracking a Variable Number of Objects," to appear in International Conference on Computer vision and Pattern Recognition (CVPR'11), Jun 2011. 4 | 5 | We are using matlab/C implementation of part based object detector from http://people.cs.uchicago.edu/~pff/latent/ 6 | and also C implementation of push-relabel algorithm from http://www.igsystems.com/cs2/index.html (please note the copyright file in "3rd_party/cs2/") 7 | 8 | To run, please call "main.m". 9 | 1. It will download ETHZ dataset (481MB) if not available (may take 30 minutes) 10 | 2. It will run part-based object detector to detect humans if the result is no available in the cache (may take an hour using 8 CPU cores). You don't need to run it since the result is included in the cache. 11 | 3. It will build the graph 12 | 4. It will call three tracking algorithms(DP, DP with NMS in the loop, and push-relabel) and plot the scores.(Figure 7 on the paper) 13 | 5. It will draw detected bounding boxes for the result of "DP with NMS in the loop" algorithm and make a new video. (you may change it to show the results of DP or push-relabel algorithm) 14 | 15 | Please note that since "successive shortest path (SSP)" and "push-relabel" algorithms are both optimum and have identical results, we do not include the implementation of SSP. 16 | 17 | 18 | -------------------------------------------------------------------------------- /evalMOT.m: -------------------------------------------------------------------------------- 1 | clc; 2 | clear all;close all; 3 | warning off all; 4 | 5 | % add toolboxes 6 | addpath('display'); 7 | addpath('eval'); 8 | addpath(genpath('utils')); 9 | 10 | datasetPath = '..\VisDrone2018-MOT-test-challenge\'; % dataset path 11 | detPath = '..\FasterRCNN-MOT-detections\test-challenge\'; % detection input path 12 | resPath = '..\test-challenge_MOT_results\'; % result path 13 | isSeqDisplay = false; % flag to display the detections 14 | isNMS = true; % flag to conduct NMS 15 | nmsThre = 0.6; % threshold of NMS 16 | 17 | evalTask = 'Task4b'; % the evaluated task, i.e, Task4a without detection input and Task4b with detection input 18 | trackerName = 'GOG'; % the tracker name 19 | evalClassSet = {'car','bus','truck','pedestrian','van'}; % the set of evaluated object category 20 | threSet = [0.5, 0.5, 0.5, 0.5, 0.5]; % the detection score threshold 21 | 22 | gtPath = fullfile(datasetPath, 'annotations'); % annotation path 23 | seqPath = fullfile(datasetPath, 'sequences'); % sequence path 24 | 25 | %% run the tracker 26 | runTrackerAllClass(isSeqDisplay, isNMS, detPath, resPath, seqPath, evalClassSet, threSet, nmsThre, trackerName); 27 | 28 | %% evaluate the tracker 29 | if(strcmp(evalTask, 'Task4a')) 30 | [ap, recall, precision] = evaluateTrackA(seqPath, resPath, gtPath, evalClassSet); 31 | elseif(strcmp(evalTask, 'Task4b')) 32 | [tendallMets, allresult] = evaluateTrackB(seqPath, resPath, gtPath, evalClassSet); 33 | end 34 | -------------------------------------------------------------------------------- /trackers/GOG/detect_objects.m: -------------------------------------------------------------------------------- 1 | function [dres bboxes] = detect_objects(vid_path) 2 | % vid_path = 'data/seq03-img-left/'; 3 | thresh = -2; %% threshod on SVM response in human detection, we'll have more detections by decreasing it. 4 | 5 | n_cores = 8; %% number of cores to use. Matlab doesn't let you use more that 8 cores on a single machine. decrese it if you have less than 8 cores. 6 | n_cores = min(8, n_cores); 7 | if matlabpool('size') ~= n_cores 8 | if matlabpool('size') > 0 9 | matlabpool('close'); 10 | end 11 | matlabpool(n_cores); 12 | end 13 | 14 | dirlist = dir([vid_path '*.png']); 15 | 16 | tmp = load ('3rd_party/voc-release3.1/INRIA/inria_final.mat'); %% load the model for human. This can be changed to any of those 20 objects in PASCAL competition. 17 | model= tmp.model; 18 | clear tmp 19 | 20 | parfor i=1:length(dirlist) 21 | display(['frame ' num2str(i)]); 22 | im = imread([vid_path dirlist(i).name]); 23 | im = imresize(im,2); %% double the image size to detect small objects. 24 | 25 | boxes = detect(im, model, thresh); %% running the detector 26 | bbox = getboxes(model, boxes); 27 | 28 | bboxes(i).bbox = nms(bbox, 0.5); %% running non-max-suppression to suppress overlaping weak detections. 29 | end 30 | dres = bboxes2dres(bboxes); %% converting the data format. 31 | dres.x = dres.x/2; %% compensate doubling image size. 32 | dres.y = dres.y/2; 33 | dres.w = dres.w/2; 34 | dres.h = dres.h/2; 35 | 36 | matlabpool('size'); 37 | 38 | -------------------------------------------------------------------------------- /eval/dropObjects.m: -------------------------------------------------------------------------------- 1 | function newdet = dropObjects(det, gt, imgHeight, imgWidth) 2 | %% drop objects in ignored region or labeled as "others" 3 | newdet = []; 4 | numFr = max(det(:,1)); 5 | for fr = 1:numFr 6 | % parse objects 7 | idxFr = det(:,1) == fr & (det(:, 8) ~= 0 & det(:, 8) ~= 11); 8 | curdet = det(idxFr,:); 9 | % parse ignored regions 10 | idxIgr = gt(:,1) == fr & (gt(:, 8) == 0 | gt(:,8) == 11); 11 | igrRegion = max(1, round(gt(idxIgr, 3:6))); 12 | if(~isempty(igrRegion)) 13 | igrMap = zeros(imgHeight, imgWidth); 14 | numIgr = size(igrRegion,1); 15 | for j = 1:numIgr 16 | igrMap(igrRegion(j,2):min(imgHeight,igrRegion(j,2)+igrRegion(j,4)),igrRegion(j,1):min(imgWidth,igrRegion(j,1)+igrRegion(j,3))) = 1; 17 | end 18 | intIgrMap = createIntImg(double(igrMap)); 19 | idxLeft = []; 20 | for i = 1:size(curdet, 1) 21 | pos = max(1,round(curdet(i,3:6))); 22 | x = max(1, min(imgWidth, pos(1))); 23 | y = max(1, min(imgHeight, pos(2))); 24 | w = pos(3); 25 | h = pos(4); 26 | tl = intIgrMap(y, x); 27 | tr = intIgrMap(y, min(imgWidth,x+w)); 28 | bl = intIgrMap(max(1,min(imgHeight,y+h)), x); 29 | br = intIgrMap(max(1,min(imgHeight,y+h)), min(imgWidth,x+w)); 30 | igrVal = tl + br - tr - bl; 31 | if(igrVal/(h*w)<0.5) 32 | idxLeft = cat(1, idxLeft, i); 33 | end 34 | end 35 | curdet = curdet(idxLeft, :); 36 | end 37 | newdet = cat(1, newdet, curdet); 38 | end 39 | -------------------------------------------------------------------------------- /trackers/GOG/show_bbox_on_image.m: -------------------------------------------------------------------------------- 1 | % drawss bbox on an image (im1) and returns the image file 2 | % bbox: a matrix of size n*5 3 | % default line width (lw) is 2 4 | function im1 = show_bbox_on_image(im1, bbox, bws, col, lw) 5 | 6 | if ~exist('lw') 7 | lw = 2; 8 | end 9 | 10 | m1 = floor((lw-1)/2); %% reduce 1 for the pixel itself 11 | m2 = ceil((lw-1)/2); 12 | 13 | [sz1 sz2 sz3] = size(im1); 14 | sz = size(bbox, 1); 15 | 16 | bbox = round(bbox); 17 | 18 | for j = floor(size(bbox,2)/4):-1:1 %%for all parts 19 | for i = 1:sz 20 | x1 = bbox(i, (j-1)*4+1); 21 | y1 = bbox(i, (j-1)*4+2); 22 | x2 = bbox(i, (j-1)*4+3); 23 | y2 = bbox(i, (j-1)*4+4); 24 | 25 | for k = 1:3 %% RGB channels 26 | im1(max(1,y1-m1):min(sz1,y1+m2), max(1,x1):min(sz2,x2), k) = col(k, bbox(i,end)); 27 | im1(max(1,y2-m1):min(sz1,y2+m2), max(1,x1):min(sz2,x2), k) = col(k, bbox(i,end)); 28 | im1(max(1,y1):min(sz1,y2), max(1,x1-m1):min(sz2,x1+m2), k) = col(k, bbox(i,end)); 29 | im1(max(1,y1):min(sz1,y2), max(1,x2-m1):min(sz2,x2+m2), k) = col(k, bbox(i,end)); 30 | end 31 | if ~isempty(bws) %% add text if needed 32 | col1 = col(:, bbox(i, end)); 33 | im1 = show_text_on_image(im1, num2str(bbox(i,end)), col1, min(max(x1-10,1),sz2), min(max(y1-20,1),sz1), 20, bws(bbox(i,end)).bw); 34 | end 35 | end 36 | end 37 | 38 | function im = show_text_on_image(im, txt, col, x, y, h, bw) 39 | [sz11 sz22 sz33] =size(im); 40 | 41 | [sz1 sz2] = size(bw); 42 | y2 = min(y+sz1-1, sz11); 43 | x2 = min(x+sz2-1, sz22); 44 | 45 | for k = 1:3 %% RGB channels 46 | im(y2-sz1+1:y2, x2-sz2+1:x2, k) = (1-bw) * col(k); 47 | end 48 | 49 | 50 | -------------------------------------------------------------------------------- /utils/printMetricsDet.m: -------------------------------------------------------------------------------- 1 | function printMetricsDet(metrics, metricsInfo, dispHeader,dispMetrics,padChar) 2 | % print metrics 3 | % 4 | % ... 5 | % 6 | 7 | % default names 8 | if nargin==1 9 | 10 | metricsInfo.names.long = {'Recall','Precision','False Alarm Rate', ... 11 | 'Ground Truth', 'True Positives', 'False Positives', 'False Negatives', 'MODA','MODP'}; 12 | 13 | metricsInfo.names.short = {'Rcll','Prcn','FAR', ... 14 | 'GT', 'TP', 'FP', 'FN', 'MODA','MODP'}; 15 | 16 | metricsInfo.widths.long = [6 9 16 15 15 15 15 5 5]; 17 | metricsInfo.widths.short = [5 5 5 6 6 6 6 5 5]; 18 | 19 | metricsInfo.format.long = {'.1f','.1f','.2f', ... 20 | 'i','i','i','i', '.1f','.1f'}; 21 | 22 | metricsInfo.format.short=metricsInfo.format.long; 23 | end 24 | 25 | namesToDisplay=metricsInfo.names.long; 26 | widthsToDisplay=metricsInfo.widths.long; 27 | formatToDisplay=metricsInfo.format.long; 28 | 29 | namesToDisplay=metricsInfo.names.short; 30 | widthsToDisplay=metricsInfo.widths.short; 31 | formatToDisplay=metricsInfo.format.short; 32 | 33 | if nargin<3, dispHeader=1; end 34 | if nargin<4 35 | dispMetrics=1:length(metrics); 36 | end 37 | if nargin<5 38 | padChar={' ','|',' ',' ',' ',' ','|',' ',' '}; 39 | end 40 | 41 | if dispHeader 42 | for m=dispMetrics 43 | printString=sprintf('fprintf(''%%%is%s'',char(namesToDisplay(m)))',widthsToDisplay(m),char(padChar(m))); 44 | eval(printString) 45 | end 46 | fprintf('\n'); 47 | end 48 | 49 | for m=dispMetrics 50 | printString=sprintf('fprintf(''%%%i%s%s'',metrics(m))',widthsToDisplay(m),char(formatToDisplay(m)),char(padChar(m))); 51 | eval(printString) 52 | end 53 | 54 | % if standard, new line 55 | if nargin<4 56 | fprintf('\n'); 57 | end -------------------------------------------------------------------------------- /trackers/GOG/saveStateInfo.m: -------------------------------------------------------------------------------- 1 | function stateInfo = saveStateInfo(bboxes_tracked) 2 | 3 | frame_num = size(bboxes_tracked, 2); 4 | index = 1; 5 | 6 | for frame = 1:frame_num 7 | bboxes = bboxes_tracked(1,frame).bbox; 8 | id_num = size(bboxes, 1); 9 | for id = 1:id_num 10 | track_result(index,1) = bboxes(id, 1); 11 | track_result(index,2) = bboxes(id, 2); 12 | track_result(index,3) = bboxes(id, 3) - bboxes(id, 1); 13 | track_result(index,4) = bboxes(id, 4) - bboxes(id, 2); 14 | track_result(index,5) = frame; 15 | track_result(index,6) = bboxes(id, 5); 16 | index = index + 1; 17 | end 18 | end 19 | 20 | sorted_result = sortrows(track_result,6); 21 | 22 | stateInfo.F = frame_num; 23 | stateInfo.frameNums = 1:frame_num; 24 | detect_num = size(sorted_result,1); 25 | index = 0; 26 | cur_id = -1; 27 | 28 | for i = 1:detect_num 29 | if (cur_id ~= sorted_result(i,6)) 30 | cur_id = sorted_result(i,6); 31 | index = index + 1; 32 | stateInfo.X(:,index) = zeros(frame_num,1); 33 | stateInfo.Y(:,index) = zeros(frame_num,1); 34 | stateInfo.Xi(:,index) = zeros(frame_num,1); 35 | stateInfo.Yi(:,index) = zeros(frame_num,1); 36 | stateInfo.W(:,index) = zeros(frame_num,1); 37 | stateInfo.H(:,index) = zeros(frame_num,1); 38 | end 39 | bbox = sorted_result(i,:); 40 | n = bbox(1,5); 41 | stateInfo.X(n,index) = bbox(1,1)+0.5*bbox(1,3); 42 | stateInfo.Y(n,index) = bbox(1,2)+bbox(1,4); 43 | stateInfo.Xi(n,index) = stateInfo.X(n,index); 44 | stateInfo.Yi(n,index) = stateInfo.Y(n,index); 45 | stateInfo.W(n,index) = bbox(1,3); 46 | stateInfo.H(n,index) = bbox(1,4); 47 | end -------------------------------------------------------------------------------- /display/displayTrackingResult.m: -------------------------------------------------------------------------------- 1 | function displayTrackingResult(sceneInfo, res, seqName) 2 | % Display Tracking Result 3 | % 4 | % Take scene information sceneInfo and 5 | % the tracking result from stateInfo 6 | % 7 | % 8 | % (C) Anton Andriyenko, 2012 9 | % 10 | % The code may be used free of charge for non-commercial and 11 | % educational purposes, the only requirement is that this text is 12 | % preserved within the derivative work. For any other purpose you 13 | % must contact the authors for permission. This code may not be 14 | % redistributed without written permission from the authors. 15 | 16 | %% convert res to stateInfo 17 | stateInfo = []; 18 | stateInfo.F = max(sceneInfo.frameNums); 19 | stateInfo.frameNums = sceneInfo.frameNums; 20 | index = 0; 21 | cur_id = -1; 22 | 23 | res = sortrows(res,2); 24 | 25 | for i = 1:size(res,1) 26 | if (cur_id ~= res(i,2)) 27 | cur_id = res(i,2); 28 | index = index + 1; 29 | stateInfo.X(:,index) = zeros(stateInfo.F,1); 30 | stateInfo.Y(:,index) = zeros(stateInfo.F,1); 31 | stateInfo.Xi(:,index) = zeros(stateInfo.F,1); 32 | stateInfo.Yi(:,index) = zeros(stateInfo.F,1); 33 | stateInfo.W(:,index) = zeros(stateInfo.F,1); 34 | stateInfo.H(:,index) = zeros(stateInfo.F,1); 35 | end 36 | bbox = res(i,:); 37 | n = bbox(1); 38 | stateInfo.X(n,index) = bbox(3)+0.5*bbox(5); 39 | stateInfo.Y(n,index) = bbox(4)+bbox(6); 40 | stateInfo.Xi(n,index) = stateInfo.X(n,index); 41 | stateInfo.Yi(n,index) = stateInfo.Y(n,index); 42 | stateInfo.W(n,index) = bbox(5); 43 | stateInfo.H(n,index) = bbox(6); 44 | end 45 | 46 | reopenFig(['Tracking Results of Sequence ' seqName]); 47 | displayBBoxes(sceneInfo, stateInfo); -------------------------------------------------------------------------------- /trackers/GOG/score.m: -------------------------------------------------------------------------------- 1 | function [missr, fppi] = score(c, g, n) 2 | 3 | thr = 0.5; 4 | 5 | if isempty(c) || isempty(g), 6 | missr = 1; 7 | fppi = inf; 8 | prec = 0; 9 | rec = 0; 10 | ap = 0; 11 | return; 12 | end 13 | 14 | r = c.r; 15 | pos = zeros(length(c.x), 1); 16 | 17 | %%% find positives 18 | for fr = min(c.fr):max(c.fr) 19 | I = find(c.fr == fr); 20 | J = find(g.fr == fr); 21 | [v,ind] = sort(r(I)); 22 | I = I(ind); 23 | 24 | while ~isempty(I) && ~isempty(J), 25 | i = I(end); %% Select highest scoring candidate 26 | ov = calc_overlap(c,i,g,J); %% Search for an unclaimed positive 27 | [val, ind] = max(ov); 28 | if val > thr, 29 | pos(i) = 1; 30 | J(ind) = []; 31 | end 32 | I(end) = []; 33 | end 34 | end 35 | 36 | % remove false-positives that overlap with "people" in ground truth 37 | keep = logical(ones(size(c.x))); 38 | for fr = min(c.fr):max(c.fr) 39 | I = find(c.fr == fr & pos == 0); 40 | J = find(n.fr == fr); 41 | [v,ind] = sort(r(I)); 42 | I = I(ind); 43 | 44 | while ~isempty(I) && ~isempty(J), 45 | i = I(end); %% Select highest scoring candidate 46 | ov = calc_overlap(c,i,n,J); %% Search for a positive on "people" area. 47 | [val,ind] = max(ov); 48 | if val > thr, 49 | keep(i) = 0; %% ignore it completely since it overlaps with "people" 50 | J(ind) = []; 51 | end 52 | I(end) = []; 53 | end 54 | end 55 | 56 | r = r(keep); 57 | pos = pos(keep); 58 | 59 | [r, I] = sort(r,'descend'); 60 | pos = pos(I); 61 | fp = cumsum(~pos); 62 | tp = cumsum(pos); 63 | rec = tp/length(g.x); 64 | prec = tp./(fp+tp); 65 | 66 | nfrs = length(unique(c.fr)); 67 | % nfrs = max(c.fr) - min(c.fr) + 1; 68 | missr = 1-rec; 69 | fppi = fp / nfrs; 70 | 71 | -------------------------------------------------------------------------------- /trackers/GOG/imageToWorld.m: -------------------------------------------------------------------------------- 1 | function [Xw Yw Zw]=imageToWorld(Xi, Yi, camPar) 2 | 3 | mGeo=camPar.mGeo; 4 | mExt=camPar.mExt; 5 | mInt=camPar.mInt; 6 | 7 | mTx=mExt.mTx; 8 | mTy=mExt.mTy; 9 | mTz=mExt.mTz; 10 | 11 | mT=[mExt.mTx;mExt.mTy;mExt.mTz]; 12 | 13 | %% internal init 14 | sa = sin(mExt.mRx); 15 | ca = cos(mExt.mRx); 16 | sb = sin(mExt.mRy); 17 | cb = cos(mExt.mRy); 18 | sg = sin(mExt.mRz); 19 | cg = cos(mExt.mRz); 20 | 21 | mR11 = cb * cg; 22 | mR12 = cg * sa * sb - ca * sg; 23 | mR13 = sa * sg + ca * cg * sb; 24 | mR21 = cb * sg; 25 | mR22 = sa * sb * sg + ca * cg; 26 | mR23 = ca * sb * sg - cg * sa; 27 | mR31 = -sb; 28 | mR32 = cb * sa; 29 | mR33 = ca * cb; 30 | 31 | 32 | 33 | % /* convert from image to distorted sensor coordinates */ 34 | Xd = mGeo.mDpx * (Xi - mInt.mCx) / mInt.mSx; 35 | Yd = mGeo.mDpy * (Yi - mInt.mCy); 36 | 37 | % /* convert from distorted sensor to undistorted sensor plane coordinates */ 38 | [Xu Yu]=distortedToUndistortedSensorCoord (Xd, Yd, mInt.mKappa1); 39 | 40 | % /* calculate the corresponding xw and yw world coordinates */ 41 | % /* (these equations were derived by simply inverting */ 42 | % /* the perspective projection equations using Macsyma) */ 43 | Zw=0; 44 | common_denominator = ((mR11 * mR32 - mR12 * mR31) * Yu + ... 45 | (mR22 * mR31 - mR21 * mR32) * Xu - ... 46 | mInt.mFocal * mR11 * mR22 + mInt.mFocal * mR12 * mR21); 47 | 48 | Xw = (((mR12 * mR33 - mR13 * mR32) * Yu + ... 49 | (mR23 * mR32 - mR22 * mR33) * Xu - ... 50 | mInt.mFocal * mR12 * mR23 + mInt.mFocal * mR13 * mR22) * Zw + ... 51 | (mR12 * mTz - mR32 * mTx) * Yu + ... 52 | (mR32 * mTy - mR22 * mTz) * Xu - ... 53 | mInt.mFocal * mR12 * mTy + mInt.mFocal * mR22 * mTx) / common_denominator; 54 | 55 | Yw = -(((mR11 * mR33 - mR13 * mR31) * Yu + ... 56 | (mR23 * mR31 - mR21 * mR33) * Xu - ... 57 | mInt.mFocal * mR11 * mR23 + mInt.mFocal * mR13 * mR21) * Zw + ... 58 | (mR11 * mTz - mR31 * mTx) * Yu + ... 59 | (mR31 * mTy - mR21 * mTz) * Xu - ... 60 | mInt.mFocal * mR11 * mTy + mInt.mFocal * mR21 * mTx) / common_denominator; 61 | 62 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/imageToWorld.m: -------------------------------------------------------------------------------- 1 | function [Xw Yw Zw]=imageToWorld(Xi, Yi, camPar) 2 | 3 | mGeo=camPar.mGeo; 4 | mExt=camPar.mExt; 5 | mInt=camPar.mInt; 6 | 7 | mTx=mExt.mTx; 8 | mTy=mExt.mTy; 9 | mTz=mExt.mTz; 10 | 11 | mT=[mExt.mTx;mExt.mTy;mExt.mTz]; 12 | 13 | %% internal init 14 | sa = sin(mExt.mRx); 15 | ca = cos(mExt.mRx); 16 | sb = sin(mExt.mRy); 17 | cb = cos(mExt.mRy); 18 | sg = sin(mExt.mRz); 19 | cg = cos(mExt.mRz); 20 | 21 | mR11 = cb * cg; 22 | mR12 = cg * sa * sb - ca * sg; 23 | mR13 = sa * sg + ca * cg * sb; 24 | mR21 = cb * sg; 25 | mR22 = sa * sb * sg + ca * cg; 26 | mR23 = ca * sb * sg - cg * sa; 27 | mR31 = -sb; 28 | mR32 = cb * sa; 29 | mR33 = ca * cb; 30 | 31 | 32 | 33 | % /* convert from image to distorted sensor coordinates */ 34 | Xd = mGeo.mDpx * (Xi - mInt.mCx) / mInt.mSx; 35 | Yd = mGeo.mDpy * (Yi - mInt.mCy); 36 | 37 | % /* convert from distorted sensor to undistorted sensor plane coordinates */ 38 | [Xu Yu]=distortedToUndistortedSensorCoord (Xd, Yd, mInt.mKappa1); 39 | 40 | % /* calculate the corresponding xw and yw world coordinates */ 41 | % /* (these equations were derived by simply inverting */ 42 | % /* the perspective projection equations using Macsyma) */ 43 | Zw=0; 44 | common_denominator = ((mR11 * mR32 - mR12 * mR31) * Yu + ... 45 | (mR22 * mR31 - mR21 * mR32) * Xu - ... 46 | mInt.mFocal * mR11 * mR22 + mInt.mFocal * mR12 * mR21); 47 | 48 | Xw = (((mR12 * mR33 - mR13 * mR32) * Yu + ... 49 | (mR23 * mR32 - mR22 * mR33) * Xu - ... 50 | mInt.mFocal * mR12 * mR23 + mInt.mFocal * mR13 * mR22) * Zw + ... 51 | (mR12 * mTz - mR32 * mTx) * Yu + ... 52 | (mR32 * mTy - mR22 * mTz) * Xu - ... 53 | mInt.mFocal * mR12 * mTy + mInt.mFocal * mR22 * mTx) / common_denominator; 54 | 55 | Yw = -(((mR11 * mR33 - mR13 * mR31) * Yu + ... 56 | (mR23 * mR31 - mR21 * mR33) * Xu - ... 57 | mInt.mFocal * mR11 * mR23 + mInt.mFocal * mR13 * mR21) * Zw + ... 58 | (mR11 * mTz - mR31 * mTx) * Yu + ... 59 | (mR31 * mTy - mR21 * mTz) * Xu - ... 60 | mInt.mFocal * mR11 * mTy + mInt.mFocal * mR21 * mTx) / common_denominator; 61 | 62 | end -------------------------------------------------------------------------------- /utils/printMetricsExt.m: -------------------------------------------------------------------------------- 1 | function printMetricsExt(metrics, metricsInfo, dispHeader,dispMetrics,padChar) 2 | % print metrics 3 | % 4 | % ... 5 | % 6 | 7 | % default names 8 | if nargin==1 9 | metricsInfo.names.long = {'IDF1', 'IDP', 'IDR', 'Recall','Precision','False Alarm Rate', ... 10 | 'GT Tracks','Mostly Tracked','Partially Tracked','Mostly Lost', ... 11 | 'False Positives', 'False Negatives', 'ID Switches', 'Fragmentations', ... 12 | 'MOTA','MOTP', 'MOTA Log'}; 13 | 14 | metricsInfo.names.short = {'IDF1', 'IDP', 'IDR', 'Rcll','Prcn','FAR', ... 15 | 'GT','MT','PT','ML', ... 16 | 'FP', 'FN', 'IDs', 'FM', ... 17 | 'MOTA','MOTP', 'MOTAL'}; 18 | 19 | metricsInfo.widths.long = [5 4 4 6 9 16 9 14 17 11 15 15 11 14 5 5 8]; 20 | metricsInfo.widths.short = [5 4 4 5 5 5 4 4 4 4 6 6 5 5 5 5 5]; 21 | 22 | metricsInfo.format.long = {'.1f','.1f','.1f', ... 23 | '.1f','.1f','.2f', ... 24 | 'i','i','i','i', ... 25 | 'i','i','i','i', ... 26 | '.1f','.1f','.1f'}; 27 | 28 | metricsInfo.format.short=metricsInfo.format.long; 29 | end 30 | 31 | namesToDisplay=metricsInfo.names.long; 32 | widthsToDisplay=metricsInfo.widths.long; 33 | formatToDisplay=metricsInfo.format.long; 34 | 35 | namesToDisplay=metricsInfo.names.short; 36 | widthsToDisplay=metricsInfo.widths.short; 37 | formatToDisplay=metricsInfo.format.short; 38 | 39 | if nargin<3, dispHeader=1; end 40 | if nargin<4 41 | dispMetrics=1:length(metrics); 42 | end 43 | if nargin<5 44 | padChar={' ',' ','|',' ',' ','| ','',' ',' ','|','',' ',' ','| ',' ',' ',' ',' '}; 45 | end 46 | 47 | if dispHeader 48 | for m=dispMetrics 49 | printString=sprintf('fprintf(''%%%is%s'',char(namesToDisplay(m)))',widthsToDisplay(m),char(padChar(m))); 50 | eval(printString) 51 | end 52 | fprintf('\n'); 53 | end 54 | 55 | for m=dispMetrics 56 | printString=sprintf('fprintf(''%%%i%s%s'',metrics(m))',widthsToDisplay(m),char(formatToDisplay(m)),char(padChar(m))); 57 | eval(printString) 58 | end 59 | 60 | % if standard, new line 61 | if nargin<4 62 | fprintf('\n'); 63 | end -------------------------------------------------------------------------------- /trackers/GOG/tracking_dp.m: -------------------------------------------------------------------------------- 1 | function [res, min_cs] = tracking_dp(dres, c_en, c_ex, c_ij, betta, thr_cost, max_it, nms_in_loop) 2 | 3 | if ~exist('max_it') 4 | max_it = 1e5; 5 | end 6 | if ~exist('thr_cost') 7 | thr_cost = 0; 8 | end 9 | 10 | thr_nms = 0.5; 11 | 12 | dnum = length(dres.x); 13 | 14 | dres.c = betta - dres.r; 15 | 16 | dres.dp_c = []; 17 | dres.dp_link = []; 18 | dres.orig = []; 19 | 20 | min_c = -inf; 21 | it = 0; 22 | k = 0; 23 | inds_all = zeros(1,1e5); 24 | id_s = zeros(1,1e5); 25 | redo_nodes = [1:dnum]'; 26 | while (min_c < thr_cost) && (it < max_it) 27 | it = it+1; 28 | 29 | dres.dp_c(redo_nodes,1) = dres.c(redo_nodes) + c_en; 30 | dres.dp_link(redo_nodes,1) = 0; 31 | dres.orig(redo_nodes,1) = redo_nodes; 32 | 33 | for ii=1:length(redo_nodes) 34 | i = redo_nodes(ii); 35 | f2 = dres.nei(i).inds; 36 | if isempty(f2) 37 | continue; 38 | end 39 | 40 | [min_cost j] = min(c_ij + dres.c(i) + dres.dp_c(f2)); 41 | min_link = f2(j); 42 | if dres.dp_c(i,1) > min_cost 43 | dres.dp_c(i,1) = min_cost; 44 | dres.dp_link(i,1) = min_link; 45 | dres.orig(i,1) = dres.orig(min_link); 46 | end 47 | end 48 | 49 | [min_c ind] = min(dres.dp_c + c_ex); 50 | 51 | inds = zeros(dnum,1); 52 | 53 | k1 = 0; 54 | while ind~=0 55 | k1 = k1+1; 56 | inds(k1) = ind; 57 | ind = dres.dp_link(ind); 58 | end 59 | inds = inds(1:k1); 60 | 61 | inds_all(k+1:k+length(inds)) = inds; 62 | id_s(k+1:k+length(inds)) = it; 63 | k = k+length(inds); 64 | 65 | if nms_in_loop 66 | supp_inds = nms_aggressive(dres, inds, thr_nms); 67 | origs = unique(dres.orig(supp_inds)); 68 | redo_nodes = find(ismember(dres.orig, origs)); 69 | else 70 | supp_inds = inds; 71 | origs = inds(end); 72 | redo_nodes = find(dres.orig == origs); 73 | end 74 | redo_nodes = setdiff(redo_nodes, supp_inds); 75 | dres.dp_c(supp_inds) = inf; 76 | dres.c(supp_inds) = inf; 77 | 78 | min_cs(it) = min_c; 79 | end 80 | inds_all = inds_all(1:k); 81 | id_s = id_s(1:k); 82 | 83 | res = sub(dres, inds_all); 84 | res.id = id_s'; 85 | 86 | -------------------------------------------------------------------------------- /utils/printMetrics.m: -------------------------------------------------------------------------------- 1 | function printMetrics(metrics, metricsInfo, dispHeader,dispMetrics,padChar) 2 | % print metrics 3 | % 4 | % ... 5 | % 6 | % extended version with ID Measures 7 | if length(metrics)==17 8 | printMetricsExt(metrics) 9 | return; 10 | end 11 | 12 | % Detections MODP/MODA metrics 13 | if length(metrics)==9 14 | printMetricsDet(metrics) 15 | return; 16 | end 17 | 18 | % default names 19 | if nargin==1 20 | metricsInfo.names.long = {'Recall','Precision','False Alarm Rate', ... 21 | 'GT Tracks','Mostly Tracked','Partially Tracked','Mostly Lost', ... 22 | 'False Positives', 'False Negatives', 'ID Switches', 'Fragmentations', ... 23 | 'MOTA','MOTP', 'MOTA Log'}; 24 | 25 | metricsInfo.names.short = {'Rcll','Prcn','FAR', ... 26 | 'GT','MT','PT','ML', ... 27 | 'FP', 'FN', 'IDs', 'FM', ... 28 | 'MOTA','MOTP', 'MOTAL'}; 29 | 30 | metricsInfo.widths.long = [6 9 16 9 14 17 11 15 15 11 14 5 5 8]; 31 | metricsInfo.widths.short = [5 5 5 4 4 4 4 6 6 5 5 5 5 5]; 32 | 33 | metricsInfo.format.long = {'.1f','.1f','.2f', ... 34 | 'i','i','i','i', ... 35 | 'i','i','i','i', ... 36 | '.1f','.1f','.1f'}; 37 | 38 | metricsInfo.format.short=metricsInfo.format.long; 39 | end 40 | 41 | namesToDisplay=metricsInfo.names.long; 42 | widthsToDisplay=metricsInfo.widths.long; 43 | formatToDisplay=metricsInfo.format.long; 44 | 45 | namesToDisplay=metricsInfo.names.short; 46 | widthsToDisplay=metricsInfo.widths.short; 47 | formatToDisplay=metricsInfo.format.short; 48 | 49 | if nargin<3, dispHeader=1; end 50 | if nargin<4 51 | dispMetrics=1:length(metrics)-1; 52 | end 53 | if nargin<5 54 | padChar={' ',' ','|',' ',' ',' ','|',' ',' ',' ','| ',' ',' ',' '}; 55 | end 56 | 57 | if dispHeader 58 | for m=dispMetrics 59 | printString=sprintf('fprintf(''%%%is%s'',char(namesToDisplay(m)))',widthsToDisplay(m),char(padChar(m))); 60 | eval(printString) 61 | end 62 | fprintf('\n'); 63 | end 64 | 65 | for m=dispMetrics 66 | printString=sprintf('fprintf(''%%%i%s%s'',metrics(m))',widthsToDisplay(m),char(formatToDisplay(m)),char(padChar(m))); 67 | eval(printString) 68 | end 69 | 70 | % if standard, new line 71 | if nargin<4 72 | fprintf('\n'); 73 | end -------------------------------------------------------------------------------- /eval/calcAP.m: -------------------------------------------------------------------------------- 1 | function [aps, recall, precision] = calcAP(track_confs, track_labels, tp_cell, fp_cell, num_vids, num_track_per_class, num_track_thr, defaultTrackThr, evalClassSet) 2 | 3 | fprintf('evaluating VisDrone2018 Task4a :: computing ap\n'); 4 | recall = cell(1,num_track_thr); 5 | precision = cell(1,num_track_thr); 6 | aps = cell(1,num_track_thr); 7 | confs = [track_confs{:}]; 8 | [~, ind] = sort(confs,'descend'); 9 | for o = 1:num_track_thr 10 | tp_all = []; 11 | fp_all = []; 12 | for v = 1:num_vids 13 | tp_all = [tp_all(:); tp_cell{v}{o}']; 14 | fp_all = [fp_all(:); fp_cell{v}{o}']; 15 | end 16 | 17 | tp_all = tp_all(ind)'; 18 | fp_all = fp_all(ind)'; 19 | obj_labels = [track_labels{:}]; 20 | obj_labels = obj_labels(ind); 21 | 22 | for c = 1:10 23 | % compute precision/recall 24 | if(num_track_per_class(c)) 25 | tp = cumsum(tp_all(obj_labels==c)); 26 | fp = cumsum(fp_all(obj_labels==c)); 27 | recall{o}{c} = (tp/num_track_per_class(c))'; 28 | precision{o}{c} = (tp./(fp+tp))'; 29 | aps{o}(c) = VOCap(recall{o}{c},precision{o}{c})*100; 30 | end 31 | end 32 | end 33 | 34 | fprintf('-------------\n'); 35 | fprintf('Category\tAP\n'); 36 | if(length(aps) ~= length(defaultTrackThr)) 37 | error('Inconsistent number of APs.'); 38 | end 39 | ap = aps{1}; 40 | for t = 2:length(aps) 41 | ap = ap + aps{t}; 42 | end 43 | ap = ap ./ length(aps); 44 | eval_ap_ind = []; 45 | for i = 1:length(evalClassSet) 46 | s = evalClassSet{i}; 47 | ind = getClassID(evalClassSet{i}); 48 | if(length(s) < 5) 49 | fprintf('%s\t\t\t%0.2f%%\n',s,ap(ind)); 50 | elseif(length(s) < 8) 51 | fprintf('%s\t\t%0.2f%%\n',s,ap(ind)); 52 | else 53 | fprintf('%s\t%0.2f%%\n',s,ap(ind)); 54 | end 55 | eval_ap_ind = cat(1, eval_ap_ind, ind); 56 | end 57 | fprintf(' - - - - - - - - \n'); 58 | fprintf('Mean AP:\t\t %0.2f%%\n',mean(ap(eval_ap_ind))); 59 | fprintf(' = = = = = = = = \n'); 60 | for t = 1:length(aps) 61 | ap = aps{t}; 62 | fprintf('Mean AP@%0.2f:\t %0.2f%%\n',defaultTrackThr(t),mean(ap(eval_ap_ind))); 63 | end 64 | fprintf(' = = = = = = = = \n'); -------------------------------------------------------------------------------- /utils/evaluateBenchmark.m: -------------------------------------------------------------------------------- 1 | function metsBenchmark = evaluateBenchmark(allMets, world) 2 | 3 | % Aggregate scores from all sequences over each object category 4 | MT = 0; PT = 0; ML = 0; FRA = 0; 5 | falsepositives = 0; missed = 0; idswitches = 0; 6 | Fgt = 0; distsum = 0; Ngt = 0; sumg = 0; 7 | Nc = 0; 8 | numGT = 0; numPRED = 0; IDTP = 0; IDFP = 0; IDFN = 0; 9 | 10 | for ind = 1:length(allMets) 11 | if(~isempty(allMets(ind).m)) 12 | numGT = numGT + allMets(ind).IDmeasures.numGT; 13 | numPRED = numPRED + allMets(ind).IDmeasures.numPRED; 14 | IDTP = IDTP + allMets(ind).IDmeasures.IDTP; 15 | IDFN = IDFN + allMets(ind).IDmeasures.IDFN; 16 | IDFP = IDFP + allMets(ind).IDmeasures.IDFP; 17 | 18 | MT = MT + allMets(ind).additionalInfo.MT; 19 | PT = PT + allMets(ind).additionalInfo.PT; 20 | ML = ML + allMets(ind).additionalInfo.ML; 21 | FRA = FRA + allMets(ind).additionalInfo.FRA; 22 | Fgt = Fgt + allMets(ind).additionalInfo.Fgt; 23 | Ngt = Ngt + allMets(ind).additionalInfo.Ngt; 24 | Nc = Nc + sum(allMets(ind).additionalInfo.c); 25 | sumg = sumg + sum(allMets(ind).additionalInfo.g); 26 | falsepositives = falsepositives + sum(allMets(ind).additionalInfo.fp); 27 | missed = missed + sum(allMets(ind).additionalInfo.m); 28 | idswitches = idswitches + sum(allMets(ind).additionalInfo.mme); 29 | dists = allMets(ind).additionalInfo.d; 30 | td = allMets(ind).additionalInfo.td; 31 | distsum = distsum + sum(sum(dists)); 32 | end 33 | end 34 | 35 | IDPrecision = IDTP / (IDTP + IDFP); 36 | IDRecall = IDTP / (IDTP + IDFN); 37 | IDF1 = 2*IDTP/(numGT + numPRED); 38 | if(numPRED==0) 39 | IDPrecision = 0; 40 | end 41 | 42 | IDP = IDPrecision * 100; 43 | IDR = IDRecall * 100; 44 | IDF1 = IDF1 * 100; 45 | 46 | FAR = falsepositives / Fgt; 47 | MOTP = (1-distsum/Nc) * 100; 48 | if(world) 49 | MOTP = MOTP / td; 50 | end 51 | if(isnan(MOTP)) 52 | MOTP = 0; 53 | end 54 | MOTAL = (1-(missed+falsepositives+log10(idswitches+1))/sumg)*100; 55 | MOTA = (1-(missed+falsepositives+idswitches)/sumg)*100; 56 | recall = Nc/sumg*100; 57 | precision = Nc/(falsepositives+Nc)*100; 58 | 59 | metsBenchmark = [IDF1, IDP, IDR, recall, precision, FAR, Ngt, MT, PT, ML, falsepositives, missed, idswitches, FRA, MOTA, MOTP, MOTAL]; -------------------------------------------------------------------------------- /trackers/GOG/undistortedToDistortedSensorCoord.m: -------------------------------------------------------------------------------- 1 | function [Xd Yd]=undistortedToDistortedSensorCoord (Xu, Yu, mKappa1) 2 | 3 | % global ifs elses 4 | 5 | if ((~Xu && ~Yu) || ~mKappa1) 6 | % ifs(1)=ifs(1)+1; 7 | Xd = Xu; 8 | Yd = Yu; 9 | else %% THIS ONE %% 10 | % elses(1)=elses(1)+1; 11 | Ru = sqrt(Xu*Xu + Yu*Yu); 12 | 13 | c = 1.0 / mKappa1; 14 | d = -c * Ru; 15 | 16 | Q = c / 3; 17 | R = -d / 2; 18 | D = Q*Q*Q + R*R; 19 | 20 | if (D >= 0) %% THIS ONE %% 21 | % ifs(2)=ifs(2)+1; 22 | %/* one real root */ 23 | D = sqrt(D); 24 | if (R + D > 0) %% THIS ONE %% 25 | % ifs(3)=ifs(3)+1; 26 | S = (R + D)^ (1.0/3.0); 27 | else 28 | % elses(3)=elses(3)+1; 29 | S = -(-R - D)^ (1.0/3.0); 30 | end 31 | if (R - D > 0) 32 | % ifs(4)=ifs(4)+1; 33 | T = (R - D)^(1.0/3.0); 34 | else %% THIS ONE %% 35 | % elses(4)=elses(4)+1; 36 | T = -(D - R)^(1.0/3.0); 37 | end 38 | Rd = S + T; 39 | 40 | if (Rd < 0) 41 | Rd = sqrt(-1.0 / (3 * mKappa1)); 42 | % /*fprintf (stderr, "\nWarning: undistorted image point to distorted image point mapping limited by\n"); 43 | % fprintf (stderr, " maximum barrel distortion radius of %lf\n", Rd); 44 | % fprintf (stderr, " (Xu = %lf, Yu = %lf) -> (Xd = %lf, Yd = %lf)\n\n", Xu, Yu, Xu * Rd / Ru, Yu * Rd / Ru);*/ 45 | end 46 | else 47 | % elses(2)=elses(2)+1; 48 | % /* three real roots */ 49 | D = sqrt(-D); 50 | S = ( sqrt(R*R + D*D))^(1.0/3.0 ); 51 | T = atan2(D, R) / 3; 52 | sinT = sin(T); 53 | cosT = cos(T); 54 | 55 | % /* the larger positive root is 2*S*cos(T) */ 56 | % /* the smaller positive root is -S*cos(T) + SQRT(3)*S*sin(T) */ 57 | % /* the negative root is -S*cos(T) - SQRT(3)*S*sin(T) */ 58 | 59 | Rd = -S * cosT + sqrt(3.0) * S * sinT; % /* use the smaller positive root */ 60 | end 61 | 62 | lambda = Rd / Ru; 63 | 64 | Xd = Xu * lambda; 65 | Yd = Yu * lambda; 66 | end 67 | end -------------------------------------------------------------------------------- /utils/camera/undistortedToDistortedSensorCoord.m: -------------------------------------------------------------------------------- 1 | function [Xd Yd]=undistortedToDistortedSensorCoord (Xu, Yu, mKappa1) 2 | 3 | % global ifs elses 4 | 5 | if ((~Xu && ~Yu) || ~mKappa1) 6 | % ifs(1)=ifs(1)+1; 7 | Xd = Xu; 8 | Yd = Yu; 9 | else %% THIS ONE %% 10 | % elses(1)=elses(1)+1; 11 | Ru = sqrt(Xu*Xu + Yu*Yu); 12 | 13 | c = 1.0 / mKappa1; 14 | d = -c * Ru; 15 | 16 | Q = c / 3; 17 | R = -d / 2; 18 | D = Q*Q*Q + R*R; 19 | 20 | if (D >= 0) %% THIS ONE %% 21 | % ifs(2)=ifs(2)+1; 22 | %/* one real root */ 23 | D = sqrt(D); 24 | if (R + D > 0) %% THIS ONE %% 25 | % ifs(3)=ifs(3)+1; 26 | S = (R + D)^ (1.0/3.0); 27 | else 28 | % elses(3)=elses(3)+1; 29 | S = -(-R - D)^ (1.0/3.0); 30 | end 31 | if (R - D > 0) 32 | % ifs(4)=ifs(4)+1; 33 | T = (R - D)^(1.0/3.0); 34 | else %% THIS ONE %% 35 | % elses(4)=elses(4)+1; 36 | T = -(D - R)^(1.0/3.0); 37 | end 38 | Rd = S + T; 39 | 40 | if (Rd < 0) 41 | Rd = sqrt(-1.0 / (3 * mKappa1)); 42 | % /*fprintf (stderr, "\nWarning: undistorted image point to distorted image point mapping limited by\n"); 43 | % fprintf (stderr, " maximum barrel distortion radius of %lf\n", Rd); 44 | % fprintf (stderr, " (Xu = %lf, Yu = %lf) -> (Xd = %lf, Yd = %lf)\n\n", Xu, Yu, Xu * Rd / Ru, Yu * Rd / Ru);*/ 45 | end 46 | else 47 | % elses(2)=elses(2)+1; 48 | % /* three real roots */ 49 | D = sqrt(-D); 50 | S = ( sqrt(R*R + D*D))^(1.0/3.0 ); 51 | T = atan2(D, R) / 3; 52 | sinT = sin(T); 53 | cosT = cos(T); 54 | 55 | % /* the larger positive root is 2*S*cos(T) */ 56 | % /* the smaller positive root is -S*cos(T) + SQRT(3)*S*sin(T) */ 57 | % /* the negative root is -S*cos(T) - SQRT(3)*S*sin(T) */ 58 | 59 | Rd = -S * cosT + sqrt(3.0) * S * sinT; % /* use the smaller positive root */ 60 | end 61 | 62 | lambda = Rd / Ru; 63 | 64 | Xd = Xu * lambda; 65 | Yd = Yu * lambda; 66 | end 67 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/undistortedToDistortedSensorCoord.m: -------------------------------------------------------------------------------- 1 | function [Xd Yd]=undistortedToDistortedSensorCoord (Xu, Yu, mKappa1) 2 | 3 | % global ifs elses 4 | 5 | if ((~Xu && ~Yu) || ~mKappa1) 6 | % ifs(1)=ifs(1)+1; 7 | Xd = Xu; 8 | Yd = Yu; 9 | else %% THIS ONE %% 10 | % elses(1)=elses(1)+1; 11 | Ru = sqrt(Xu*Xu + Yu*Yu); 12 | 13 | c = 1.0 / mKappa1; 14 | d = -c * Ru; 15 | 16 | Q = c / 3; 17 | R = -d / 2; 18 | D = Q*Q*Q + R*R; 19 | 20 | if (D >= 0) %% THIS ONE %% 21 | % ifs(2)=ifs(2)+1; 22 | %/* one real root */ 23 | D = sqrt(D); 24 | if (R + D > 0) %% THIS ONE %% 25 | % ifs(3)=ifs(3)+1; 26 | S = (R + D)^ (1.0/3.0); 27 | else 28 | % elses(3)=elses(3)+1; 29 | S = -(-R - D)^ (1.0/3.0); 30 | end 31 | if (R - D > 0) 32 | % ifs(4)=ifs(4)+1; 33 | T = (R - D)^(1.0/3.0); 34 | else %% THIS ONE %% 35 | % elses(4)=elses(4)+1; 36 | T = -(D - R)^(1.0/3.0); 37 | end 38 | Rd = S + T; 39 | 40 | if (Rd < 0) 41 | Rd = sqrt(-1.0 / (3 * mKappa1)); 42 | % /*fprintf (stderr, "\nWarning: undistorted image point to distorted image point mapping limited by\n"); 43 | % fprintf (stderr, " maximum barrel distortion radius of %lf\n", Rd); 44 | % fprintf (stderr, " (Xu = %lf, Yu = %lf) -> (Xd = %lf, Yd = %lf)\n\n", Xu, Yu, Xu * Rd / Ru, Yu * Rd / Ru);*/ 45 | end 46 | else 47 | % elses(2)=elses(2)+1; 48 | % /* three real roots */ 49 | D = sqrt(-D); 50 | S = ( sqrt(R*R + D*D))^(1.0/3.0 ); 51 | T = atan2(D, R) / 3; 52 | sinT = sin(T); 53 | cosT = cos(T); 54 | 55 | % /* the larger positive root is 2*S*cos(T) */ 56 | % /* the smaller positive root is -S*cos(T) + SQRT(3)*S*sin(T) */ 57 | % /* the negative root is -S*cos(T) - SQRT(3)*S*sin(T) */ 58 | 59 | Rd = -S * cosT + sqrt(3.0) * S * sinT; % /* use the smaller positive root */ 60 | end 61 | 62 | lambda = Rd / Ru; 63 | 64 | Xd = Xu * lambda; 65 | Yd = Yu * lambda; 66 | end 67 | end -------------------------------------------------------------------------------- /eval/evaluateTendMark.m: -------------------------------------------------------------------------------- 1 | function metsBenchmark = evaluateTendMark( allMets, world ) 2 | 3 | 4 | % Aggregate scores from all sequences 5 | MT = 0; PT = 0; ML = 0; FRA = 0; 6 | falsepositives = 0; missed = 0; idswitches = 0; 7 | Fgt = 0; distsum = 0; Ngt = 0; sumg = 0; 8 | Nc = 0; 9 | numGT = 0; numPRED = 0; IDTP = 0; IDFP = 0; IDFN = 0; 10 | 11 | for ind = 1:length(allMets) 12 | if isempty(allMets(ind).m) 13 | fprintf('\n\nResults missing for sequence #%d\n', ind) 14 | continue; 15 | end 16 | numGT = numGT + allMets(ind).IDmeasures.numGT; 17 | numPRED = numPRED + allMets(ind).IDmeasures.numPRED; 18 | IDTP = IDTP + allMets(ind).IDmeasures.IDTP; 19 | IDFN = IDFN + allMets(ind).IDmeasures.IDFN; 20 | IDFP = IDFP + allMets(ind).IDmeasures.IDFP; 21 | 22 | MT = MT + allMets(ind).additionalInfo.MT; 23 | PT = PT + allMets(ind).additionalInfo.PT; 24 | ML = ML + allMets(ind).additionalInfo.ML; 25 | FRA = FRA + allMets(ind).additionalInfo.FRA; 26 | Fgt = Fgt + allMets(ind).additionalInfo.Fgt; 27 | Ngt = Ngt + allMets(ind).additionalInfo.Ngt; 28 | Nc = Nc + sum(allMets(ind).additionalInfo.c); 29 | sumg = sumg + sum(allMets(ind).additionalInfo.g); 30 | falsepositives = falsepositives + sum(allMets(ind).additionalInfo.fp); 31 | missed = missed + sum(allMets(ind).additionalInfo.m); 32 | idswitches = idswitches + sum(allMets(ind).additionalInfo.mme); 33 | dists = allMets(ind).additionalInfo.d; 34 | td = allMets(ind).additionalInfo.td; 35 | distsum = distsum + sum(sum(dists)); 36 | end 37 | 38 | IDPrecision = IDTP / (IDTP + IDFP); 39 | IDRecall = IDTP / (IDTP + IDFN); 40 | IDF1 = 2*IDTP/(numGT + numPRED); 41 | if numPRED==0, IDPrecision = 0; end 42 | IDP = IDPrecision * 100; 43 | IDR = IDRecall * 100; 44 | IDF1 = IDF1 * 100; 45 | 46 | 47 | FAR = falsepositives / Fgt; 48 | MOTP = (1-distsum/Nc) * 100; 49 | if world, MOTP = MOTP / td; end 50 | if isnan(MOTP), MOTP = 0; end 51 | MOTAL=(1-(missed+falsepositives+log10(idswitches+1))/sumg)*100; 52 | MOTA=(1-(missed+falsepositives+idswitches)/sumg)*100; 53 | recall=Nc/sumg*100; 54 | precision=Nc/(falsepositives+Nc)*100; 55 | 56 | metsBenchmark = [IDF1, IDP, IDR, recall, precision, FAR, Ngt, MT, PT, ML, falsepositives, missed, idswitches, FRA, MOTA, MOTP, MOTAL]; 57 | 58 | end 59 | 60 | -------------------------------------------------------------------------------- /trackers/GOG/utils/parseDetections.m: -------------------------------------------------------------------------------- 1 | function detections = parseDetections(curdetections, frameNums) 2 | % read detection file and create a struct array 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | cnt = numel(frameNums); 13 | detections(cnt).bx=[]; 14 | detections(cnt).by=[]; 15 | detections(cnt).xp=[]; 16 | detections(cnt).yp=[]; 17 | detections(cnt).ht=[]; 18 | detections(cnt).wd=[]; 19 | detections(cnt).sc=[]; 20 | 21 | detections(cnt).xi=[]; 22 | detections(cnt).yi=[]; 23 | for t = frameNums 24 | idxObj = find(curdetections(:,1) == t); 25 | nObjects = numel(idxObj); 26 | bx =[];by=[];xp=[];yp=[]; 27 | ht=[];wd=[];sc=[]; 28 | xi=[];yi=[]; 29 | for j = 1:nObjects 30 | loc = curdetections(idxObj(j), 3:6); 31 | score = curdetections(idxObj(j), 7); 32 | left = loc(1); 33 | top = loc(2); 34 | width = loc(3); 35 | height = loc(4); 36 | xis = left + width/2; 37 | yis = top + height; 38 | bx = cat(2, bx, left); 39 | by=cat(2, by, top); 40 | xp=cat(2, xp, xis); 41 | yp=cat(2, xp, yis); 42 | ht=cat(2, ht, height); 43 | wd=cat(2, wd, width); 44 | sc=cat(2, sc, score); 45 | xi=cat(2, xi, xis); 46 | yi=cat(2, yi, yis); 47 | end 48 | detections(t).bx=bx; 49 | detections(t).by=by; 50 | detections(t).xp=xp; 51 | detections(t).yp=yp; 52 | detections(t).ht=ht; 53 | detections(t).wd=wd; 54 | detections(t).sc=sc; 55 | 56 | detections(t).xi=xi; 57 | detections(t).yi=yi; 58 | end 59 | 60 | %% set xp and yp accordingly 61 | detections = setDetectionPositions(detections); 62 | end 63 | 64 | function detections = setDetectionPositions(detections) 65 | % set xp,yp to xi,yi if tracking is in image (2d) 66 | % set xp,yp to xw,yi if tracking is in world (3d) 67 | F = length(detections); 68 | for t = 1:F 69 | detections(t).xp=detections(t).xi; 70 | detections(t).yp=detections(t).yi; 71 | end 72 | end -------------------------------------------------------------------------------- /trackers/GOG/show_bboxes_on_video.m: -------------------------------------------------------------------------------- 1 | % it shows bboxes on frames of a video (bunch of frames in "input_frames") and outputs a video "video_fname" 2 | % bboxes(i).bbox is an n*5 matrix: detections on the i'th frame 3 | % "thr" is used to prune detection results: default: -inf 4 | % if you don't pass "output_frames", it will make a temporary one and then delete it in the end. 5 | % "bws" is track numbers in image format (used as label for the boxes) 6 | 7 | function show_bboxes_on_video(input_frames, bboxes, video_fname, bws, frame_rate, thr, output_frames, frameNums) 8 | 9 | if ~exist('frame_rate', 'var') 10 | frame_rate = 20; 11 | end 12 | if ~exist('thr', 'var') 13 | thr = -inf; 14 | end 15 | if exist('output_frames', 'var') 16 | if ~isempty(output_frames) 17 | flag = 0; 18 | % unix(['rm -r ' output_frames]); 19 | else 20 | flag = 1; 21 | end 22 | else 23 | flag = 1; 24 | end 25 | if flag == 1 26 | output_frames = tempname; %% A temporary folder name 27 | output_frames = [output_frames(end-9:end) '/']; 28 | end 29 | 30 | % mkdir (output_frames); 31 | 32 | col = round((rand(3,1e4)/2+.5)*255); %% we assume number of tracks is less than 1e4. 33 | 34 | dirlist = dir([input_frames '*.jpg']); %%list of images 35 | if isempty(dirlist) 36 | dirlist = dir([input_frames '*.png']); 37 | end 38 | 39 | figure(1), title('Tracking Results'); 40 | % [imgWidth, imgHeight] = size(imread(fullfile(input_frames, [sprintf('img%0.5d', frameNums(1)) '.jpg']))); 41 | % figure('Position',[100 200 imgWidth imgHeight]), title('Tracking Results'); 42 | for i = 1:length(bboxes) 43 | bbox = bboxes(i).bbox; 44 | % img = imread(fullfile(input_frames, [sprintf('frame_%0.4d', frameNums(i)-1) '.jpg']));%% read an image 45 | img = imread(fullfile(input_frames, [sprintf('img%0.5d', frameNums(i)) '.jpg']));%% read an image 46 | if ~isempty(bbox) 47 | img = show_bbox_on_image(img, bbox(bbox(:,end) > thr, :), bws, col); 48 | end 49 | imshow(img); 50 | % frame number 51 | text(20,50,sprintf('%d',i),'FontSize',20); 52 | pause(0.01); 53 | % imwrite(img, [output_frames sprintf('%0.4d', i) '.jpg']); %%write the output image 54 | % imwrite(img, [output_frames sprintf('%0.5d', i) '.jpg']); %%write the output image 55 | end 56 | 57 | frames_to_video(output_frames, video_fname, frame_rate); %%convert frames to video 58 | 59 | if flag 60 | % unix(['rm -r ' output_frames]); %%remove temporary output folder 61 | end 62 | -------------------------------------------------------------------------------- /utils/camera/imageToWorld.m: -------------------------------------------------------------------------------- 1 | function [Xw, Yw, Zw]=imageToWorld(Xi, Yi, camPar) 2 | 3 | % if scalar, just up/downscale = orthographic 4 | if camPar.ortho 5 | Xw=Xi*camPar.scale; 6 | Yw=Yi*camPar.scale; 7 | Zw=0; 8 | else 9 | 10 | mGeo=camPar.mGeo; 11 | mExt=camPar.mExt; 12 | mInt=camPar.mInt; 13 | 14 | mTx=mExt.mTx; 15 | mTy=mExt.mTy; 16 | mTz=mExt.mTz; 17 | 18 | mT=[mExt.mTx;mExt.mTy;mExt.mTz]; 19 | 20 | %% internal init 21 | sa = sin(mExt.mRx); 22 | ca = cos(mExt.mRx); 23 | sb = sin(mExt.mRy); 24 | cb = cos(mExt.mRy); 25 | sg = sin(mExt.mRz); 26 | cg = cos(mExt.mRz); 27 | 28 | mR11 = cb * cg; 29 | mR12 = cg * sa * sb - ca * sg; 30 | mR13 = sa * sg + ca * cg * sb; 31 | mR21 = cb * sg; 32 | mR22 = sa * sb * sg + ca * cg; 33 | mR23 = ca * sb * sg - cg * sa; 34 | mR31 = -sb; 35 | mR32 = cb * sa; 36 | mR33 = ca * cb; 37 | 38 | 39 | 40 | % /* convert from image to distorted sensor coordinates */ 41 | Xd = mGeo.mDpx * (Xi - mInt.mCx) / mInt.mSx; 42 | Yd = mGeo.mDpy * (Yi - mInt.mCy); 43 | 44 | % /* convert from distorted sensor to undistorted sensor plane coordinates */ 45 | [Xu Yu]=distortedToUndistortedSensorCoord (Xd, Yd, mInt.mKappa1); 46 | 47 | % /* calculate the corresponding xw and yw world coordinates */ 48 | % /* (these equations were derived by simply inverting */ 49 | % /* the perspective projection equations using Macsyma) */ 50 | Zw=0; 51 | common_denominator = ((mR11 * mR32 - mR12 * mR31) * Yu + ... 52 | (mR22 * mR31 - mR21 * mR32) * Xu - ... 53 | mInt.mFocal * mR11 * mR22 + mInt.mFocal * mR12 * mR21); 54 | 55 | Xw = (((mR12 * mR33 - mR13 * mR32) * Yu + ... 56 | (mR23 * mR32 - mR22 * mR33) * Xu - ... 57 | mInt.mFocal * mR12 * mR23 + mInt.mFocal * mR13 * mR22) * Zw + ... 58 | (mR12 * mTz - mR32 * mTx) * Yu + ... 59 | (mR32 * mTy - mR22 * mTz) * Xu - ... 60 | mInt.mFocal * mR12 * mTy + mInt.mFocal * mR22 * mTx) / common_denominator; 61 | 62 | Yw = -(((mR11 * mR33 - mR13 * mR31) * Yu + ... 63 | (mR23 * mR31 - mR21 * mR33) * Xu - ... 64 | mInt.mFocal * mR11 * mR23 + mInt.mFocal * mR13 * mR21) * Zw + ... 65 | (mR11 * mTz - mR31 * mTx) * Yu + ... 66 | (mR31 * mTy - mR21 * mTz) * Xu - ... 67 | mInt.mFocal * mR11 * mTy + mInt.mFocal * mR21 * mTx) / common_denominator; 68 | % else 69 | % error('imageToWorld: camera parameters format unknown'); 70 | end 71 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/greedy_Pets_gt_generator.m: -------------------------------------------------------------------------------- 1 | clear;clc; 2 | addpath('../../input_trans'); 3 | 4 | global sceneInfo opt; 5 | 6 | dbfolder='E:\ComputerVision\Multi-target Tracking\TPAMI_Dataset\Pedestrian_Dataset\PETS2009\S2_L1'; 7 | video_name = 'PETS2009-S2L1'; 8 | opt.track3d = 1; 9 | 10 | %% camera 11 | cameraconffile=[]; 12 | if opt.track3d 13 | cameraconffile=fullfile(dbfolder,'camera','CameraView001.xml'); 14 | end 15 | sceneInfo.camFile=cameraconffile; 16 | 17 | if ~isempty(sceneInfo.camFile) 18 | sceneInfo.camPar=parseCameraParameters(sceneInfo.camFile); 19 | end 20 | 21 | %% ground truth 22 | sceneInfo.gtFile=''; 23 | sceneInfo.gtFile=fullfile(dbfolder,'gt','PETS2009-S2L1.xml'); 24 | outPath = '.\gtInfo\PETS\'; 25 | outName = [video_name '_gtInfo.mat']; 26 | 27 | outPath2 = '.\detect_gt\PETS\'; 28 | outName2 = [video_name '_detect_gt.mat']; 29 | global gtInfo 30 | sceneInfo.gtAvailable=0; 31 | if ~isempty(sceneInfo.gtFile) 32 | sceneInfo.gtAvailable=1; 33 | % first determine the type 34 | [~, ~, fileext]=fileparts(sceneInfo.gtFile); 35 | 36 | if strcmpi(fileext,'.xml') % CVML 37 | gtInfo=parseGT(sceneInfo.gtFile); 38 | elseif strcmpi(fileext,'.mat') 39 | % check for the var gtInfo 40 | fileInfo=who('-file',sceneInfo.gtFile); 41 | varExists=0; cnt=0; 42 | while ~varExists && cntbbLoad for test data (see bbGt>bbLoad) 13 | % .thr - [.5] threshold on overlap area for comparing two bbs 14 | % .mul - [0] if true allow multiple matches to each gt 15 | % .reapply - [0] if true re-apply detector even if bbs already computed 16 | % .ref - [10.^(-2:.25:0)] reference points (see bbGt>compRoc) 17 | % .lims - [3.1e-3 1e1 .05 1] plot axis limits 18 | % .show - [0] optional figure number for display 19 | % 20 | % OUTPUTS 21 | % miss - log-average miss rate computed at reference points 22 | % roc - [nx3] n data points along roc of form [score fp tp] 23 | % gt - [mx5] ground truth results [x y w h match] (see bbGt>evalRes) 24 | % dt - [nx6] detect results [x y w h score match] (see bbGt>evalRes) 25 | % 26 | % EXAMPLE 27 | % 28 | % See also acfTrain, acfDetect, acfDemoInria, bbGt 29 | % 30 | % Piotr's Image&Video Toolbox Version 3.22 31 | % Copyright 2013 Piotr Dollar & Ron Appel. [pdollar-at-caltech.edu] 32 | % Please email me if you find bugs, or have suggestions or questions! 33 | % Licensed under the Simplified BSD License [see external/bsd.txt] 34 | 35 | % get parameters 36 | dfs={ 'name','REQ', 'imgDir','REQ', 'gtDir','REQ', 'pLoad',[], ... 37 | 'thr',.5,'mul',0, 'reapply',0, 'ref',10.^(-2:.25:0), ... 38 | 'lims',[3.1e-3 1e1 .05 1], 'show',0 }; 39 | [name,imgDir,gtDir,pLoad,thr,mul,reapply,ref,lims,show] = ... 40 | getPrmDflt(varargin,dfs,1); 41 | 42 | % run detector on directory of images 43 | bbsNm=[name 'Dets.txt']; 44 | if(reapply && exist(bbsNm,'file')), delete(bbsNm); end 45 | if(reapply || ~exist(bbsNm,'file')) 46 | detector = load([name 'Detector.mat']); 47 | detector = detector.detector; 48 | imgNms = bbGt('getFiles',{imgDir}); 49 | acfDetect( imgNms, detector, bbsNm ); 50 | end 51 | 52 | % run evaluation using bbGt 53 | [gt,dt] = bbGt('loadAll',gtDir,bbsNm,pLoad); 54 | [gt,dt] = bbGt('evalRes',gt,dt,thr,mul); 55 | [fp,tp,score,miss] = bbGt('compRoc',gt,dt,1,ref); 56 | miss=exp(mean(log(max(1e-10,1-miss)))); roc=[score fp tp]; 57 | 58 | % optionally plot roc 59 | if( ~show ), return; end 60 | figure(show); plotRoc([fp tp],'logx',1,'logy',1,'xLbl','fppi',... 61 | 'lims',lims,'color','g','smooth',1,'fpTarget',ref); 62 | title(sprintf('log-average miss rate = %.2f%%',miss*100)); 63 | savefig([name 'Roc'],show,'png'); 64 | 65 | end 66 | -------------------------------------------------------------------------------- /eval/runTrackerAllClass.m: -------------------------------------------------------------------------------- 1 | function runTrackerAllClass(isSeqDisplay, isNMS, detPath, resPath, seqPath, evalClassSet, threSet, nmsThre, trackerName) 2 | 3 | createPath(resPath); % create the saving path of the tracking results 4 | nameSeqs = findSeqList(seqPath); % find the sequence list 5 | speed = 0; 6 | numfrs = 0; 7 | 8 | % evaluate each sequence 9 | for idSeq = 1:length(nameSeqs) 10 | disp(['tracking the sequence ' num2str(idSeq) '/' num2str(length(nameSeqs)) '...']); 11 | % load detections and sequence 12 | det = load(fullfile(detPath, [nameSeqs{idSeq} '.txt'])); 13 | sequence.dataset = dir(fullfile(seqPath, [nameSeqs{idSeq} '/*.jpg'])); 14 | sequence.seqPath = fullfile(seqPath, nameSeqs{idSeq}); 15 | sequence.seqName = nameSeqs{idSeq}; 16 | img = imread(fullfile(seqPath, nameSeqs{idSeq}, sequence.dataset(1).name)); 17 | [sequence.imgHeight, sequence.imgWidth, ~] = size(img); 18 | % nms processing 19 | detections = nmsProcess(det, isNMS, nmsThre); 20 | % evaluate each object category 21 | allRes = cell(1, length(evalClassSet)); 22 | for idClass = 1:length(evalClassSet) 23 | classID = getClassID(evalClassSet{idClass}); 24 | idx = detections(:, 8) == classID & detections(:, 7) >= threSet(idClass); 25 | curdetections = detections(idx,:); 26 | if(size(curdetections,1)>=4) % at least 4 detections 27 | try 28 | % add the tracker path 29 | cd(['./trackers/' trackerName]); 30 | addpath(genpath('.')); 31 | % run the tracker 32 | [resClass, runTime] = run_tracker(sequence, curdetections); 33 | % save tracking result 34 | resClass(:,8) = classID; 35 | allRes{idClass} = resClass; 36 | speed = speed + runTime; 37 | % remove the toolbox path 38 | rmpath(genpath('.')); 39 | cd('../../'); 40 | catch err 41 | % remove the toolbox path 42 | rmpath(genpath('./')); 43 | cd('../../'); 44 | error('error in running the tracker!'); 45 | end 46 | end 47 | end 48 | % combine tracks of multiple object categories 49 | res = combineTrks(evalClassSet, allRes); 50 | % calculate the length of all the sequences 51 | numfrs = numfrs + length(sequence.dataset); 52 | % show the tracking results 53 | dlmwrite(fullfile(resPath, [nameSeqs{idSeq} '.txt']), res); 54 | % show the tracking results 55 | showResults(isSeqDisplay, res, sequence); 56 | end 57 | 58 | % calculate the speed 59 | speed = numfrs/speed; 60 | disp(['Tracking completed. The runing speed of ' trackerName ' tracker is ' num2str(roundn(speed,-2)) 'fps.']); 61 | -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/acfDemoCal.m: -------------------------------------------------------------------------------- 1 | % Demo for aggregate channel features object detector on Caltech dataset. 2 | % 3 | % (1) Download data and helper routines from Caltech Peds Website 4 | % www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/ 5 | % (1a) Download Caltech files: set*.tar and annotations.zip 6 | % (1b) Copy above files to dataDir/data-USA/ and untar/unzip contents 7 | % (1c) Download evaluation code (routines necessary for extracting images) 8 | % (2) Set dataDir/ variable below to point to location of Caltech data. 9 | % (3) Launch "matlabpool open" for faster training if available. 10 | % (4) Run demo script and enjoy your newly minted fast ped detector! 11 | % 12 | % Note: pre-trained model files are provided (delete to re-train). 13 | % Re-training may give slightly variable results on different machines. 14 | % 15 | % Piotr's Image&Video Toolbox Version 3.23 16 | % Copyright 2013 Piotr Dollar & Ron Appel. [pdollar-at-caltech.edu] 17 | % Please email me if you find bugs, or have suggestions or questions! 18 | % Licensed under the Simplified BSD License [see external/bsd.txt] 19 | 20 | %% extract training and testing images and ground truth 21 | dataDir = 'D:\code\research\detectorAcf\data\Caltech\'; 22 | for s=1:2 23 | if(s==1), type='train'; else type='test'; end 24 | if(exist([dataDir type '/annotations'],'dir')), continue; end 25 | dbInfo(['Usa' type]); dbExtract([dataDir type],1); 26 | end 27 | 28 | %% set up opts for training detector (see acfTrain) 29 | opts=acfTrain(); opts.modelDs=[50 20.5]; opts.modelDsPad=[64 32]; 30 | opts.pPyramid.smooth=.5; opts.pPyramid.pChns.pColor.smooth=0; 31 | opts.posGtDir=[dataDir 'train/annotations']; opts.nWeak=[32 128 512 2048]; 32 | opts.posImgDir=[dataDir 'train/images']; opts.pJitter=struct('flip',1); 33 | opts.pBoost.pTree.fracFtrs=1/16; opts.name='models/AcfCaltech'; 34 | pLoad={'lbls',{'person'},'ilbls',{'people'},'squarify',{3,.41}}; 35 | opts.pLoad = [pLoad 'hRng',[50 inf], 'vRng',[1 1] ]; 36 | 37 | %% train detector (see acfTrain) 38 | detector = acfTrain( opts ); 39 | 40 | %% modify detector (see acfModify) 41 | detector = acfModify(detector,'cascThr',-1,'cascCal',-.005); 42 | 43 | %% run detector on a sample image (see acfDetect) 44 | imgNms=bbGt('getFiles',{[dataDir 'test/images']}); 45 | I=imread(imgNms{1862}); tic, bbs=acfDetect(I,detector); toc 46 | figure(1); im(I); bbApply('draw',bbs); pause(.1); 47 | 48 | %% test detector and plot roc (see acfTest) 49 | [~,~,gt,dt]=acfTest('name',opts.name,'imgDir',[dataDir 'test/images'],... 50 | 'gtDir',[dataDir 'test/annotations'],'pLoad',[pLoad, 'hRng',[50 inf],... 51 | 'vRng',[.65 1],'xRng',[5 635],'yRng',[5 475]],'show',2); 52 | 53 | %% optionally show top false positives ('type' can be 'fp','fn','tp','dt') 54 | if( 0 ), bbGt('cropRes',gt,dt,imgNms,'type','fn','n',50,... 55 | 'show',3,'dims',opts.modelDs([2 1])); end 56 | -------------------------------------------------------------------------------- /utils/costFunction.m: -------------------------------------------------------------------------------- 1 | function [cost, fp, fn] = costFunction( tr1, tr2, THRESHOLD, world ) 2 | 3 | frames_gt = tr1(:,2); 4 | frames_pred = tr2(:,2); 5 | 6 | % If trajectories don't overlap in time then return cost or inf 7 | overlapTest = (frames_gt(1) >= frames_pred(1) && frames_gt(1) < frames_pred(end)) || ... 8 | (frames_gt(end) >= frames_pred(1) && frames_gt(end) <= frames_pred(end)) || ... 9 | (frames_pred(1) >= frames_gt(1) && frames_pred(1) <= frames_gt(end)) || ... 10 | (frames_pred(end) >= frames_gt(1) && frames_pred(end) <= frames_gt(end)); 11 | 12 | if ~overlapTest 13 | fp = length(frames_pred); 14 | fn = length(frames_gt); 15 | cost = fp + fn; 16 | return; 17 | end 18 | 19 | [isfoundGT, posGT] = ismember_mex(frames_gt, frames_pred); 20 | [isfoundPred, posPred] = ismember_mex(frames_pred, frames_gt); 21 | 22 | % Use points at infinity when no match exists 23 | columns = [7,8]; 24 | if ~world 25 | columns = [3 4 5 6]; 26 | end 27 | 28 | % Ground truth data and the corresponding data from the prediction 29 | pointsGT = tr1(isfoundGT, columns); 30 | pointsGTPred = tr2(posGT(isfoundGT),columns); 31 | 32 | % Prediction data and the corresponding data from ground truth 33 | pointsPred = tr2(isfoundPred, columns); 34 | pointsPredGT = tr1(posPred(isfoundPred),columns); 35 | 36 | unmatchedGT = sum(isfoundGT==0); 37 | unmatchedPred = sum(isfoundPred==0); 38 | 39 | distanceGTvsPred = distanceFunction(pointsGT, pointsGTPred, world); 40 | distancePredvsGT = distanceFunction(pointsPred, pointsPredGT, world); 41 | 42 | if world % Euclidean distance test 43 | fn = unmatchedGT + sum( distanceGTvsPred > THRESHOLD ); 44 | fp = unmatchedPred + sum( distancePredvsGT > THRESHOLD ); 45 | else % IntersectionOverUnion test 46 | fn = unmatchedGT + sum( distanceGTvsPred < THRESHOLD ); 47 | fp = unmatchedPred + sum( distancePredvsGT < THRESHOLD ); 48 | end 49 | cost = fp + fn; 50 | 51 | % Sanity check 52 | tp1 = length(frames_gt) - fn; 53 | tp2 = length(frames_pred) - fp; 54 | 55 | assert(tp1 == tp2, 'Something is wrong in the input. Make sure there are no duplicate frames...'); 56 | 57 | 58 | end 59 | 60 | function distance = distanceFunction(point1, point2, world) 61 | 62 | if world 63 | 64 | % Euclidean distance 65 | distance = sqrt(sum(abs(point1 - point2).^2,2)); 66 | 67 | else 68 | 69 | % Intersection_over_union 70 | box1 = point1; 71 | box2 = point2; 72 | 73 | area1 = box1(:,3) .* box1(:,4); 74 | area2 = box2(:,3) .* box2(:,4); 75 | 76 | l1 = box1(:,1); r1 = box1(:,1) + box1(:,3); t1 = box1(:,2); b1 = box1(:,2) + box1(:,4); 77 | l2 = box2(:,1); r2 = box2(:,1) + box2(:,3); t2 = box2(:,2); b2 = box2(:,2) + box2(:,4); 78 | 79 | x_overlap = max(0, min(r1,r2) - max(l1,l2)); 80 | y_overlap = max(0, min(b1,b2) - max(t1,t2)); 81 | intersectionArea = x_overlap .* y_overlap; 82 | unionArea = area1 + area2 - intersectionArea; 83 | iou = intersectionArea ./ unionArea; 84 | 85 | distance = iou; 86 | 87 | end 88 | 89 | 90 | 91 | end 92 | 93 | -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/acfDemoInria.m: -------------------------------------------------------------------------------- 1 | % Demo for aggregate channel features object detector on Inria dataset. 2 | % 3 | % (1) Download data and helper routines from Caltech Peds Website 4 | % www.vision.caltech.edu/Image_Datasets/CaltechPedestrians/ 5 | % (1a) Download INRIA files: set00.tar, set01.tar, and annotations.zip 6 | % (1b) Copy above three files to dataDir/ and untar/unzip contents 7 | % (1c) Download evaluation code (routines necessary for extracting images) 8 | % (2) Set dataDir/ variable below to point to location of INRIA data. 9 | % (3) Launch "matlabpool open" for faster training if available. 10 | % (4) Run demo script and enjoy your newly minted fast ped detector! 11 | % 12 | % Note: pre-trained model files are provided (delete to re-train). 13 | % Re-training may give slightly variable results on different machines. 14 | % 15 | % Piotr's Image&Video Toolbox Version 3.22 16 | % Copyright 2013 Piotr Dollar & Ron Appel. [pdollar-at-caltech.edu] 17 | % Please email me if you find bugs, or have suggestions or questions! 18 | % Licensed under the Simplified BSD License [see external/bsd.txt] 19 | 20 | %% extract training and testing images and ground truth 21 | dataDir = 'D:\code\research\detectorAcf\data\Inria\'; 22 | for s=1:2 23 | if(s==1), set='00'; type='train'; else set='01'; type='test'; end 24 | if(exist([dataDir type '/posGt'],'dir')), continue; end 25 | seqIo([dataDir 'set' set '/V000'],'toImgs',[dataDir type '/pos']); 26 | seqIo([dataDir 'set' set '/V001'],'toImgs',[dataDir type '/neg']); 27 | V=vbb('vbbLoad',[dataDir 'annotations/set' set '/V000']); 28 | vbb('vbbToFiles',V,[dataDir type '/posGt']); 29 | end 30 | 31 | %% set up opts for training detector (see acfTrain) 32 | opts=acfTrain(); opts.modelDs=[100 41]; opts.modelDsPad=[128 64]; 33 | opts.posGtDir=[dataDir 'train/posGt']; opts.nWeak=[32 128 512 2048]; 34 | opts.posImgDir=[dataDir 'train/pos']; opts.pJitter=struct('flip',1); 35 | opts.negImgDir=[dataDir 'train/neg']; opts.pBoost.pTree.fracFtrs=1/16; 36 | opts.pLoad={'squarify',{3,.41}}; opts.name='models/AcfInria'; 37 | 38 | %% train detector (see acfTrain) 39 | detector = acfTrain( opts ); 40 | 41 | %% modify detector (see acfModify) 42 | detector = acfModify(detector,'cascThr',-1,'cascCal',0); 43 | 44 | %% run detector on a sample image (see acfDetect) 45 | imgNms=bbGt('getFiles',{[dataDir 'test/pos']}); 46 | I=imread(imgNms{1}); tic, bbs=acfDetect(I,detector); toc 47 | figure(1); im(I); bbApply('draw',bbs); pause(.1); 48 | 49 | %% test detector and plot roc (see acfTest) 50 | [miss,~,gt,dt]=acfTest('name',opts.name,'imgDir',[dataDir 'test/pos'],... 51 | 'gtDir',[dataDir 'test/posGt'],'pLoad',opts.pLoad,'show',2); 52 | 53 | %% optional timing test for detector (should be ~30 fps) 54 | if( 0 ) 55 | detector1=acfModify(detector,'pad',[0 0]); n=60; Is=cell(1,n); 56 | for i=1:n, Is{i}=imResample(imread(imgNms{i}),[480 640]); end 57 | tic, for i=1:n, acfDetect(Is{i},detector1); end; 58 | fprintf('Detector runs at %.2f fps on 640x480 images.\n',n/toc); 59 | end 60 | 61 | %% optionally show top false positives ('type' can be 'fp','fn','tp','dt') 62 | if( 0 ), bbGt('cropRes',gt,dt,imgNms,'type','fn','n',50,... 63 | 'show',3,'dims',opts.modelDs([2 1])); end 64 | -------------------------------------------------------------------------------- /trackers/GOG/parseCameraParameters.m: -------------------------------------------------------------------------------- 1 | function camPar=parseCameraParameters(camconffile) 2 | % 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | xDoc=xmlread(fullfile(camconffile)); 13 | 14 | width=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('width')); 15 | height=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('height')); 16 | 17 | ncx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('ncx')); 18 | nfx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('nfx')); 19 | dx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dx')); 20 | dy=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dy')); 21 | dpx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dpx')); 22 | dpy=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dpy')); 23 | 24 | focal=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('focal')); 25 | kappa1=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('kappa1')); 26 | cx=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('cx')); 27 | cy=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('cy')); 28 | sx=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('sx')); 29 | 30 | tx=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('tx')); 31 | ty=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('ty')); 32 | tz=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('tz')); 33 | rx=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('rx')); 34 | ry=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('ry')); 35 | rz=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('rz')); 36 | 37 | mGeo.mImgWidth = width; 38 | mGeo.mImgHeight = height; 39 | mGeo.mNcx = ncx; 40 | mGeo.mNfx = nfx; 41 | mGeo.mDx = dx; 42 | mGeo.mDy = dy; 43 | mGeo.mDpx = dpx; 44 | mGeo.mDpy = dpy; 45 | 46 | 47 | %% intrinsic 48 | mInt.mFocal = focal; 49 | mInt.mKappa1 = kappa1; 50 | mInt.mCx = cx; 51 | mInt.mCy = cy; 52 | mInt.mSx = sx; 53 | 54 | %% extrinsic 55 | mExt.mTx = tx; 56 | mExt.mTy = ty; 57 | mExt.mTz = tz; 58 | mExt.mRx = rx; 59 | mExt.mRy = ry; 60 | mExt.mRz = rz; 61 | 62 | %% inverted 63 | mT=[tx;ty;tz]; 64 | sa = sin(rx); 65 | ca = cos(rx); 66 | sb = sin(ry); 67 | cb = cos(ry); 68 | sg = sin(rz); 69 | cg = cos(rz); 70 | 71 | mR11 = cb * cg; 72 | mR12 = cg * sa * sb - ca * sg; 73 | mR13 = sa * sg + ca * cg * sb; 74 | mR21 = cb * sg; 75 | mR22 = sa * sb * sg + ca * cg; 76 | mR23 = ca * sb * sg - cg * sa; 77 | mR31 = -sb; 78 | mR32 = cb * sa; 79 | mR33 = ca * cb; 80 | 81 | mR=[mR11 mR12 mR13; 82 | mR21 mR22 mR23; 83 | mR31 mR32 mR33]; 84 | 85 | transform=[mR mT;[0 0 0 1]]; 86 | invtrans=inv(transform); 87 | tx=invtrans(1,4);ty=invtrans(2,4);tz=invtrans(3,4); 88 | 89 | mExt.mTxi = tx; 90 | mExt.mTyi = ty; 91 | mExt.mTzi = tz; 92 | 93 | camPar.mExt=mExt; 94 | camPar.mInt=mInt; 95 | camPar.mGeo=mGeo; 96 | 97 | %% mkappa<0 98 | if kappa1<0 99 | warning('CAREFUL! kappa1 < 0, cam derivates are wrong!'); 100 | end 101 | 102 | [camPar.mR camPar.mT]=getRotTrans(camPar); 103 | 104 | end -------------------------------------------------------------------------------- /trackers/GOG/utils/parseCameraParameters.m: -------------------------------------------------------------------------------- 1 | function camPar=parseCameraParameters(camconffile) 2 | % 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | xDoc=xmlread(fullfile(camconffile)); 13 | 14 | width=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('width')); 15 | height=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('height')); 16 | 17 | ncx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('ncx')); 18 | nfx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('nfx')); 19 | dx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dx')); 20 | dy=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dy')); 21 | dpx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dpx')); 22 | dpy=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dpy')); 23 | 24 | focal=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('focal')); 25 | kappa1=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('kappa1')); 26 | cx=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('cx')); 27 | cy=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('cy')); 28 | sx=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('sx')); 29 | 30 | tx=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('tx')); 31 | ty=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('ty')); 32 | tz=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('tz')); 33 | rx=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('rx')); 34 | ry=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('ry')); 35 | rz=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('rz')); 36 | 37 | mGeo.mImgWidth = width; 38 | mGeo.mImgHeight = height; 39 | mGeo.mNcx = ncx; 40 | mGeo.mNfx = nfx; 41 | mGeo.mDx = dx; 42 | mGeo.mDy = dy; 43 | mGeo.mDpx = dpx; 44 | mGeo.mDpy = dpy; 45 | 46 | 47 | %% intrinsic 48 | mInt.mFocal = focal; 49 | mInt.mKappa1 = kappa1; 50 | mInt.mCx = cx; 51 | mInt.mCy = cy; 52 | mInt.mSx = sx; 53 | 54 | %% extrinsic 55 | mExt.mTx = tx; 56 | mExt.mTy = ty; 57 | mExt.mTz = tz; 58 | mExt.mRx = rx; 59 | mExt.mRy = ry; 60 | mExt.mRz = rz; 61 | 62 | %% inverted 63 | mT=[tx;ty;tz]; 64 | sa = sin(rx); 65 | ca = cos(rx); 66 | sb = sin(ry); 67 | cb = cos(ry); 68 | sg = sin(rz); 69 | cg = cos(rz); 70 | 71 | mR11 = cb * cg; 72 | mR12 = cg * sa * sb - ca * sg; 73 | mR13 = sa * sg + ca * cg * sb; 74 | mR21 = cb * sg; 75 | mR22 = sa * sb * sg + ca * cg; 76 | mR23 = ca * sb * sg - cg * sa; 77 | mR31 = -sb; 78 | mR32 = cb * sa; 79 | mR33 = ca * cb; 80 | 81 | mR=[mR11 mR12 mR13; 82 | mR21 mR22 mR23; 83 | mR31 mR32 mR33]; 84 | 85 | transform=[mR mT;[0 0 0 1]]; 86 | invtrans=inv(transform); 87 | tx=invtrans(1,4);ty=invtrans(2,4);tz=invtrans(3,4); 88 | 89 | mExt.mTxi = tx; 90 | mExt.mTyi = ty; 91 | mExt.mTzi = tz; 92 | 93 | camPar.mExt=mExt; 94 | camPar.mInt=mInt; 95 | camPar.mGeo=mGeo; 96 | 97 | %% mkappa<0 98 | if kappa1<0 99 | warning('CAREFUL! kappa1 < 0, cam derivates are wrong!'); 100 | end 101 | 102 | [camPar.mR camPar.mT]=getRotTrans(camPar); 103 | 104 | end -------------------------------------------------------------------------------- /trackers/GOG/tracking_push_relabel.m: -------------------------------------------------------------------------------- 1 | function [res] = tracking_push_relabel(dres, c_en, c_ex, c_ij, betta, max_it) 2 | 3 | dnum = length(dres.x); 4 | 5 | dres.c = betta - dres.r; %% cost for each detection window 6 | 7 | %%% The mex function works with large numbers. 8 | dres.c = dres.c *1e6; 9 | c_en = c_en *1e6; 10 | c_ex = c_ex *1e6; 11 | c_ij = c_ij *1e6; 12 | 13 | n_nodes = 2*dnum+2; %% number of nodes in the graph 14 | n_edges = 0; 15 | 16 | dat_in = zeros(1e7,3); %% each row represents an edge from node in column 1 to node in column 2 with cost in column 3. 17 | k_dat = 0; 18 | for i = 1:dnum 19 | k_dat = k_dat+3; 20 | dat_in(k_dat-2,:) = [1 2*i c_en ]; 21 | dat_in(k_dat-1,:) = [2*i 2*i+1 dres.c(i) ]; 22 | dat_in(k_dat,:) = [2*i+1 n_nodes c_ex ]; 23 | end 24 | for i=1:dnum 25 | f2 = dres.nei(i).inds; 26 | for j = 1:length(f2) 27 | k_dat = k_dat+1; 28 | dat_in(k_dat,:) = [2*f2(j)+1 2*i c_ij]; 29 | end 30 | end 31 | dat_in = [dat_in repmat([0 1],size(dat_in,1),1)]; %% add two columns: 0 for min capacity in column 4 and 1 for max capacity in column 5 for all edges. 32 | 33 | excess_node = [1 n_nodes]; %% push flow in the first node and collect it in the last node. 34 | 35 | k = 0; 36 | dat2_old = [0 0 0]; 37 | 38 | inds_all = []; 39 | tic 40 | lb=1; 41 | ub=1e4; 42 | tr_num_old = 1; 43 | 44 | tic 45 | 46 | while ub-lb > 1 %% bisection search for the optimum amount of flow. This can be implemented by Golden section search more efficiently. 47 | tr_num = round((lb+ub)/2); 48 | 49 | [cost_l, dat_l] = cs2_func(dat_in(1:k_dat,:), excess_node, [tr_num -tr_num]); %% try flow = tr_num 50 | [cost_u, dat_u] = cs2_func(dat_in(1:k_dat,:), excess_node, [tr_num+1 -tr_num-1]); %% try flow = tr_num+1 51 | if cost_u-cost_l > 0 52 | ub = tr_num; 53 | else 54 | lb = tr_num; 55 | end 56 | k=k+1; 57 | end 58 | 59 | if cost_u < cost_l 60 | dat1 = dat_u; 61 | else 62 | cost1 = cost_l; 63 | dat1 = dat_l; 64 | end 65 | 66 | %%%% backtrack tracks to get ids 67 | tmp = find( dat1(:, 1) == 1); 68 | start = dat1(tmp, 2); %% starting nodes; is even 69 | 70 | tmp = find( ~mod(dat1(:, 1), 2) .* (dat1(:, 2)-dat1(:, 1) == 11) ); 71 | detcs = dat1(tmp, 1); %% detection nodes; is even 72 | 73 | tmp = find( mod(dat1(:, 1), 2) .* ~mod(dat1(:, 2), 2) .* (dat1(:, 2)-dat1(:, 1) ~= 1) ); 74 | links = dat1(tmp, 1:2); %% links; is [even odd] 75 | 76 | res_inds = zeros(1, 1e5); 77 | res_ids = zeros(1, 1e5); 78 | 79 | k = 0; 80 | for i = 1:length(start); %% for each track 81 | this1 = start(i); 82 | while this1 ~= n_nodes 83 | k = k+1; 84 | res_inds(k) = this1/2; 85 | res_ids(k) = i; 86 | this1 = links(find(links(:,1) == this1+1), 2); %% should have only one value 87 | if mod(this1, 2) + (length(this1) ~= 1) %% sanity check 88 | display('error in the output of solver'); 89 | end 90 | end 91 | end 92 | res_inds = res_inds(1:k); %% only these detection windows are used in tracks. 93 | res_ids = res_ids(1:k); %% track id for each detection window 94 | 95 | %%% Calculate the cost value to sort tracks 96 | this_cost = zeros(1, max(res_ids)); 97 | for i = 1:max(res_ids) %% for each track 98 | inds = find(res_ids == i); 99 | len1= length(inds); 100 | track_cost(i) = sum(dres.c(res_inds(inds))) + (len1-1) * c_ij + c_en + c_ex; 101 | end 102 | [dummy sort_inds] = sort(track_cost); 103 | 104 | for i = 1:length(sort_inds) 105 | res_ids_sorted(res_ids == sort_inds(i)) = i; 106 | end 107 | 108 | res = sub(dres, res_inds); 109 | res.id = res_ids_sorted(:); 110 | 111 | % [dummy tmp] = sort(res.id); 112 | % res = sub(res,tmp); 113 | % % res = sub(dres,inds_all_its(1).inds); 114 | % % res.r = res.r/1e6; 115 | 116 | -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/acfDetect.m: -------------------------------------------------------------------------------- 1 | function bbs = acfDetect( I, detector, fileName ) 2 | % Run aggregate channel features object detector on given image(s). 3 | % 4 | % The input 'I' can either be a single image (or filename) or a cell array 5 | % of images (or filenames). In the first case, the return is a set of bbs 6 | % where each row has the format [x y w h score] and score is the confidence 7 | % of detection. If the input is a cell array, the output is a cell array 8 | % where each element is a set of bbs in the form above (in this case a 9 | % parfor loop is used to speed execution). If 'fileName' is specified, the 10 | % bbs are saved to a comma separated text file and the output is set to 11 | % bbs=1. If saving detections for multiple images the output is stored in 12 | % the format [imgId x y w h score] and imgId is a one-indexed image id. 13 | % 14 | % A cell of detectors trained with the same channels can be specified, 15 | % detected bbs from each detector are concatenated. If using multiple 16 | % detectors and opts.pNms.separate=1 then each bb has a sixth element 17 | % bbType=j, where j is the j-th detector, see bbNms.m for details. 18 | % 19 | % USAGE 20 | % bbs = acfDetect( I, detector, [fileName] ) 21 | % 22 | % INPUTS 23 | % I - input image(s) of filename(s) of input image(s) 24 | % detector - detector(s) trained via acfTrain 25 | % fileName - [] target filename (if specified return is 1) 26 | % 27 | % OUTPUTS 28 | % bbs - [nx5] array of bounding boxes or cell array of bbs 29 | % 30 | % EXAMPLE 31 | % 32 | % See also acfTrain, acfModify, bbGt>loadAll, bbNms 33 | % 34 | % Piotr's Image&Video Toolbox Version 3.20 35 | % Copyright 2013 Piotr Dollar & Ron Appel. [pdollar-at-caltech.edu] 36 | % Please email me if you find bugs, or have suggestions or questions! 37 | % Licensed under the Simplified BSD License [see external/bsd.txt] 38 | 39 | % run detector on every image 40 | if(nargin<3), fileName=''; end; multiple=iscell(I); 41 | if(~isempty(fileName) && exist(fileName,'file')), bbs=1; return; end 42 | if(~multiple), bbs=acfDetectImg(I,detector); else 43 | n=length(I); bbs=cell(n,1); 44 | for i=1:n, 45 | if ~mod(i,10), fprintf('.'); end 46 | bbs{i}=acfDetectImg(I{i},detector); 47 | end 48 | fprintf('\n'); 49 | end 50 | 51 | % write results to disk if fileName specified 52 | if(isempty(fileName)), return; end 53 | d=fileparts(fileName); if(~isempty(d)&&~exist(d,'dir')), mkdir(d); end 54 | if( multiple ) % add image index to each bb and flatten result 55 | for i=1:n, bbs{i}=[ones(size(bbs{i},1),1)*i bbs{i}]; end 56 | bbs=cell2mat(bbs); 57 | end 58 | dlmwrite(fileName,bbs); bbs=1; 59 | 60 | end 61 | 62 | function bbs = acfDetectImg( I, detector ) 63 | % Run trained sliding-window object detector on given image. 64 | Ds=detector; if(~iscell(Ds)), Ds={Ds}; end; nDs=length(Ds); 65 | opts=Ds{1}.opts; pPyramid=opts.pPyramid; pNms=opts.pNms; 66 | imreadf=opts.imreadf; imreadp=opts.imreadp; 67 | shrink=pPyramid.pChns.shrink; pad=pPyramid.pad; 68 | separate=nDs>1 && isfield(pNms,'separate') && pNms.separate; 69 | % perform actual computations 70 | if(all(ischar(I))), I=feval(imreadf,I,imreadp{:}); end 71 | P = chnsPyramid(I,pPyramid); bbs = cell(P.nScales,nDs); 72 | for i=1:P.nScales 73 | for j=1:nDs, opts=Ds{j}.opts; 74 | modelDsPad=opts.modelDsPad; modelDs=opts.modelDs; 75 | bb = acfDetect1(P.data{i},Ds{j}.clf,shrink,... 76 | modelDsPad(1),modelDsPad(2),opts.stride,opts.cascThr); 77 | shift=(modelDsPad-modelDs)/2-pad; 78 | bb(:,1)=(bb(:,1)+shift(2))/P.scaleshw(i,2); 79 | bb(:,2)=(bb(:,2)+shift(1))/P.scaleshw(i,1); 80 | bb(:,3)=modelDs(2)/P.scales(i); 81 | bb(:,4)=modelDs(1)/P.scales(i); 82 | if(separate), bb(:,6)=j; end; bbs{i,j}=bb; 83 | end 84 | end; bbs=cat(1,bbs{:}); 85 | if(~isempty(pNms)), bbs=bbNms(bbs,pNms); end 86 | end 87 | -------------------------------------------------------------------------------- /utils/IDmeasures.m: -------------------------------------------------------------------------------- 1 | % Tracking Performance Measures as described in the paper: 2 | % 3 | % Performance Measures and a Data Set for Multi-Target, Multi-Camera Tracking. 4 | % E. Ristani, F. Solera, R. S. Zou, R. Cucchiara and C. Tomasi. 5 | % ECCV 2016 Workshop on Benchmarking Multi-Target Tracking. 6 | % 7 | % Ergys Ristani 8 | % Duke University 2016 9 | 10 | function [measures] = IDmeasures( groundTruthMat, predictionMat, threshold, world ) 11 | % Input: 12 | % groundTruthMat - frame, ID, left, top, width, height, worldX, worldY 13 | % predictionMat - frame, ID, left, top, width, height, worldX, worldY 14 | % threshold - Ground plane distance (1m) or intersection_over_union 15 | % world - boolean paramenter determining if the evaluation is 16 | % done in the world ground plane or in the image plane 17 | 18 | % Convert input trajectories from .top format to cell arrays. Each cell has 19 | % data for one identity. 20 | idsPred = unique(predictionMat(:,2)); 21 | idsGT = unique(groundTruthMat(:,2)); 22 | ground_truth = cell(length(idsGT),1); 23 | prediction = cell(length(idsPred),1); 24 | for i = 1:length(idsGT) 25 | ground_truth{i} = groundTruthMat(groundTruthMat(:,2) == idsGT(i),:); 26 | end 27 | for i = 1:length(idsPred) 28 | prediction{i} = predictionMat(predictionMat(:,2) == idsPred(i),:); 29 | end 30 | 31 | % Initialize cost matrix blocks 32 | cost = zeros(length(prediction) + length(ground_truth)); 33 | cost( length(ground_truth) + 1:end, 1:length(prediction)) = inf; 34 | cost( 1:length(ground_truth), length(prediction) + 1 : end) = inf; 35 | 36 | fp = zeros(size(cost)); 37 | fn = zeros(size(cost)); 38 | 39 | % Compute cost block 40 | [costBlock, fpBlock, fnBlock] = costBlockMex(ground_truth, prediction, threshold, world); 41 | % for i = 1:length(ground_truth) 42 | % for j = 1:length(prediction) 43 | % [cost(i,j), fp(i,j), fn(i,j)] = costFunction(ground_truth{i}, prediction{j}, threshold, world); 44 | % end 45 | % end 46 | cost(1:size(costBlock,1),1:size(costBlock,2)) = costBlock; 47 | fp(1:size(costBlock,1),1:size(costBlock,2)) = fpBlock; 48 | fn(1:size(costBlock,1),1:size(costBlock,2)) = fnBlock; 49 | 50 | % Compute FP block 51 | for i = 1:length(prediction) 52 | cost(i+length(ground_truth),i) = size(prediction{i},1); 53 | fp(i+length(ground_truth),i) = size(prediction{i},1); 54 | end 55 | 56 | % Compute FN block 57 | for i = 1:length(ground_truth) 58 | cost(i,i+length(prediction)) = size(ground_truth{i},1); 59 | fn(i,i+length(prediction)) = size(ground_truth{i},1); 60 | 61 | end 62 | 63 | % Solve truth-to-result identity matching 64 | [optimalMatch, totalCost] = MinCostMatching(cost); 65 | for i = 1:size(optimalMatch,1) 66 | assignment(i) = find(optimalMatch(i,:)); 67 | end 68 | 69 | % For visualization 70 | % solutionMatrix = zeros(size(cost)); 71 | % for i = 1:length(assignment), solutionMatrix(i,assignment(i)) = 1; end 72 | 73 | numGT = sum(cellfun(@(x) size(x,1), ground_truth)); 74 | numPRED = sum(cellfun(@(x) size(x,1), prediction)); 75 | 76 | % Count assignment errors 77 | IDFP = 0; 78 | IDFN = 0; 79 | for i = 1:length(assignment) 80 | IDFP = IDFP + fp(i,assignment(i)); 81 | IDFN = IDFN + fn(i,assignment(i)); 82 | end 83 | 84 | IDTP = numGT - IDFN; 85 | % Sanity check 86 | assert(IDTP == numPRED - IDFP); 87 | 88 | IDPrecision = IDTP / (IDTP + IDFP); 89 | if numPRED == 0, IDPrecision = 0; end 90 | IDRecall = IDTP / (IDTP + IDFN); 91 | IDF1 = 2*IDTP/(numGT + numPRED); 92 | 93 | measures.IDP = IDPrecision * 100; 94 | measures.IDR = IDRecall * 100; 95 | measures.IDF1 = IDF1 * 100; 96 | measures.numGT = numGT; 97 | measures.numPRED = numPRED; 98 | measures.IDTP = IDTP; 99 | measures.IDFP = IDFP; 100 | measures.IDFN = IDFN; 101 | 102 | 103 | -------------------------------------------------------------------------------- /utils/convertMatToStruct.m: -------------------------------------------------------------------------------- 1 | function stInfo=convertMatToStruct(allData, gtMaxFrame) 2 | 3 | numCols=size(allData,2); 4 | numLines=size(allData,1); 5 | 6 | % quickly check format 7 | assert(numCols>=7,'FORMAT ERROR: Each line must have at least 6 values'); 8 | % assert(all(allData(:,1)>0),'FORMAT ERROR: Frame numbers must be positive.'); 9 | % assert(all(allData(:,2)>0),'FORMAT ERROR: IDs must be positive.'); 10 | 11 | IDMap = unique(allData(:,2))'; 12 | nIDs = length(IDMap); 13 | % fprintf('%d unique targets IDs discovered\n',nIDs); 14 | % pause 15 | 16 | % do we have bbox coordinates? 17 | imCoord=0; 18 | if any(any(allData(:,3:6)~= -1)) 19 | imCoord=1; 20 | end 21 | 22 | % do we have world coordinates? 23 | worldCoord=0; 24 | 25 | % ... we do if they exist and are not -1 (default) 26 | if size(allData,2)>=9 27 | if any(any(allData(:,[8 9])~= -1)) 28 | worldCoord=1; 29 | end 30 | end 31 | 32 | % at least one representation must be defined 33 | assert(imCoord || worldCoord, ... 34 | 'FORMAT ERROR: Neither bounding boxes nor world coorsinates defined.'); 35 | 36 | % go through all lines 37 | for l=numLines:-1:1 38 | lineData=allData(l,:); 39 | 40 | fr = lineData(1); % frame number 41 | id = lineData(2); % target id 42 | 43 | % map id to 1..nIDs 44 | id = find(IDMap==id); 45 | 46 | %%%% sanity checks 47 | % ignore non-positive frames and IDs 48 | if fr<1, 49 | continue; 50 | end 51 | 52 | % bounding box 53 | stInfo.W(fr,id) = lineData(5); 54 | stInfo.H(fr,id) = lineData(6); 55 | stInfo.Xi(fr,id) = lineData(3) + stInfo.W(fr,id)/2; 56 | stInfo.Yi(fr,id) = lineData(4) + stInfo.H(fr,id); 57 | 58 | % values should not be exactly 0 59 | if ~stInfo.W(fr,id) 60 | stInfo.W(fr,id) = stInfo.W(fr,id) + 0.0001; 61 | end 62 | if ~stInfo.H(fr,id) 63 | stInfo.H(fr,id) = stInfo.H(fr,id) + 0.0001; 64 | end 65 | if ~stInfo.Xi(fr,id) 66 | stInfo.Xi(fr,id) = stInfo.Xi(fr,id) + 0.0001; 67 | end 68 | if ~stInfo.Yi(fr,id) 69 | stInfo.Yi(fr,id) = stInfo.Yi(fr,id) + 0.0001; 70 | end 71 | % consider 3D coordinates 72 | if worldCoord 73 | stInfo.Xgp(fr,id) = lineData(7); 74 | stInfo.Ygp(fr,id) = lineData(8); 75 | 76 | % position should not be exactly 0 77 | if ~stInfo.Xgp(fr,id) 78 | stInfo.Xgp(fr,id)=stInfo.Xgp(fr,id)+0.0001; 79 | end 80 | if ~stInfo.Ygp(fr,id) 81 | stInfo.Ygp(fr,id)=stInfo.Ygp(fr,id)+0.0001; 82 | end 83 | end 84 | end 85 | 86 | % append empty frames? 87 | if gtMaxFrame ~= -1 88 | 89 | Fgt=gtMaxFrame; 90 | F=size(stInfo.W,1); 91 | % if stateInfo shorter, pad with zeros 92 | if F max(gtMat{ind}(:,1)),:) = []; % clip result to gtMaxFrame 84 | resMat{ind} = resdata; 85 | % split the result for each object category 86 | ressortdata = classSplit(resdata); 87 | % evaluate sequence 88 | tendMets = classEval(gtsortdata, ressortdata, allMets, ind, evalClassSet, sequenceName); 89 | tendallMets = [tendallMets,tendMets]; 90 | tendmetsBenchmark = evaluateBenchmark(tendMets, world); 91 | fprintf(' ********************* Sequence %s Results *********************\n', sequenceName); 92 | printMetrics(tendmetsBenchmark); 93 | allresult = cat(1, allresult, tendmetsBenchmark); 94 | end 95 | 96 | %% calculate overall scores 97 | metsBenchmark = evaluateBenchmark(tendallMets, world); 98 | allresult = cat(1, allresult, metsBenchmark); 99 | fprintf('\n'); 100 | fprintf(' ********************* Your VisDrone2019 Results *********************\n'); 101 | printMetrics(metsBenchmark); 102 | fprintf('\n'); 103 | 104 | %% calculate overall scores for each object category 105 | for k = 1:length(evalClassSet) 106 | className = evalClassSet{k}; 107 | cateallMets = []; 108 | curInd = k:length(evalClassSet):length(tendallMets); 109 | for i = 1:length(curInd) 110 | cateallMets = [cateallMets, tendallMets(curInd(i))]; 111 | end 112 | metsCategory = evaluateBenchmark(cateallMets, world); 113 | metsCategory(isnan(metsCategory)) = 0; 114 | fprintf('evaluating tracking %s:\n', className); 115 | printMetrics(metsCategory); 116 | fprintf('\n'); 117 | end 118 | -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/acfModify.m: -------------------------------------------------------------------------------- 1 | function detector = acfModify( detector, varargin ) 2 | % Modify aggregate channel features object detector. 3 | % 4 | % Takes an object detector trained by acfTrain() and modifies it. Only 5 | % certain modifications are allowed to the detector and the detector should 6 | % never be modified directly (this may cause the detector to be invalid and 7 | % cause segmentation faults). Any valid modification to a detector after it 8 | % is trained should be performed using acfModify(). 9 | % 10 | % The parameters 'nPerOct', 'nOctUp', 'nApprox', 'lambdas', 'pad', 'minDs' 11 | % modify the channel feature pyramid created (see help of chnsPyramid.m for 12 | % more details) and primarily control the scales used. The parameters 13 | % 'pNms', 'stride', 'cascThr' and 'cascCal' modify the detector behavior 14 | % (see help of acfTrain.m for more details). Finally, 'rescale' can be 15 | % used to rescale the trained detector (this change is irreversible). 16 | % 17 | % USAGE 18 | % detector = acfModify( detector, pModify ) 19 | % 20 | % INPUTS 21 | % detector - detector trained via acfTrain 22 | % pModify - parameters (struct or name/value pairs) 23 | % .nPerOct - [] number of scales per octave 24 | % .nOctUp - [] number of upsampled octaves to compute 25 | % .nApprox - [] number of approx. scales to use 26 | % .lambdas - [] coefficients for power law scaling (see BMVC10) 27 | % .pad - [] amount to pad channels (along T/B and L/R) 28 | % .minDs - [] minimum image size for channel computation 29 | % .pNms - [] params for non-maximal suppression (see bbNms.m) 30 | % .stride - [] spatial stride between detection windows 31 | % .cascThr - [] constant cascade threshold (affects speed/accuracy) 32 | % .cascCal - [] cascade calibration (affects speed/accuracy) 33 | % .rescale - [] rescale entire detector by given ratio 34 | % 35 | % OUTPUTS 36 | % detector - modified object detector 37 | % 38 | % EXAMPLE 39 | % 40 | % See also chnsPyramid, bbNms, acfTrain, acfDetect 41 | % 42 | % Piotr's Image&Video Toolbox Version 3.20 43 | % Copyright 2013 Piotr Dollar & Ron Appel. [pdollar-at-caltech.edu] 44 | % Please email me if you find bugs, or have suggestions or questions! 45 | % Licensed under the Simplified BSD License [see external/bsd.txt] 46 | 47 | % get parameters (and copy to detector and pPyramid structs) 48 | opts=detector.opts; p=opts.pPyramid; 49 | dfs={ 'nPerOct',p.nPerOct, 'nOctUp',p.nOctUp, 'nApprox',p.nApprox, ... 50 | 'lambdas',p.lambdas, 'pad',p.pad, 'minDs',p.minDs, 'pNms',opts.pNms, ... 51 | 'stride',opts.stride,'cascThr',opts.cascThr,'cascCal',0,'rescale',1 }; 52 | [p.nPerOct,p.nOctUp,p.nApprox,p.lambdas,p.pad,p.minDs,opts.pNms,... 53 | opts.stride,opts.cascThr,cascCal,rescale] = getPrmDflt(varargin,dfs,1); 54 | 55 | % finalize pPyramid and opts 56 | p.complete=0; p.pChns.complete=0; p=chnsPyramid([],p); p=p.pPyramid; 57 | p.complete=1; p.pChns.complete=1; shrink=p.pChns.shrink; 58 | opts.stride=max(1,round(opts.stride/shrink))*shrink; 59 | opts.pPyramid=p; detector.opts=opts; 60 | 61 | % calibrate and rescale detector 62 | detector.clf.hs = detector.clf.hs+cascCal; 63 | if(rescale~=1), detector=detectorRescale(detector,rescale); end 64 | 65 | end 66 | 67 | function detector = detectorRescale( detector, rescale ) 68 | % Rescale detector by ratio rescale. 69 | opts=detector.opts; shrink=opts.pPyramid.pChns.shrink; 70 | bh=opts.modelDsPad(1)/shrink; bw=opts.modelDsPad(2)/shrink; 71 | opts.stride=max(1,round(opts.stride*rescale/shrink))*shrink; 72 | modelDsPad=round(opts.modelDsPad*rescale/shrink)*shrink; 73 | rescale=modelDsPad./opts.modelDsPad; opts.modelDsPad=modelDsPad; 74 | opts.modelDs=round(opts.modelDs.*rescale); detector.opts=opts; 75 | bh1=opts.modelDsPad(1)/shrink; bw1=opts.modelDsPad(2)/shrink; 76 | % move 0-indexed (x,y) location of each lookup feature 77 | clf=detector.clf; fids=clf.fids; is=find(clf.child>0); 78 | fids=double(fids(is)); n=length(fids); loc=zeros(n,3); 79 | loc(:,3)=floor(fids/bh/bw); fids=fids-loc(:,3)*bh*bw; 80 | loc(:,2)=floor(fids/bh); fids=fids-loc(:,2)*bh; loc(:,1)=fids; 81 | loc(:,1)=min(bh1-1,round(loc(:,1)*rescale(1))); 82 | loc(:,2)=min(bw1-1,round(loc(:,2)*rescale(2))); 83 | fids = loc(:,3)*bh1*bw1 + loc(:,2)*bh1 + loc(:,1); 84 | clf.fids(is)=int32(fids); 85 | % rescale thrs for all features (fpdw trick) 86 | nChns=[detector.info.nChns]; assert(max(loc(:,3)) 88 | lambdas=opts.pPyramid.lambdas; lambdas=sqrt(prod(rescale)).^-lambdas(k); 89 | clf.thrs(is)=clf.thrs(is).*lambdas(loc(:,3)+1)'; detector.clf=clf; 90 | end 91 | -------------------------------------------------------------------------------- /utils/external/dollar/toolbox/detector/evalDetections.m: -------------------------------------------------------------------------------- 1 | %% 2 | 3 | addpath(genpath('..')); 4 | addpath(genpath('../../../../scripts')); 5 | 6 | resDir = getResDir; 7 | dataDir = getDataDir; 8 | 9 | challenge = 2; % 2D MOT 2015 10 | % challenge = 5; % MOT16 11 | 12 | % eval all 13 | challenge = 2; % 2D MOT 2015 14 | challenge = 5; % MOT16 15 | 16 | detectorName = 'acf'; 17 | detectorName = 'dpm'; 18 | detectorName = 'fasterrcnndet-th-0'; 19 | % detectorName = ''; 20 | 21 | sequences=[]; 22 | % allSeq={'TUD-Stadtmitte'}; 23 | % sequences='PETS09-S2L1'; 24 | % sequences={'TUD-Stadtmitte','PETS09-S2L1'}; 25 | allSeq = parseSequences([0 challenge],dataDir); 26 | % allSeq = {'MOT16-01'} 27 | 28 | dt0=[]; 29 | gt0=[]; 30 | % for each sequence 31 | allFrCnt=0; 32 | for seq=allSeq 33 | 34 | [seqName, seqFolder, imgFolder, imgExt, F, dirImages] ... 35 | = getSeqInfo(seq, dataDir); 36 | 37 | 38 | % detFolder = [dataDir,seqName,filesep,'det',filesep]; 39 | % detFile = [detFolder,'det.txt']; 40 | [detFolder, detFile]=getDetInfo(seqName,dataDir,detectorName); 41 | 42 | % if ~exist(detFile,'file'), continue; end 43 | 44 | gtFolder= [dataDir,seqName,filesep,'gt',filesep]; 45 | gtFile = [gtFolder,'gt.txt']; 46 | 47 | detRaw=dlmread(detFile); 48 | gtRaw=dlmread(gtFile); 49 | 50 | 51 | 52 | for t=1:F 53 | allFrCnt=allFrCnt+1; 54 | exdet=find(detRaw(:,1)==t); 55 | bbox=detRaw(exdet,3:7); 56 | dt0{allFrCnt}=bbox; 57 | 58 | exgt=find(gtRaw(:,1)==t & gtRaw(:,8)==1); 59 | gt0{allFrCnt}=[gtRaw(exgt,3:6) zeros(length(exgt),1)]; 60 | 61 | end 62 | end 63 | 64 | allSeq = parseSequences([1 challenge],dataDir); 65 | % allSeq = {'MOT16-02'} 66 | 67 | dt1=[]; 68 | gt1=[]; 69 | 70 | % for each sequence 71 | allFrCnt1=0; 72 | for seq=allSeq 73 | 74 | [seqName, seqFolder, imgFolder, imgExt, F, dirImages] ... 75 | = getSeqInfo(seq, dataDir); 76 | 77 | 78 | % detFolder = [dataDir,seqName,filesep,'det',filesep]; 79 | % detFile = [detFolder,'det.txt']; 80 | [detFolder, detFile]=getDetInfo(seqName,dataDir,detectorName); 81 | % if ~exist(detFile,'file'), continue; end 82 | 83 | gtFolder= [dataDir,seqName,filesep,'gt',filesep]; 84 | gtFile = [gtFolder,'gt.txt']; 85 | 86 | detRaw=dlmread(detFile); 87 | gtRaw=dlmread(gtFile); 88 | 89 | 90 | for t=1:F 91 | allFrCnt1=allFrCnt1+1; 92 | exdet=find(detRaw(:,1)==t); 93 | bbox=detRaw(exdet,3:7); 94 | dt1{allFrCnt1}=bbox; 95 | 96 | exgt=find(gtRaw(:,1)==t & gtRaw(:,8)==1); 97 | gt1{allFrCnt1}=[gtRaw(exgt,3:6) zeros(length(exgt),1)]; 98 | 99 | end 100 | end 101 | 102 | 103 | 104 | % lims=[3.1e-3 1e1 .05 1]; 105 | lims=[0 1 0 1]; 106 | ref=10.^(-2:.25:0); 107 | ref=0:.1:1; 108 | 109 | %% 110 | clf; hold on; box on; 111 | 112 | % Training Set 113 | [gt,dt]=bbGt('evalRes',gt0,dt0); 114 | [fp,tp,score,miss] = bbGt('compRoc',gt,dt,0,ref); 115 | 116 | % Test Set 117 | [gt,dt]=bbGt('evalRes',gt1,dt1); 118 | [fp1,tp1,score1,miss1] = bbGt('compRoc',gt,dt,0,ref); 119 | 120 | set(gca,'FontSize',12) 121 | plot(fp,tp,'linewidth',2); 122 | plot(fp1,tp1,'linewidth',2,'color','r'); 123 | 124 | opX=fp(end); opY=tp(end); 125 | plot(opX,opY,'.','MarkerSize',25); 126 | opX1=fp1(end); opY1=tp1(end); 127 | plot(opX1,opY1,'.','MarkerSize',25,'color','r'); 128 | 129 | %% 130 | fs=22; 131 | set(gca,'FontSize',fs); 132 | text(opX+.25,opY+.1,sprintf('Rcll: %.1f %%\nPrc: %.1f %%',opX*100,opY*100),'VerticalAlignment','top','HorizontalAlignment','right','FontSize',fs-4); 133 | text(opX1-.05,opY1-.025,sprintf('Rcll: %.1f %%\nPrc: %.1f %%',opX1*100,opY1*100),'VerticalAlignment','top','HorizontalAlignment','right','FontSize',fs-4); 134 | xlim(lims(1:2)); ylim(lims(3:4)); 135 | 136 | 137 | xlabel('Recall'); ylabel('Precision'); 138 | title('Detector Performance'); 139 | legend('Training Set','Test Set'); 140 | 141 | % export_fig 'det-dollar.pdf' -png -pdf; 142 | % saveas(gcf,'det-dollar.pdf'); 143 | % saveas(gcf,'det-dollar.png'); 144 | % export_fig 'det-dollar.pdf' -transparent; 145 | pdfFileName = sprintf('det-%s.pdf',detectorName); 146 | export_fig(pdfFileName, '-transparent'); 147 | % export_fig '../../../../../../papers/2015/arxiv-benchmark/figures/det-dollar.pdf' -transparent; 148 | 149 | 150 | 151 | % miss=exp(mean(log(max(1e-10,1-miss)))); roc=[score fp tp]; 152 | % figure(show); plotRoc([fp tp],'logx',1,'logy',0,'xLbl','fppi',... 153 | % 'lims',lims,'color','g','smooth',1,'fpTarget',ref); 154 | % title(sprintf('log-average miss rate = %.2f%%',miss*100)); 155 | -------------------------------------------------------------------------------- /utils/convertTXTToStruct.m: -------------------------------------------------------------------------------- 1 | function stInfo=convertTXTToStruct(txtFile,seqFolder) 2 | % read CSV file and convert to Matlab struct format 3 | 4 | fprintf('Importing data from %s\n',txtFile); 5 | 6 | % if file empty, return empty (null) solution 7 | tf = dir(txtFile); 8 | if tf.bytes == 0 9 | 10 | F=0; 11 | emptySol = zeros(F,0); 12 | stInfo.X=emptySol; stInfo.Y=emptySol; stInfo.Xi=emptySol; stInfo.Yi=emptySol; 13 | stInfo.W=emptySol; stInfo.H=emptySol; stInfo.Xgp=emptySol; stInfo.Ygp=emptySol; 14 | return; 15 | end 16 | 17 | % load text file 18 | allData = dlmread(txtFile); 19 | numCols=size(allData,2); 20 | numLines=size(allData,1); 21 | 22 | % quickly check format 23 | assert(numCols>=7,'FORMAT ERROR: Each line must have at least 6 values'); 24 | % assert(all(allData(:,1)>0),'FORMAT ERROR: Frame numbers must be positive.'); 25 | % assert(all(allData(:,2)>0),'FORMAT ERROR: IDs must be positive.'); 26 | 27 | IDMap = unique(allData(:,2))'; 28 | nIDs = length(IDMap); 29 | % fprintf('%d unique targets IDs discovered\n',nIDs); 30 | % pause 31 | 32 | % do we have bbox coordinates? 33 | imCoord=0; 34 | if any(any(allData(:,3:6)~= -1)) 35 | imCoord=1; 36 | end 37 | 38 | % do we have world coordinates? 39 | worldCoord=0; 40 | 41 | % ... we do if they exist and are not -1 (default) 42 | if size(allData,2)>=9 43 | if any(any(allData(:,[8 9])~= -1)) 44 | worldCoord=1; 45 | end 46 | end 47 | 48 | % at least one representation must be defined 49 | assert(imCoord || worldCoord, ... 50 | 'FORMAT ERROR: Neither bounding boxes nor world coorsinates defined.'); 51 | 52 | % are we dealing with MOT16 ground truth? 53 | MOT16GT=false; 54 | if numCols==9 && ~isempty(strfind(seqFolder,'MOT16')) 55 | MOT16GT=true; 56 | end 57 | 58 | 59 | % go through all lines 60 | for l=1:numLines 61 | lineData=allData(l,:); 62 | 63 | % ignore 0-marked GT 64 | if ~lineData(7), continue; end 65 | 66 | % ignore non-pedestrians for MOT16 67 | if MOT16GT && lineData(8)~= 1, continue; end 68 | 69 | 70 | fr = lineData(1); % frame number 71 | id = lineData(2); % target id 72 | 73 | % map id to 1..nIDs 74 | id = find(IDMap==id); 75 | 76 | %%%% sanity checks 77 | % ignore non-positive frames and IDs 78 | if fr<1, continue; end 79 | 80 | % ignore too large frame numbers 81 | if fr>1e4, continue; end 82 | 83 | 84 | 85 | 86 | % bounding box 87 | stInfo.W(fr,id) = lineData(5); 88 | stInfo.H(fr,id) = lineData(6); 89 | stInfo.Xi(fr,id) = lineData(3) + stInfo.W(fr,id)/2; 90 | stInfo.Yi(fr,id) = lineData(4) + stInfo.H(fr,id); 91 | 92 | % consider 3D coordinates 93 | if worldCoord 94 | stInfo.Xgp(fr,id) = lineData(8); 95 | stInfo.Ygp(fr,id) = lineData(9); 96 | 97 | % position should not be exactly 0 98 | if ~stInfo.Xgp(fr,id) 99 | stInfo.Xgp(fr,id)=stInfo.Xgp(fr,id)+0.0001; 100 | end 101 | if ~stInfo.Ygp(fr,id) 102 | stInfo.Ygp(fr,id)=stInfo.Ygp(fr,id)+0.0001; 103 | end 104 | end 105 | end 106 | 107 | % append empty frames? 108 | if nargin>1 109 | imgFolders = dir(fullfile(seqFolder,filesep,'img*')); 110 | imgFolder = fullfile(seqFolder,imgFolders(1).name,filesep); 111 | imgExt=getImgExt(seqFolder); 112 | 113 | imgMask=[imgFolder,'*' imgExt]; 114 | dirImages = dir(imgMask); 115 | Fgt=length(dirImages); 116 | F=size(stInfo.W,1); 117 | % if stateInfo shorter, pad with zeros 118 | if F 9 | #include 10 | using namespace std; 11 | 12 | typedef unsigned int uint32; 13 | 14 | inline void getChild( float *chns1, uint32 *cids, uint32 *fids, 15 | float *thrs, uint32 offset, uint32 &k0, uint32 &k ) 16 | { 17 | float ftr = chns1[cids[fids[k]]]; 18 | k = (ftr rs, cs; vector hs1; 62 | for( int c=0; c2) { 80 | // specialized case for treeDepth>2 81 | for( int t = 0; t < nTrees; t++ ) { 82 | uint32 offset=t*nTreeNodes, k=offset, k0=0; 83 | for( int i=0; icascThr) { cs.push_back(c); rs.push_back(r); hs1.push_back(h); } 100 | } 101 | delete [] cids; m=cs.size(); 102 | 103 | // convert to bbs 104 | plhs[0] = mxCreateNumericMatrix(m,5,mxDOUBLE_CLASS,mxREAL); 105 | double *bbs = (double*) mxGetData(plhs[0]); 106 | for( int i=0; i 2 | #include 3 | #include 4 | #include 5 | using namespace std; 6 | // Min cost bipartite matching via shortest augmenting paths 7 | // 8 | // Code from https://github.com/jaehyunp/ 9 | // 10 | // This is an O(n^3) implementation of a shortest augmenting path 11 | // algorithm for finding min cost perfect matchings in dense 12 | // graphs. In practice, it solves 1000x1000 problems in around 1 13 | // second. 14 | // 15 | // cost[i][j] = cost for pairing left node i with right node j 16 | // Lmate[i] = index of right node that left node i pairs with 17 | // Rmate[j] = index of left node that right node j pairs with 18 | // 19 | // The values in cost[i][j] may be positive or negative. To perform 20 | // maximization, simply negate the cost[][] matrix. 21 | 22 | 23 | 24 | typedef vector VD; 25 | typedef vector VVD; 26 | typedef vector VI; 27 | 28 | double MinCostMatching(const VVD &cost, VI &Lmate, VI &Rmate) { 29 | int n = int(cost.size()); 30 | 31 | // construct dual feasible solution 32 | VD u(n); 33 | VD v(n); 34 | for (int i = 0; i < n; i++) { 35 | u[i] = cost[i][0]; 36 | for (int j = 1; j < n; j++) u[i] = min(u[i], cost[i][j]); 37 | } 38 | for (int j = 0; j < n; j++) { 39 | v[j] = cost[0][j] - u[0]; 40 | for (int i = 1; i < n; i++) v[j] = min(v[j], cost[i][j] - u[i]); 41 | } 42 | 43 | // construct primal solution satisfying complementary slackness 44 | Lmate = VI(n, -1); 45 | Rmate = VI(n, -1); 46 | int mated = 0; 47 | for (int i = 0; i < n; i++) { 48 | for (int j = 0; j < n; j++) { 49 | if (Rmate[j] != -1) continue; 50 | if (fabs(cost[i][j] - u[i] - v[j]) < 1e-10) { 51 | Lmate[i] = j; 52 | Rmate[j] = i; 53 | mated++; 54 | break; 55 | } 56 | } 57 | } 58 | 59 | VD dist(n); 60 | VI dad(n); 61 | VI seen(n); 62 | 63 | // repeat until primal solution is feasible 64 | while (mated < n) { 65 | 66 | // find an unmatched left node 67 | int s = 0; 68 | while (Lmate[s] != -1) s++; 69 | 70 | // initialize Dijkstra 71 | fill(dad.begin(), dad.end(), -1); 72 | fill(seen.begin(), seen.end(), 0); 73 | for (int k = 0; k < n; k++) 74 | dist[k] = cost[s][k] - u[s] - v[k]; 75 | 76 | int j = 0; 77 | while (true) { 78 | 79 | // find closest 80 | j = -1; 81 | for (int k = 0; k < n; k++) { 82 | if (seen[k]) continue; 83 | if (j == -1 || dist[k] < dist[j]) j = k; 84 | } 85 | seen[j] = 1; 86 | 87 | // termination condition 88 | if (Rmate[j] == -1) break; 89 | 90 | // relax neighbors 91 | const int i = Rmate[j]; 92 | for (int k = 0; k < n; k++) { 93 | if (seen[k]) continue; 94 | const double new_dist = dist[j] + cost[i][k] - u[i] - v[k]; 95 | if (dist[k] > new_dist) { 96 | dist[k] = new_dist; 97 | dad[k] = j; 98 | } 99 | } 100 | } 101 | 102 | // update dual variables 103 | for (int k = 0; k < n; k++) { 104 | if (k == j || !seen[k]) continue; 105 | const int i = Rmate[k]; 106 | v[k] += dist[k] - dist[j]; 107 | u[i] -= dist[k] - dist[j]; 108 | } 109 | u[s] += dist[j]; 110 | 111 | // augment along path 112 | while (dad[j] >= 0) { 113 | const int d = dad[j]; 114 | Rmate[j] = Rmate[d]; 115 | Lmate[Rmate[j]] = j; 116 | j = d; 117 | } 118 | Rmate[j] = s; 119 | Lmate[s] = j; 120 | 121 | mated++; 122 | } 123 | 124 | double value = 0; 125 | for (int i = 0; i < n; i++) 126 | value += cost[i][Lmate[i]]; 127 | 128 | return value; 129 | } 130 | 131 | void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] ) 132 | { 133 | /* Input arguments */ 134 | int nOfRows = mxGetM(prhs[0]); 135 | int nOfColumns = mxGetN(prhs[0]); 136 | double* distMatrix = mxGetPr(prhs[0]); 137 | 138 | /* Output arguments */ 139 | plhs[0] = mxCreateDoubleMatrix(nOfRows, nOfColumns, mxREAL); 140 | plhs[1] = mxCreateDoubleMatrix(1, 1, mxREAL); 141 | double *assignment = mxGetPr(plhs[0]); 142 | double *cost = mxGetPr(plhs[1]); 143 | 144 | if (nOfRows == 0 || nOfColumns == 0) 145 | return; 146 | 147 | /* Call C-function */ 148 | double INF = 1e8; 149 | int squareSize = max(nOfRows, nOfColumns); 150 | vector> alldist(squareSize, vector(squareSize, INF)); 151 | for (int i = 0; i < nOfRows; i++) 152 | { 153 | for (int j =0; j < nOfColumns; j++) 154 | { 155 | alldist[i][j] = distMatrix[j*nOfRows + i]; 156 | } 157 | } 158 | 159 | vector Lmate, Rmate; 160 | MinCostMatching(alldist, Lmate, Rmate); 161 | 162 | cost[0] = 0; 163 | for (int i = 0; i < nOfRows; i++) 164 | { 165 | if (Lmate[i] < nOfColumns && alldist[i][Lmate[i]] != INF) 166 | { 167 | assignment[Lmate[i] * nOfRows + i] = 1; 168 | cost[0] += alldist[i][Lmate[i]]; 169 | } 170 | } 171 | 172 | } 173 | 174 | -------------------------------------------------------------------------------- /utils/camera/parseCameraParameters.m: -------------------------------------------------------------------------------- 1 | function camPar=parseCameraParameters(camconffile) 2 | % 3 | % 4 | % (C) Anton Andriyenko, 2012 5 | % 6 | % The code may be used free of charge for non-commercial and 7 | % educational purposes, the only requirement is that this text is 8 | % preserved within the derivative work. For any other purpose you 9 | % must contact the authors for permission. This code may not be 10 | % redistributed without written permission from the authors. 11 | 12 | % if static cam 13 | % if isempty(strfind(camconffile,'%')) 14 | 15 | [pt fl ex]=fileparts(camconffile); 16 | if isequal(ex,'.mat') 17 | load(camconffile); 18 | return; 19 | else 20 | xDoc=xmlread(fullfile(camconffile)); 21 | 22 | camname=xDoc.getElementsByTagName('Camera').item(0).getAttribute('name'); 23 | if strcmpi(camname,'PRML_LAB') 24 | camPar.ortho=1; % Bird's eye view orthographic 25 | camPar.mR = str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('scale')); 26 | camPar.scale = camPar.mR; 27 | % fill in rest 28 | camPar.mT=0; 29 | camPar.mInt=0; 30 | camPar.mGeo=0; 31 | else 32 | camPar.ortho=0; % Bird's eye view orthographic 33 | width=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('width')); 34 | height=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('height')); 35 | 36 | ncx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('ncx')); 37 | nfx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('nfx')); 38 | dx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dx')); 39 | dy=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dy')); 40 | dpx=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dpx')); 41 | dpy=str2double(xDoc.getElementsByTagName('Geometry').item(0).getAttribute('dpy')); 42 | 43 | focal=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('focal')); 44 | kappa1=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('kappa1')); 45 | cx=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('cx')); 46 | cy=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('cy')); 47 | sx=str2double(xDoc.getElementsByTagName('Intrinsic').item(0).getAttribute('sx')); 48 | 49 | tx=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('tx')); 50 | ty=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('ty')); 51 | tz=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('tz')); 52 | rx=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('rx')); 53 | ry=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('ry')); 54 | rz=str2double(xDoc.getElementsByTagName('Extrinsic').item(0).getAttribute('rz')); 55 | 56 | mGeo.mImgWidth = width; 57 | mGeo.mImgHeight = height; 58 | mGeo.mNcx = ncx; 59 | mGeo.mNfx = nfx; 60 | mGeo.mDx = dx; 61 | mGeo.mDy = dy; 62 | mGeo.mDpx = dpx; 63 | mGeo.mDpy = dpy; 64 | 65 | 66 | %% intrinsic 67 | mInt.mFocal = focal; 68 | mInt.mKappa1 = kappa1; 69 | mInt.mCx = cx; 70 | mInt.mCy = cy; 71 | mInt.mSx = sx; 72 | 73 | %% extrinsic 74 | mExt.mTx = tx; 75 | mExt.mTy = ty; 76 | mExt.mTz = tz; 77 | mExt.mRx = rx; 78 | mExt.mRy = ry; 79 | mExt.mRz = rz; 80 | 81 | %% inverted 82 | mT=[tx;ty;tz]; 83 | sa = sin(rx); 84 | ca = cos(rx); 85 | sb = sin(ry); 86 | cb = cos(ry); 87 | sg = sin(rz); 88 | cg = cos(rz); 89 | 90 | mR11 = cb * cg; 91 | mR12 = cg * sa * sb - ca * sg; 92 | mR13 = sa * sg + ca * cg * sb; 93 | mR21 = cb * sg; 94 | mR22 = sa * sb * sg + ca * cg; 95 | mR23 = ca * sb * sg - cg * sa; 96 | mR31 = -sb; 97 | mR32 = cb * sa; 98 | mR33 = ca * cb; 99 | 100 | mR=[mR11 mR12 mR13; 101 | mR21 mR22 mR23; 102 | mR31 mR32 mR33]; 103 | 104 | transform=[mR mT;[0 0 0 1]]; 105 | invtrans=inv(transform); 106 | tx=invtrans(1,4);ty=invtrans(2,4);tz=invtrans(3,4); 107 | 108 | mExt.mTxi = tx; 109 | mExt.mTyi = ty; 110 | mExt.mTzi = tz; 111 | 112 | camPar.mExt=mExt; 113 | camPar.mInt=mInt; 114 | camPar.mGeo=mGeo; 115 | 116 | %% mkappa<0 117 | if kappa1<0 118 | warning('CAREFUL! kappa1 < 0, cam derivates are wrong!'); 119 | end 120 | 121 | [camPar.mR camPar.mT]=getRotTrans(camPar); 122 | % else 123 | % global sceneInfo 124 | % F=length(sceneInfo.frameNums); 125 | % for t=1:F 126 | % 127 | % end 128 | % end 129 | % end 130 | end 131 | end -------------------------------------------------------------------------------- /utils/costBlockMex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "mex.h" 3 | #include 4 | #include 5 | #include 6 | using namespace std; 7 | 8 | inline int index(int i, int j, int numRows) // 1-indexed to C 9 | { 10 | return (j-1)*numRows + i-1; 11 | } 12 | 13 | void correspondingFrames(double* frames1, int N, double* frames2, int M, int* loc) 14 | { 15 | int pos = 0; 16 | int i = 0; 17 | while (i < N && pos < M) { 18 | while (pos < M) { 19 | if (frames1[i] == frames2[pos]) { 20 | loc[i] = pos; pos++; i++; 21 | break; 22 | } 23 | else if (frames1[i] < frames2[pos]) { 24 | loc[i] = -1; i++; 25 | if (i == N) break; 26 | } 27 | else pos++; 28 | } 29 | } 30 | } 31 | 32 | void computeDistances(double* tr1, double* tr2, int numPoints1, int numPoints2, int* position, bool world, double* distance) 33 | { 34 | if (world) 35 | { 36 | double* wx1 = &tr1[index(1, 7, numPoints1)]; 37 | double* wy1 = &tr1[index(1, 8, numPoints1)]; 38 | double* wx2 = &tr2[index(1, 7, numPoints2)]; 39 | double* wy2 = &tr2[index(1, 8, numPoints2)]; 40 | 41 | for (int i = 0; i < numPoints1; i++) 42 | { 43 | if (position[i] == -1) 44 | distance[i] = 1e9; 45 | else 46 | { 47 | double dx = wx1[i] - wx2[position[i]]; 48 | double dy = wy1[i] - wy2[position[i]]; 49 | distance[i] = sqrt(dx*dx + dy*dy); 50 | } 51 | } 52 | } 53 | else 54 | { 55 | double* l1 = &tr1[index(1, 3, numPoints1)]; 56 | double* t1 = &tr1[index(1, 4, numPoints1)]; 57 | double* w1 = &tr1[index(1, 5, numPoints1)]; 58 | double* h1 = &tr1[index(1, 6, numPoints1)]; 59 | double* l2 = &tr2[index(1, 3, numPoints2)]; 60 | double* t2 = &tr2[index(1, 4, numPoints2)]; 61 | double* w2 = &tr2[index(1, 5, numPoints2)]; 62 | double* h2 = &tr2[index(1, 6, numPoints2)]; 63 | 64 | for (int i = 0; i < numPoints1; i++) 65 | { 66 | if (position[i] == -1) 67 | distance[i] = 0; 68 | else 69 | { 70 | double area1 = w1[i] * h1[i]; 71 | double area2 = w2[position[i]] * h2[position[i]]; 72 | 73 | double x_overlap = max(0.0, min(l1[i] + w1[i], l2[position[i]] + w2[position[i]]) - max(l1[i], l2[position[i]])); 74 | double y_overlap = max(0.0, min(t1[i] + h1[i], t2[position[i]] + h2[position[i]]) - max(t1[i], t2[position[i]])); 75 | double intersectionArea = x_overlap*y_overlap; 76 | double unionArea = area1 + area2 - intersectionArea; 77 | double iou = intersectionArea / unionArea; 78 | distance[i] = iou; 79 | } 80 | } 81 | } 82 | } 83 | 84 | void compute(double* tr1, double* tr2, const int* dim1, const int* dim2, double threshold, bool world, double& cost, double& fp, double& fn) 85 | { 86 | int numPoints1 = dim1[0]; 87 | int numPoints2 = dim2[0]; 88 | int numCols1 = dim1[1]; 89 | int numCols2 = dim2[1]; 90 | int tr1start, tr1end, tr2start, tr2end; 91 | tr1start = tr1[index(1,1, numPoints1)]; 92 | tr1end = tr1[index(numPoints1,1, numPoints1)]; 93 | tr2start = tr2[index(1,1, numPoints2)]; 94 | tr2end = tr2[index(numPoints2,1, numPoints2)]; 95 | 96 | 97 | bool overlapTest = ((tr1start >= tr2start && tr1start <= tr2end) || 98 | (tr1end >= tr2start && tr1end <= tr2end) || 99 | (tr2start >= tr1start && tr2start <= tr1end) || 100 | (tr2end >= tr1start && tr2end <= tr1end)); 101 | 102 | if (!overlapTest) 103 | { 104 | fp = numPoints2; 105 | fn = numPoints1; 106 | cost = numPoints1 + numPoints2; 107 | return; 108 | } 109 | 110 | int* positionGT = new int[numPoints1]; 111 | int* positionPred = new int[numPoints2]; 112 | for (int i = 0; i < numPoints1; i++) positionGT[i] = -1; 113 | for (int i = 0; i < numPoints2; i++) positionPred[i] = -1; 114 | double* distanceGT = new double[numPoints1]; 115 | double* distancePred = new double[numPoints2]; 116 | double* frames1 = &tr1[index(1, 1, numPoints1)]; 117 | double* frames2 = &tr2[index(1, 1, numPoints2)]; 118 | 119 | correspondingFrames(frames1, numPoints1, frames2, numPoints2, positionGT); 120 | correspondingFrames(frames2, numPoints2, frames1, numPoints1, positionPred); 121 | computeDistances(tr1, tr2, numPoints1, numPoints2, positionGT, world, distanceGT); 122 | computeDistances(tr2, tr1, numPoints2, numPoints1, positionPred, world, distancePred); 123 | 124 | fp = 0; fn = 0; 125 | if (world) { 126 | for (int i = 0; i < numPoints1; i++) if (distanceGT[i] > threshold) fn++; 127 | for (int i = 0; i < numPoints2; i++) if (distancePred[i] > threshold) fp++; 128 | } 129 | else { 130 | for (int i = 0; i < numPoints1; i++) if (distanceGT[i] < threshold) fn++; 131 | for (int i = 0; i < numPoints2; i++) if (distancePred[i] < threshold) fp++; 132 | } 133 | cost = fp + fn; 134 | 135 | delete[] positionGT; 136 | delete[] positionPred; 137 | delete[] distanceGT; 138 | delete[] distancePred; 139 | 140 | } 141 | 142 | 143 | 144 | 145 | 146 | void mexFunction(int nlhs, mxArray *plhs[], 147 | int nrhs, const mxArray *prhs[]) 148 | { 149 | 150 | int numGT = mxGetNumberOfElements(prhs[0]); 151 | int numPred = mxGetNumberOfElements(prhs[1]); 152 | int numEl = numGT + numPred; 153 | 154 | double threshold = (double)mxGetScalar(prhs[2]); 155 | bool world = (bool)mxGetScalar(prhs[3]); 156 | 157 | double *cost, *fp, *fn; 158 | plhs[0] = mxCreateDoubleMatrix(numGT, numPred, mxREAL); 159 | plhs[1] = mxCreateDoubleMatrix(numGT, numPred, mxREAL); 160 | plhs[2] = mxCreateDoubleMatrix(numGT, numPred, mxREAL); 161 | cost = mxGetPr(plhs[0]); 162 | fp = mxGetPr(plhs[1]); 163 | fn = mxGetPr(plhs[2]); 164 | 165 | #pragma omp parallel for 166 | for (int i = 0; i < numGT; i++) { 167 | #pragma omp parallel for 168 | for (int j = 0; j < numPred; j++) { 169 | 170 | 171 | const int *dim1, *dim2; 172 | dim1 = (int *)mxGetDimensions(mxGetCell(prhs[0], i)); 173 | dim2 = (int *)mxGetDimensions(mxGetCell(prhs[1], j)); 174 | double* tr1 = mxGetPr(mxGetCell(prhs[0],i)); 175 | double* tr2 = mxGetPr(mxGetCell(prhs[1],j)); 176 | int ind = j*numGT+ i; 177 | compute(tr1, tr2, dim1, dim2, threshold, world, cost[ind], fp[ind], fn[ind]); 178 | } 179 | } 180 | 181 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | VisDrone2018-MOT Benchmark Toolkit 2 | 3 | Introduction 4 | 5 | This is the documentation of the VisDrone2018 competitions development kit for multiple object tracking (MOT) challenge. 6 | 7 | This code library is for research purpose only, which is modified based on the toolkits in MOTChallenge [1] and PASCAL VOC [2]. 8 | 9 | The code is tested on the Windows 10 and macOS Sierra 10.12.6 systems, with the Matlab 2013a/2014b/2016b/2017b platforms. 10 | 11 | If you have any questions, please contact us (email:tju.drone.vision@gmail.com). 12 | 13 | Citation 14 | 15 | If you use our toolkit or dataset, please cite our paper as follows: 16 | 17 | @article{zhuvisdrone2018, 18 | 19 | title={Vision Meets Drones: A Challenge}, 20 | 21 | author={Zhu, Pengfei and Wen, Longyin and Bian, Xiao and Haibin, Ling and Hu, Qinghua}, 22 | 23 | journal={arXiv preprint:1804.07437}, 24 | 25 | year={2018} 26 | 27 | } 28 | 29 | 30 | Dataset 31 | 32 | For MOT competition, there are three sets of data and labels: training data, validation data, 33 | and test-challenge data. There is no overlap between the three sets. 34 | 35 | Number of snippets 36 | ------------------------------------------------------------------------------------------------ 37 | Dataset Training Validation Test-Challenge 38 | ------------------------------------------------------------------------------------------------ 39 | Multiple object tracking 56 clips 7 clips 16 clips 40 | 24,201 frames 2,819 frames 6,333 frames 41 | ------------------------------------------------------------------------------------------------ 42 | 43 | The challenge aims to recover the object trajectories with (Task 4B) or without (Task 4A) the detection results in each video frame. Notably, in the VisDrone2018 Challenge, we only consider five object categories in multi-object tracking, i.e., car, bus, truck, pedestrian, and van. We manually annotate the bounding boxes of different objects and ignored regiones in each video frame. Annotations on the training and validation sets are publicly available. 44 | 45 | The dataset can be downloaded at 46 | 47 | http://www.aiskyeye.com/ 48 | 49 | 50 | Evaluation Routines 51 | 52 | The notes for the folders: 53 | * main functions 54 | * evalMOT.m is the main function to evaluate your tracker 55 | 56 | * put the source codes in ./trackers/ (please refer the source codes of GOG tracker) 57 | 58 | * modify the dataset path and result path 59 | 60 | * use "isSeqDisplay" to show the groundtruth and detections 61 | 62 | * select the evaluated task, i.e, Task 4A without detection results, Task 4B with detection results 63 | 64 | * evaluateTrackA.m is the main function to evaluate your tracker using the measures in Task 4A without detection results. 65 | 66 | * evaluateTrackB.m is the main function to evaluate your tracker using the measures in Task 4B with the Faster RCNN detection results. 67 | 68 | MOT Submission Format 69 | 70 | Submission of the results will consist of TXT files with one line per predicted object.It looks as follows: 71 | 72 | ,,,,,,,,, 73 | 74 | ----------------------------------------------------------------------------------------------------------------------------------- 75 | Name Description 76 | ----------------------------------------------------------------------------------------------------------------------------------- 77 | The frame index of the video frame 78 | 79 | In the DETECTION result file, the identity of the target should be set to the constant -1. 80 | In the GROUNDTRUTH file, the identity of the target is used to provide the temporal corresponding 81 | relation of the bounding boxes in different frames. 82 | 83 | The x coordinate of the top-left corner of the predicted bounding box 84 | 85 | The y coordinate of the top-left corner of the predicted object bounding box 86 | 87 | The width in pixels of the predicted object bounding box 88 | 89 | The height in pixels of the predicted object bounding box 90 | 91 | The score in the DETECTION file indicates the confidence of the predicted bounding box enclosing 92 | an object instance. 93 | The score in GROUNDTRUTH file is set to 1 or 0. 1 indicates the bounding box is considered in evaluation, 94 | while 0 indicates the bounding box will be ignored. 95 | 96 | The object category indicates the type of annotated object, (i.e., ignored regions(0), pedestrian(1), 97 | people(2), bicycle(3), car(4), van(5), truck(6), tricycle(7), awning-tricycle(8), bus(9), motor(10), 98 | others(11)) 99 | 100 | The score in the DETECTION file should be set to the constant -1. 101 | The score in the GROUNDTRUTH file indicates the degree of object parts appears outside a frame 102 | (i.e., no truncation = 0 (truncation ratio 0%), and partial truncation = 1 (truncation ratio 1% ~ 50%)). 103 | 104 | The score in the DETECTION file should be set to the constant -1. 105 | The score in the GROUNDTRUTH file indicates the fraction of objects being occluded 106 | (i.e., no occlusion = 0 (occlusion ratio 0%), partial occlusion = 1 (occlusion ratio 1% ~ 50%), 107 | and heavy occlusion = 2 (occlusion ratio 50% ~ 100%)). 108 | 109 | The sample submission of the GOG tracker can be found in our website. 110 | 111 | 112 | References 113 | 114 | [1] A. Milan, L. Leal-Taixe, K. Schindler, D. Cremers, S. Roth, and I. Reid, "Multiple Object Tracking Benchmark 2016", https://motchallenge.net/results/MOT16/. 115 | 116 | [2] E. Park, W. Liu, O. Russakovsky, J. Deng, F.-F. Li, and A. Berg, "Large Scale Visual Recognition Challenge 2017", http://imagenet.org/challenges/LSVRC/2017 117 | 118 | Version History 119 | 1.0.2 - Jul 1, 2019 120 | - fix the bugs in droping objects in ignored regions 121 | 122 | 1.0.1 - May 2, 2018 123 | - fix the bugs in evaluating each object category 124 | - improve the evaluation speed 125 | 126 | 1.0.0 - Apr 27, 2018 127 | - initial release 128 | 129 | -------------------------------------------------------------------------------- /utils/preprocessResult.m: -------------------------------------------------------------------------------- 1 | function resFileClean = preprocessResult(resFile, seqName, dataDir, force, minvis) 2 | % reads submitted (raw) MOT16 result from .txt 3 | % and removes all boxes that are associated with ambiguous annotations 4 | % such as sitting people, cyclists or mannequins. 5 | % Also removes partially occluded boxes if minvis>0 6 | 7 | % resFile='/home/amilan/research/projects/bmtt-dev/code/bae/res/0001/ADL-Rundle-6.txt'; 8 | % seqName = 'MOT16-09'; 9 | assert(cleanRequired(seqName),'preproccessing should only be done for MOT16/17') 10 | 11 | if nargin<4, force=1; end 12 | if nargin<5, minvis=0; end 13 | 14 | fprintf('Preprocessing (cleaning) %s...\n',seqName); 15 | 16 | % if file does not exist, do nothing 17 | if ~exist(resFile,'file') 18 | fprintf('Results file does not exist\n'); 19 | resFileClean = []; 20 | return; 21 | end 22 | 23 | [p,f,e]=fileparts(resFile); 24 | cleanDir = [p,filesep,'clean']; 25 | if ~exist(cleanDir, 'dir'), mkdir(cleanDir); end 26 | resFileClean = [cleanDir,filesep,f,e]; 27 | 28 | % if clean file already exists and no need to redo, skip 29 | if ~force && exist(resFileClean, 'file') 30 | fprintf('skipping...\n'); 31 | return; 32 | end 33 | 34 | % if file empty, just copy it 35 | tf = dir(resFile); 36 | if tf.bytes == 0 37 | fprintf('Results file empty\n'); 38 | copyfile(resFile,resFileClean); 39 | return; 40 | end 41 | 42 | if nargin<3, dataDir = getDataDir; end 43 | 44 | % [seqName, seqFolder, imgFolder, imgExt, F, dirImages] ... 45 | % = getSeqInfo(seq, dataDir); 46 | 47 | [seqName, seqFolder, imgFolder, frameRate, F, imWidth, imHeight, imgExt] ... 48 | = getSeqInfoFromFile(seqName, dataDir); 49 | 50 | % read in result 51 | resRaw = dlmread(resFile); 52 | 53 | 54 | 55 | %% 56 | 57 | % read ground truth 58 | gtFolder = [dataDir,seqName,filesep,'gt',filesep]; 59 | gtFile = [gtFolder,'gt.txt']; 60 | gtRaw = dlmread(gtFile); 61 | 62 | % make sure we have MOT16 ground truth (= 9 columns) 63 | assert(size(gtRaw,2)==9, 'unknown GT format') 64 | 65 | % define which classes should be ignored 66 | distractors = {'person_on_vhcl','static_person','distractor','reflection'}; 67 | 68 | keepBoxes = true(size(resRaw,1),1); 69 | 70 | showVis = 0; 71 | 72 | td=0.5; % overlap threshold 73 | for t=1:F 74 | if ~mod(t,100), fprintf('.'); end 75 | 76 | % find all result boxes in this frame 77 | resInFrame = find(resRaw(:,1)==t); N = length(resInFrame); 78 | resInFrame = reshape(resInFrame,1,N); 79 | 80 | % find all GT boxes in frame 81 | GTInFrame = find(gtRaw(:,1)==t); Ngt = length(GTInFrame); 82 | GTInFrame = reshape(GTInFrame,1,Ngt); 83 | 84 | % compute all overlaps for current frame 85 | allisects=zeros(Ngt,N); 86 | g=0; 87 | for gg=GTInFrame 88 | g=g+1; r=0; 89 | bxgt=gtRaw(gg,3); bygt=gtRaw(gg,4); bwgt=gtRaw(gg,5); bhgt=gtRaw(gg,6); 90 | for rr=resInFrame 91 | r=r+1; 92 | bxres=resRaw(rr,3); byres=resRaw(rr,4); bwres=resRaw(rr,5); bhres=resRaw(rr,6); 93 | 94 | if bxgt+bwgtbxres+bwres, continue; end 96 | 97 | if bygt+bhgtbyres+bhres, continue; end 99 | 100 | allisects(g,r)=boxiou(bxgt,bygt,bwgt,bhgt,bxres,byres,bwres,bhres); 101 | end 102 | end 103 | % t 104 | 105 | tmpai=allisects; 106 | tmpai=1-tmpai; 107 | tmpai(tmpai>td)=Inf; 108 | [Mtch,Cst]=Hungarian(tmpai); 109 | [mGT,mRes]=find(Mtch); 110 | % pause 111 | nMtch = length(mGT); 112 | % go through all matches 113 | for m=1:nMtch 114 | g=GTInFrame(mGT(m)); % gt box 115 | gtClassID = gtRaw(g,8); 116 | gtClassString = classIDToString(gtClassID); 117 | 118 | % if we encounter a distractor, mark to remove box 119 | if ismember(gtClassString, distractors) 120 | r = resInFrame(mRes(m)); % result box 121 | keepBoxes(r) = false; 122 | 123 | if showVis 124 | bxgt=gtRaw(g,3); bygt=gtRaw(g,4); bwgt=gtRaw(g,5); bhgt=gtRaw(g,6); idgt=gtRaw(g,2); 125 | bxres=resRaw(r,3); byres=resRaw(r,4); bwres=resRaw(r,5); bhres=resRaw(r,6); idres=resRaw(r,2); 126 | 127 | clf 128 | im = imread(fullfile(dataDir,seqName,'img1',sprintf('%06d.jpg',t))); 129 | imshow(im); hold on 130 | text(50,50,sprintf('%d',t),'color','w') 131 | 132 | % show GT box 133 | % text(bxgt,bygt-20,sprintf('%d',idgt),'color','w') 134 | classString = insertEscapeChars(classIDToString(gtClassID)); 135 | text(bxgt+50,bygt-20,sprintf('%s',classString),'color','w') 136 | rectangle('Position',[bxgt,bygt,bwgt,bhgt],'EdgeColor','w'); 137 | 138 | % show Res box 139 | % text(bxres,byres-20,sprintf('%d',idres),'color','y') 140 | rectangle('Position',[bxres,byres,bwres,bhres],'EdgeColor','y'); 141 | 142 | pause(.01) 143 | end 144 | end 145 | 146 | % if we encounter a partially occluded box, mark to remove 147 | if gtRaw(g,9)=.5. If 9 | % ovrDnm='min', the 'union' in the above formula is replaced with 'min'. 10 | % 11 | % type=='maxg': Similar to 'max', except performs the nms in a greedy 12 | % fashion. Bbs are processed in order of decreasing score, and, unlike in 13 | % 'max' nms, once a bb is suppressed it can no longer suppress other bbs. 14 | % 15 | % type='cover': Perform nms by attempting to choose the smallest subset of 16 | % the bbs such that each remaining bb is within overlap of one of the 17 | % chosen bbs. The above reduces to the weighted set cover problem which is 18 | % NP but greedy optimization yields provably good solutions. The score of 19 | % each bb is set to the sum of the scores of the bbs it covers (the max can 20 | % also be used). In practice similar to 'maxg'. 21 | % 22 | % type=='ms': Mean shift nms of bbs with a variable width kernel. radii is 23 | % a 4 element vector (x,y,w,h) that controls the amount of suppression 24 | % along each dim. Typically the first two elements should be the same, as 25 | % should the last two. Distance between w/h are computed in log2 space (ie 26 | % w and w*2 are 1 unit apart), and the radii should be set accordingly. 27 | % radii may need to change depending on spatial and scale stride of bbs. 28 | % 29 | % Although efficient, nms is O(n^2). To speed things up for large n, can 30 | % divide data into two parts (according to x or y coordinate), run nms on 31 | % each part, combine and run nms on the result. If maxn is specified, will 32 | % split the data in half if n>maxn. Note that this is a heuristic and can 33 | % change the results of nms. Moreover, setting maxn too small will cause an 34 | % increase in overall performance time. 35 | % 36 | % Finally, the bbs are optionally resized before performing nms. The 37 | % resizing is important as some detectors return bbs that are padded. For 38 | % example, if a detector returns a bounding box of size 128x64 around 39 | % objects of size 100x43 (as is typical for some pedestrian detectors on 40 | % the INRIA pedestrian database), the resize parameters should be {100/128, 41 | % 43/64, 0}, see bbApply>resize() for more info. 42 | % 43 | % USAGE 44 | % bbs = bbNms( bbs, [varargin] ) 45 | % 46 | % INPUTS 47 | % bbs - original bbs (must be of form [x y w h wt bbType]) 48 | % varargin - additional params (struct or name/value pairs) 49 | % .type - ['max'] 'max', 'maxg', 'ms', 'cover', or 'none' 50 | % .thr - [-inf] threshold below which to discard (0 for 'ms') 51 | % .maxn - [inf] if n>maxn split and run recursively (see above) 52 | % .radii - [.15 .15 1 1] supression radii ('ms' only, see above) 53 | % .overlap - [.5] area of overlap for bbs 54 | % .ovrDnm - ['union'] area of overlap denominator ('union' or 'min') 55 | % .resize - {} parameters for bbApply('resize') 56 | % .separate - [0] run nms separately on each bb type (bbType) 57 | % 58 | % OUTPUTS 59 | % bbs - suppressed bbs 60 | % 61 | % EXAMPLE 62 | % bbs=[0 0 1 1 1; .1 .1 1 1 1.1; 2 2 1 1 1]; 63 | % bbs1 = bbNms(bbs, 'type','max' ) 64 | % bbs2 = bbNms(bbs, 'thr',.5, 'type','ms') 65 | % 66 | % See also bbApply, nonMaxSuprList 67 | % 68 | % Piotr's Image&Video Toolbox Version 2.60 69 | % Copyright 2012 Piotr Dollar. [pdollar-at-caltech.edu] 70 | % Please email me if you find bugs, or have suggestions or questions! 71 | % Licensed under the Simplified BSD License [see external/bsd.txt] 72 | 73 | % get parameters 74 | dfs={'type','max','thr',[],'maxn',inf,'radii',[.15 .15 1 1],... 75 | 'overlap',.5,'ovrDnm','union','resize',{},'separate',0}; 76 | [type,thr,maxn,radii,overlap,ovrDnm,resize,separate] = ... 77 | getPrmDflt(varargin,dfs,1); 78 | if(isempty(thr)), if(strcmp(type,'ms')), thr=0; else thr=-inf; end; end 79 | if(strcmp(ovrDnm,'union')), ovrDnm=1; elseif(strcmp(ovrDnm,'min')), 80 | ovrDnm=0; else assert(false); end 81 | assert(maxn>=2); assert(numel(overlap)==1); 82 | 83 | % discard bbs below threshold and run nms1 84 | if(isempty(bbs)), bbs=zeros(0,5); end; if(strcmp(type,'none')), return; end 85 | kp=bbs(:,5)>thr; bbs=bbs(kp,:); if(isempty(bbs)), return; end 86 | if(~isempty(resize)), bbs=bbApply('resize',bbs,resize{:}); end 87 | pNms1={type,thr,maxn,radii,overlap,0}; 88 | if(~separate || size(bbs,2)<6), bbs=nms1(bbs,pNms1{:}); else 89 | ts=unique(bbs(:,6)); m=length(ts); bbs1=cell(1,m); 90 | for t=1:m, bbs1{t}=nms1(bbs(bbs(:,6)==ts(t),:),pNms1{:}); end 91 | bbs=cat(1,bbs1{:}); 92 | end 93 | 94 | function bbs = nms1( bbs, type, thr, maxn, radii, overlap, isy ) 95 | % if big split in two, recurse, merge, then run on merged 96 | if( size(bbs,1)>maxn ) 97 | n2=floor(size(bbs,1)/2); [~,ord]=sort(bbs(:,1+isy)+bbs(:,3+isy)/2); 98 | bbs0=nms1(bbs(ord(1:n2),:),type,thr,maxn,radii,overlap,~isy); 99 | bbs1=nms1(bbs(ord(n2+1:end),:),type,thr,maxn,radii,overlap,~isy); 100 | bbs=[bbs0; bbs1]; 101 | end 102 | % run actual nms on given bbs 103 | switch type 104 | case 'max', bbs = nmsMax(bbs,overlap,0,ovrDnm); 105 | case 'maxg', bbs = nmsMax(bbs,overlap,1,ovrDnm); 106 | case 'ms', bbs = nmsMs(bbs,thr,radii); 107 | case 'cover', bbs = nmsCover(bbs,overlap,ovrDnm); 108 | otherwise, error('unknown type: %s',type); 109 | end 110 | end 111 | 112 | function bbs = nmsMax( bbs, overlap, greedy, ovrDnm ) 113 | % for each i suppress all j st j>i and area-overlap>overlap 114 | [~,ord]=sort(bbs(:,5),'descend'); bbs=bbs(ord,:); 115 | n=size(bbs,1); kp=true(1,n); as=bbs(:,3).*bbs(:,4); 116 | xs=bbs(:,1); xe=bbs(:,1)+bbs(:,3); ys=bbs(:,2); ye=bbs(:,2)+bbs(:,4); 117 | for i=1:n, if(greedy && ~kp(i)), continue; end 118 | for j=(i+1):n, if(kp(j)==0), continue; end 119 | iw=min(xe(i),xe(j))-max(xs(i),xs(j)); if(iw<=0), continue; end 120 | ih=min(ye(i),ye(j))-max(ys(i),ys(j)); if(ih<=0), continue; end 121 | o=iw*ih; if(ovrDnm), u=as(i)+as(j)-o; else u=min(as(i),as(j)); end 122 | o=o/u; if(o>overlap), kp(j)=0; end 123 | end 124 | end 125 | bbs=bbs(kp>0,:); 126 | end 127 | 128 | function bbs = nmsMs( bbs, thr, radii ) 129 | % position = [x+w/2,y+h/2,log2(w),log2(h)], ws=weights-thr 130 | ws=bbs(:,5)-thr; w=bbs(:,3); h=bbs(:,4); n=length(w); 131 | ps=[bbs(:,1)+w/2 bbs(:,2)+h/2 log2(w) log2(h)]; 132 | % find modes starting from each elt, then merge nodes that are same 133 | ps1=zeros(n,4); ws1=zeros(n,1); stopThr=1e-2; 134 | for i=1:n, [ps1(i,:), ws1(i,:)]=nmsMs1(i); end 135 | [ps,ws] = nonMaxSuprList(ps1,ws1,stopThr*100,[],[],2); 136 | % convert back to bbs format and sort by weight 137 | w=pow2(ps(:,3)); h=pow2(ps(:,4)); 138 | bbs=[ps(:,1)-w/2 ps(:,2)-h/2 w h ws+thr]; 139 | [ws,ord]=sort(ws,'descend'); bbs=bbs(ord,:); 140 | 141 | function [p,w]=nmsMs1(ind) 142 | % variable bandwith kernel (analytically defined) 143 | p=ps(ind,:); [n,m]=size(ps); onesN=ones(n,1); 144 | h = [pow2(ps(:,3)) pow2(ps(:,4)) onesN onesN]; 145 | h = h .* radii(onesN,:); hInv=1./h; 146 | while(1) 147 | % compute (weighted) squared Euclidean distance to each neighbor 148 | d=(ps-p(onesN,:)).*hInv; d=d.*d; d=sum(d,2); 149 | % compute new mode 150 | wMask=ws.*exp(-d); wMask=wMask/sum(wMask); p1=wMask'*ps; 151 | % stopping criteria 152 | diff=sum(abs(p1-p))/m; p=p1; if(diffoverlap), N(i,j)=1; end 168 | end 169 | end 170 | % perform set cover operation (greedily choose next best) 171 | N=N+N'; bbs1=zeros(n,5); n1=n; c=0; 172 | while( n1>0 ), [~,i0]=max(N*bbs(:,5)); 173 | N0=N(:,i0)==1; n1=n1-sum(N0); N(N0,:)=0; N(:,N0)=0; 174 | c=c+1; bbs1(c,1:4)=bbs(i0,1:4); bbs1(c,5)=sum(bbs(N0,5)); 175 | end 176 | bbs=bbs1(1:c,:); 177 | end 178 | end 179 | --------------------------------------------------------------------------------