├── .gitignore ├── 3rd_party ├── TLD │ ├── bbox │ │ ├── bb_burn.m │ │ ├── bb_center.m │ │ ├── bb_click.m │ │ ├── bb_click_move.m │ │ ├── bb_cluster.m │ │ ├── bb_cluster_confidence.m │ │ ├── bb_correct.m │ │ ├── bb_distance.m │ │ ├── bb_draw.m │ │ ├── bb_get_similar.m │ │ ├── bb_height.m │ │ ├── bb_hull.m │ │ ├── bb_isdef.m │ │ ├── bb_isin.m │ │ ├── bb_isout.m │ │ ├── bb_normalize.m │ │ ├── bb_points.m │ │ ├── bb_predict.m │ │ ├── bb_rescale_absolute.m │ │ ├── bb_rescale_relative.m │ │ ├── bb_scale.m │ │ ├── bb_scan.m │ │ ├── bb_shift_absolute.m │ │ ├── bb_shift_relative.m │ │ ├── bb_size.m │ │ ├── bb_square.m │ │ └── bb_width.m │ ├── lk.cpp │ ├── lkcompile.m │ ├── tldTracking.m │ └── utils │ │ ├── idx2id.m │ │ ├── mat2img.m │ │ ├── maximize.m │ │ ├── median2.m │ │ ├── n2s.m │ │ ├── ntuples.m │ │ ├── pseudorandom_indexes.m │ │ ├── randvalues.m │ │ ├── repcel.m │ │ ├── uniquecount.m │ │ └── vnormp.m ├── addpath │ ├── addpath_recurse.m │ └── license.txt ├── sfigure.m └── uninit │ ├── license.txt │ ├── uninit.c │ ├── uninit.m │ └── uninit.mexa64 ├── README ├── README.md ├── compile.m ├── config ├── cfg.m ├── cluster_ctl.m ├── datapath.m ├── matlab_init.m └── setpath.m ├── detection ├── Detector.m ├── cost_lcl_tsvm.m ├── feat_code.m ├── featpyramid.m ├── feature_get_for_svm.m ├── features.m ├── features_c.cc ├── gt_filter_detections.m ├── mex_resize.cc ├── nms.m ├── nms_c.cc ├── reduce.cc └── scoreBox.m ├── evalOnVids.sh ├── hashMat_mat.m ├── learning ├── compute_tsvm_deltas.m ├── getDetsEst.m └── learn_tsvm_score.m ├── mex └── compat.h ├── model ├── Model.m ├── SVM_trainer.m └── genModel.m ├── qp ├── QP.m ├── qp_assert.m ├── qp_clear.m ├── qp_init.m ├── qp_one.m ├── qp_one_c.cc ├── qp_opt.m ├── qp_prune.m └── qp_write.m ├── rect ├── check_rect_size.m ├── csvBtoK.m ├── rectBtoK.m ├── rectKtoB.m ├── rect_area.m ├── rect_aspect.m ├── rect_center.m ├── rect_contains.m ├── rect_correct_aspect.m ├── rect_equal.m ├── rect_from_center.m ├── rect_image.m ├── rect_overlap.m ├── rect_scale.m ├── rect_size.m ├── rect_trans.m ├── rect_zero_orig.m └── rects_overlap.m ├── show ├── hasDisplay.m ├── linWidth.m ├── plot_resp.m ├── showBox.m ├── showBoxVia.m ├── showBoxes.m ├── showGhostBoxes.m └── showModel.m ├── track_dp ├── DPTracker.m ├── dynprog_chain.cc ├── track_dp.m ├── track_dp_backward.m ├── track_dp_forward.m ├── track_dp_forward_augment_states.m ├── track_dp_forward_one.m ├── track_dp_gen_occlusions.m ├── track_dp_init.m └── track_dp_lcl.m ├── trackers ├── track_offline.m ├── track_online.m └── track_tbd.m └── video ├── clamp.m ├── f1score.m ├── get_frame.m ├── get_vid_range.m ├── gt_load.m ├── gt_occluded.m ├── gt_valid.m ├── hashMat.cc ├── imcropr.m ├── imgray.m ├── imrgb.m ├── score_track_file.m ├── score_track_one.m ├── track_scorer.m └── vidLen.m /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.mexa64 3 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_burn.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function img = bb_burn(img, bb_in, width) 20 | 21 | if ~exist('width','var') 22 | width = 0; 23 | end 24 | 25 | if isempty(bb_in) 26 | return; 27 | end 28 | 29 | for i = 1:size(bb_in,2) 30 | 31 | bb = bb_in(:,i); 32 | bb(1) = max([1 bb(1)]); 33 | bb(2) = max([1 bb(2)]); 34 | bb(3) = min([size(img,2), bb(3)]); 35 | bb(4) = min([size(img,1), bb(4)]); 36 | 37 | 38 | img(bb(2):bb(2)+width,bb(1):bb(3)) = 255; 39 | img(bb(4)-width:bb(4),bb(1):bb(3)) = 255; 40 | img(bb(2):bb(4),bb(1):bb(1)+width) = 255; 41 | img(bb(2):bb(4),bb(3)-width:bb(3)) = 255; 42 | 43 | end -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_center.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function center = bb_center(bb) 20 | % Info 21 | 22 | if isempty(bb) 23 | center = []; 24 | return; 25 | end 26 | 27 | center = 0.5 * [bb(1,:)+bb(3,:); bb(2,:)+bb(4,:)]; -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_click.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_click(tld,img) 20 | % Create 21 | 22 | if isfield(tld,'handle') 23 | h = get(gca,'Children'); delete(h(1:end-1)); 24 | set(tld.handle,'cdata',img); 25 | else 26 | imshow(img); 27 | end 28 | text(10,10,'Define bounding box and double click inside.','color','white'); 29 | h = imrect; 30 | p = wait(h); 31 | bb = [p(1); p(2);p(1)+p(3); p(2)+p(4)]; 32 | % [c,r,p] = impixel(img); 33 | % if length(c) ~= 2, 34 | % bb = []; 35 | % return; 36 | % end 37 | % bb = [c(1); r(1); c(2); r(2)]; -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_click_move.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_click_move(img,bb) 20 | % Change 21 | 22 | [c,r,p] = impixel(bb_burn(img,bb)); 23 | 24 | bbW = bb_width(bb); 25 | bbH = bb_height(bb); 26 | 27 | bb = [c(1) - bbW/2; r(1) - bbH/2; c(1) + bbW/2; r(1) + bbH/2]; 28 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_cluster.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function [bb,cSz] = bb_cluster(bb2, SPACE_THR, MIN_NUM_BB) 19 | % Clusters bboxes. 20 | 21 | if isempty(bb2) 22 | bb = []; 23 | cSz = []; 24 | return; 25 | end 26 | 27 | switch size(bb2,2) 28 | case 0, T = []; 29 | case 1, T = 1; 30 | case 2 31 | T = ones(2,1); 32 | if bb_distance(bb2) > SPACE_THR, T(2) = 2; end 33 | otherwise 34 | bbd = bb_distance(bb2); 35 | Z = linkagemex(bbd,'si'); 36 | T = cluster(Z,'cutoff', SPACE_THR,'criterion','distance'); 37 | end 38 | uT = unique(T); 39 | 40 | % Merge clusters 41 | bb = []; 42 | cSz = []; 43 | for i = 1:length(uT) 44 | num_bb = sum(T == uT(i)); 45 | if num_bb >= MIN_NUM_BB 46 | bb = [bb mean(bb2(:,T == uT(i)),2)]; 47 | cSz = [cSz num_bb]; 48 | end 49 | end -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_cluster_confidence.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function [oBB,oConf,oSize] = bb_cluster_confidence(iBB, iConf) 20 | % Clusterering of tracker and detector responses 21 | % First cluster returned corresponds to the tracker 22 | 23 | SPACE_THR = 0.5; 24 | 25 | oBB = []; 26 | oConf = []; 27 | oSize = []; 28 | 29 | if isempty(iBB) 30 | return; 31 | end 32 | 33 | switch size(iBB,2) 34 | case 0, T = []; 35 | case 1, T = 1; 36 | case 2 37 | T = ones(2,1); 38 | if bb_distance(iBB) > SPACE_THR, T(2) = 2; end 39 | otherwise 40 | bbd = bb_distance(iBB); 41 | Z = linkagemex(bbd,'si'); 42 | T = cluster(Z,'cutoff', SPACE_THR,'criterion','distance'); 43 | end 44 | 45 | idx_cluster = unique(T); 46 | num_clusters = length(idx_cluster); 47 | 48 | oBB = nan(4,num_clusters); 49 | oConf = nan(1,num_clusters); 50 | oSize = nan(1,num_clusters); 51 | 52 | for i = 1:num_clusters 53 | 54 | idx = T == idx_cluster(i); 55 | 56 | oBB(:,i) = mean(iBB(1:4,idx),2); 57 | oConf(i) = mean(iConf(idx)); 58 | oSize(i) = sum(idx); 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_correct.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_correct(img,bb) 20 | % Change 21 | 22 | K = 2; 23 | K2 = 1; 24 | while 1 25 | 26 | clf; imshow(img); bb_rectangle(bb,'EdgeColor','y'); 27 | %maximize(); 28 | [x,y,ch] = ginput(1); 29 | if isempty(ch), break; end 30 | switch ch 31 | case 29 32 | bb = [bb(1)+K; bb(2); bb(3)+K; bb(4)]; 33 | case 28 34 | bb = [bb(1)-K; bb(2); bb(3)-K; bb(4)]; 35 | case 30 36 | bb = [bb(1); bb(2)-K; bb(3); bb(4)-K]; 37 | case 31 38 | bb = [bb(1); bb(2)+K; bb(3); bb(4)+K]; 39 | case 46 % bigger 40 | bb = [bb(1)-K2; bb(2)-K2; bb(3)+K2; bb(4)+K2]; 41 | case 44 % smaller 42 | bb = [bb(1)+K2; bb(2)+K2; bb(3)-K2; bb(4)-K2]; 43 | 44 | end 45 | 46 | end -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_distance.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function d = bb_distance(bb1,bb2) 20 | % Info 21 | 22 | switch nargin 23 | case 1 24 | d = 1 - bb_overlap(bb1); 25 | case 2 26 | d = 1 - bb_overlap(bb1,bb2); 27 | end -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_draw.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb_draw(bb1,varargin) 20 | % Draw 21 | 22 | if isempty(bb1), return; end; 23 | idx = find(bb_isdef(bb1)); 24 | if isempty(varargin) 25 | varargin = {'edgecolor','y'}; 26 | end 27 | for i = 1:length(idx) 28 | bb = bb1(:,idx(i)); 29 | if bb(3)-bb(1) > 0 && bb(4)-bb(2)>0 30 | rectangle('Position',[bb(1) bb(2) bb(3)-bb(1) bb(4)-bb(2)],varargin{:}) 31 | 32 | if size(bb,1) == 5 33 | cp = bb_center(bb); 34 | text(cp(1),cp(2),num2str(bb(5),3),'color','w'); 35 | end 36 | 37 | end 38 | end -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_get_similar.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function [bb idx] = bb_get_similar(bb0,bb1,thr) 20 | 21 | idx = find(bb_overlap(bb1(1:4,:),bb0)>thr); 22 | bb = bb1(:,idx); -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_height.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bbH = bb_height(bb) 20 | % Info 21 | 22 | bbH = bb(4,:)-bb(2,:)+1; 23 | 24 | 25 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_hull.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_hull(bb0) 20 | 21 | bb=[min(bb0(1,:)); ... 22 | min(bb0(2,:)); ... 23 | max(bb0(3,:)); ... 24 | max(bb0(4,:))]; -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_isdef.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function id = bb_isdef(bb) 20 | % Info 21 | 22 | id = isfinite(bb(1,:)); -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_isin.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function flag = bb_isin(bb,imsize) 20 | 21 | flag = bb(1,:) >= 1 & ... 22 | bb(2,:) >= 1 & ... 23 | bb(3,:) <= imsize(2) & ... 24 | bb(4,:) <= imsize(1); -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_isout.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function idx_out = bb_isout(bb,imsize) 20 | 21 | idx_out = bb(1,:) > imsize(2) | ... 22 | bb(2,:) > imsize(1) | ... 23 | bb(3,:) < 1 | ... 24 | bb(4,:) < 1; 25 | 26 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_normalize.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb2 = bb_normalize(bb1,bb0) 20 | % Change 21 | % Shifts and rescales bboxes in BB1 according to the first bbox in BB0. 22 | 23 | W = bb_width( bb0(:,1)) / bb_width(bb1(:,1)); 24 | H = bb_height( bb0(:,1)) / bb_height(bb1(:,1)); 25 | SH = bb_center( bb0(:,1)) - bb_center(bb1(:,1)); 26 | 27 | bb2 = bb_rescale(bb_shift(bb1,SH),[W,H]); 28 | 29 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_points.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function pt = bb_points(bb,numM,numN,margin) 20 | % Generates numM x numN points on BBox. 21 | 22 | bb(1:2) = bb(1:2)+margin; 23 | bb(3:4) = bb(3:4)-margin; 24 | 25 | if (numM == 1 && numN ==1) 26 | pt = bb_center(bb); 27 | return; 28 | end 29 | 30 | if (numM == 1 && numN > 1) 31 | c = bb_center(bb); 32 | stepW = (bb(3)-bb(1)) / (numN - 1); 33 | pt = ntuples(bb(1):stepW:bb(3),c(2)); 34 | return; 35 | end 36 | 37 | if (numM > 1 && numN == 1) 38 | c = bb_center(bb); 39 | stepH = (bb(4)-bb(2)) / (numM - 1); 40 | pt = ntuples(c(1),(bb(2):stepH:bb(4))); 41 | return; 42 | end 43 | 44 | stepW = (bb(3)-bb(1)) / (numN - 1); 45 | stepH = (bb(4)-bb(2)) / (numM - 1); 46 | 47 | pt = ntuples(bb(1):stepW:bb(3),(bb(2):stepH:bb(4))); 48 | 49 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_predict.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function [BB1 shift] = bb_predict(BB0,pt0,pt1) 20 | 21 | of = pt1 - pt0; 22 | dx = median(of(1,:)); 23 | dy = median(of(2,:)); 24 | 25 | d1 = pdist(pt0','euclidean'); 26 | d2 = pdist(pt1','euclidean'); 27 | s = median(d2./d1); 28 | 29 | s1 = 0.5*(s-1)*bb_width(BB0); 30 | s2 = 0.5*(s-1)*bb_height(BB0); 31 | 32 | BB1 = [BB0(1)-s1; BB0(2)-s2; BB0(3)+s1; BB0(4)+s2] + [dx; dy; dx; dy]; 33 | shift = [s1; s2]; 34 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_rescale_absolute.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_rescale_absolute(bb,row,col) 20 | % Change 21 | 22 | bb(1) = bb(1) - col; 23 | bb(2) = bb(2) - row; 24 | bb(3) = bb(3) + col; 25 | bb(4) = bb(4) + row; -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_rescale_relative.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function BB = bb_rescale_relative(BB,s) 20 | % Change 21 | BB = BB(1:4); 22 | if length(s) == 1 23 | s = s*[1 1]; 24 | end 25 | if isempty(BB), BB = []; return; end 26 | 27 | s1 = 0.5*(s(1)-1)*bb_width(BB); 28 | s2 = 0.5*(s(2)-1)*bb_height(BB); 29 | BB = BB + [-s1; -s2; s1; s2]; 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_scale.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function bbScale = bb_scale(bb) 19 | % Returns bbox scale = sqrt(bbox area) 20 | 21 | bbScale = sqrt((bb(4,:)-bb(2,:)+1).*(bb(3,:)-bb(1,:)+1)); 22 | 23 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_scan.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function [bb_out,sca] = bb_scan(bb, imsize,min_win) 20 | 21 | SHIFT = 0.1; 22 | SCALE = 1.2.^[-10:10]; 23 | MINBB = min_win; 24 | 25 | % Chack if input bbox is smaller than minimum 26 | if min(bb_size(bb)) < MINBB 27 | bb_out = []; 28 | sca = []; 29 | return; 30 | end 31 | 32 | bbW = round(bb_width(bb) .* SCALE); 33 | bbH = round(bb_height(bb) .* SCALE); 34 | bbSHH = SHIFT * min(bbH,bbH); 35 | bbSHW = SHIFT * min(bbH,bbW); 36 | 37 | bbF = [2 2 imsize(2) imsize(1)]'; 38 | 39 | bbs = {}; 40 | sca = []; 41 | idx = 1; 42 | 43 | for i = 1:length(SCALE) 44 | if bbW(i) < MINBB || bbH(i) < MINBB, continue; end 45 | 46 | left = round(bbF(1):bbSHW(i):bbF(3)-bbW(i)-1); 47 | top = round(bbF(2):bbSHH(i):bbF(4)-bbH(i)-1); 48 | 49 | grid = ntuples(top,left); 50 | if isempty(grid), continue; end 51 | 52 | bbs{end+1} = [grid(2,:); ... 53 | grid(1,:); ... 54 | grid(2,:)+bbW(i)-1; ... 55 | grid(1,:)+bbH(i)-1; ... 56 | idx*ones(1,size(grid,2)); 57 | length(left)*ones(1,size(grid,2));]; 58 | sca = [sca [bbH(i); bbW(i)]]; 59 | idx = idx + 1; 60 | end 61 | bb_out = []; 62 | for i = 1:length(bbs) 63 | bb_out = [bb_out bbs{i}]; 64 | end 65 | 66 | % for i = 1:length(bbs) 67 | % 68 | % if i-1 > 0 69 | % idx = bb_overlap(bbs{i},bbs{i-1},2); 70 | % bbs{i}(7,:) = idx; 71 | % end 72 | % 73 | % if i+1 <= length(bbs) 74 | % idx = bb_overlap(bbs{i},bbs{i+1},2); 75 | % bbs{i}(8,:) = idx; 76 | % end 77 | % 78 | % end 79 | % disp(['MINBB: ' num2str(MINBB) ', bb: ' num2str(size(bbs,2))]); 80 | % end 81 | 82 | 83 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_shift_absolute.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_shift_absolute(bb,shift) 20 | % Change 21 | 22 | bb(1,:) = bb(1,:) + shift(1); 23 | bb(2,:) = bb(2,:) + shift(2); 24 | bb(3,:) = bb(3,:) + shift(1); 25 | bb(4,:) = bb(4,:) + shift(2); 26 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_shift_relative.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb = bb_shift_relative(bb,shift) 20 | % Change 21 | 22 | if isempty(bb) 23 | return; 24 | end 25 | bb(1,:) = bb(1,:) + bb_width(bb)*shift(1); 26 | bb(2,:) = bb(2,:) + bb_height(bb)* shift(2); 27 | bb(3,:) = bb(3,:) + bb_width(bb)*shift(1); 28 | bb(4,:) = bb(4,:) + bb_height(bb)*shift(2); 29 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_size.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function s = bb_size(bb) 20 | 21 | s = [bb(4,:)-bb(2,:)+1; bb(3,:)-bb(1,:)+1]; 22 | 23 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_square.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bb2 = bb_square(bb1) 20 | % Makes all bboxes square with the same area. 21 | 22 | if isempty(bb1); 23 | bb2 = []; 24 | return; 25 | end 26 | 27 | S = bb_scale(bb1); 28 | C = bb_center(bb1); 29 | 30 | bb2 = [C(1,:) - S/2; C(2,:) - S/2; C(1,:) + S/2; C(2,:) + S/2]; 31 | -------------------------------------------------------------------------------- /3rd_party/TLD/bbox/bb_width.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | 19 | function bbW = bb_width(bb) 20 | % Info 21 | 22 | bbW = bb(3,:)-bb(1,:)+1; 23 | 24 | 25 | -------------------------------------------------------------------------------- /3rd_party/TLD/lk.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Zdenek Kalal 2 | // 3 | // This file is part of TLD. 4 | // 5 | // TLD is free software: you can redistribute it and/or modify 6 | // it under the terms of the GNU General Public License as published by 7 | // the Free Software Foundation, either version 3 of the License, or 8 | // (at your option) any later version. 9 | // 10 | // TLD is distributed in the hope that it will be useful, 11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | // GNU General Public License for more details. 14 | // 15 | // You should have received a copy of the GNU General Public License 16 | // along with TLD. If not, see . 17 | 18 | #include "cv.h" 19 | #include "highgui.h" 20 | #include "math.h" 21 | #include 22 | #ifdef _CHAR16T 23 | #define CHAR16_T 24 | #endif 25 | #include "mex.h" 26 | 27 | 28 | const int MAX_COUNT = 500; 29 | const int MAX_IMG = 2; 30 | const int win_size = 4; 31 | 32 | void loadImageFromMatlab(const mxArray *mxImage, IplImage *image) { 33 | 34 | unsigned char *values = (unsigned char *) mxGetPr(mxImage); 35 | int widthStep = image->widthStep; 36 | int N = mxGetN(mxImage); // width 37 | int M = mxGetM(mxImage); // height 38 | 39 | if (N == 0 || M == 0) { 40 | printf("Input image error\n"); 41 | return; 42 | } 43 | 44 | for(int i=0;iimageData[j*widthStep+i] = values[j+i*M]; 47 | } 48 | 49 | void euclideanDistance (CvPoint2D32f *point1, CvPoint2D32f *point2, float *match, int nPts) { 50 | 51 | for (int i = 0; i < nPts; i++) { 52 | 53 | match[i] = sqrt((point1[i].x - point2[i].x)*(point1[i].x - point2[i].x) + 54 | (point1[i].y - point2[i].y)*(point1[i].y - point2[i].y) ); 55 | 56 | } 57 | } 58 | 59 | void normCrossCorrelation(IplImage *imgI, IplImage *imgJ, CvPoint2D32f *points0, CvPoint2D32f *points1, int nPts, char *status, float *match,int winsize, int method) { 60 | 61 | 62 | IplImage *rec0 = cvCreateImage( cvSize(winsize, winsize), 8, 1 ); 63 | IplImage *rec1 = cvCreateImage( cvSize(winsize, winsize), 8, 1 ); 64 | IplImage *res = cvCreateImage( cvSize( 1, 1 ), IPL_DEPTH_32F, 1 ); 65 | 66 | for (int i = 0; i < nPts; i++) { 67 | if (status[i] == 1) { 68 | cvGetRectSubPix( imgI, rec0, points0[i] ); 69 | cvGetRectSubPix( imgJ, rec1, points1[i] ); 70 | cvMatchTemplate( rec0,rec1, res, method ); 71 | match[i] = ((float *)(res->imageData))[0]; 72 | 73 | } else { 74 | match[i] = 0.0; 75 | } 76 | } 77 | cvReleaseImage( &rec0 ); 78 | cvReleaseImage( &rec1 ); 79 | cvReleaseImage( &res ); 80 | 81 | } 82 | 83 | 84 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 85 | { 86 | 87 | double nan = std::numeric_limits::quiet_NaN(); 88 | double inf = std::numeric_limits::infinity(); 89 | 90 | // storage for the operation... 91 | CvPoint2D32f* points[3] = {0,0,0}; 92 | IplImage **IMG = 0; 93 | IplImage **PYR = 0; 94 | IMG = (IplImage**) calloc(MAX_IMG,sizeof(IplImage*)); 95 | PYR = (IplImage**) calloc(MAX_IMG,sizeof(IplImage*)); 96 | //mexPrintf("LK: initialized\n"); 97 | 98 | if (nrhs == 0) { 99 | mexPrintf("Lucas-Kanade\n"); 100 | return; 101 | } 102 | 103 | // 0: init 104 | // 2: track 105 | int opcode = (int) *mxGetPr(prhs[0]); 106 | if(opcode == 0) 107 | return; 108 | 109 | if (IMG == 0 || (nrhs != 5 && nrhs != 6)) { 110 | if(IMG == 0) 111 | { 112 | mexPrintf("IMG==0"); 113 | return; 114 | } 115 | else 116 | { 117 | 118 | mexPrintf("lk(2,imgI,imgJ,ptsI,ptsJ,Level)\n"); 119 | // 0 1 2 3 4 120 | return; 121 | } 122 | } 123 | int Level; 124 | if (nrhs == 6) { 125 | Level = (int) *mxGetPr(prhs[5]); 126 | } else { 127 | Level = 5; 128 | } 129 | 130 | 131 | int I = 0; 132 | int J = 1; 133 | int Winsize = 10; 134 | 135 | // Images 136 | if (IMG[I] != 0) { 137 | loadImageFromMatlab(prhs[1],IMG[I]); 138 | } else { 139 | CvSize imageSize = cvSize(mxGetN(prhs[1]),mxGetM(prhs[1])); 140 | IMG[I] = cvCreateImage( imageSize, 8, 1 ); 141 | PYR[I] = cvCreateImage( imageSize, 8, 1 ); 142 | loadImageFromMatlab(prhs[1],IMG[I]); 143 | } 144 | 145 | if (IMG[J] != 0) { 146 | loadImageFromMatlab(prhs[2],IMG[J]); 147 | } else { 148 | CvSize imageSize = cvSize(mxGetN(prhs[2]),mxGetM(prhs[2])); 149 | IMG[J] = cvCreateImage( imageSize, 8, 1 ); 150 | PYR[J] = cvCreateImage( imageSize, 8, 1 ); 151 | loadImageFromMatlab(prhs[2],IMG[J]); 152 | } 153 | 154 | // Points 155 | double *ptsI = mxGetPr(prhs[3]); int nPts = mxGetN(prhs[3]); 156 | double *ptsJ = mxGetPr(prhs[4]); 157 | 158 | if (nPts != mxGetN(prhs[4])) { 159 | mexPrintf("Inconsistent input!\n"); 160 | return; 161 | } 162 | 163 | points[0] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // template 164 | points[1] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // target 165 | points[2] = (CvPoint2D32f*)cvAlloc(nPts*sizeof(CvPoint2D32f)); // forward-backward 166 | 167 | for (int i = 0; i < nPts; i++) { 168 | points[0][i].x = ptsI[2*i]; points[0][i].y = ptsI[2*i+1]; 169 | points[1][i].x = ptsJ[2*i]; points[1][i].y = ptsJ[2*i+1]; 170 | points[2][i].x = ptsI[2*i]; points[2][i].y = ptsI[2*i+1]; 171 | } 172 | 173 | // allocate space for the LK results... 174 | float *ncc = (float*) cvAlloc(nPts*sizeof(float)); 175 | float *ssd = (float*) cvAlloc(nPts*sizeof(float)); 176 | float *fb = (float*) cvAlloc(nPts*sizeof(float)); 177 | char *status = (char*) cvAlloc(nPts); 178 | char *backStatus = (char*) cvAlloc(nPts); 179 | 180 | cvCalcOpticalFlowPyrLK( IMG[I], IMG[J], PYR[I], PYR[J], points[0], points[1], nPts, cvSize(win_size,win_size), Level, status, 0, cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), CV_LKFLOW_INITIAL_GUESSES); 181 | cvCalcOpticalFlowPyrLK( IMG[J], IMG[I], PYR[J], PYR[I], points[1], points[2], nPts, cvSize(win_size,win_size), Level, backStatus, 0, cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS,20,0.03), CV_LKFLOW_INITIAL_GUESSES | CV_LKFLOW_PYR_A_READY | CV_LKFLOW_PYR_B_READY ); 182 | 183 | normCrossCorrelation(IMG[I],IMG[J],points[0],points[1],nPts, status, ncc, Winsize,CV_TM_CCOEFF_NORMED); 184 | //normCrossCorrelation(IMG[I],IMG[J],points[0],points[1],nPts, status, ssd, Winsize,CV_TM_SQDIFF); 185 | euclideanDistance( points[0],points[2],fb,nPts); 186 | 187 | 188 | // Output 189 | int M = 4; 190 | plhs[0] = mxCreateDoubleMatrix(M, nPts, mxREAL); 191 | double *output = mxGetPr(plhs[0]); 192 | for (int i = 0; i < nPts; i++) { 193 | if (status[i] == 1) { 194 | output[M*i] = (double) points[1][i].x; 195 | output[M*i+1] = (double) points[1][i].y; 196 | output[M*i+2] = (double) fb[i]; 197 | output[M*i+3] = (double) ncc[i]; 198 | //output[M*i+4] = (double) ssd[i]; 199 | } else { 200 | output[M*i] = nan; 201 | output[M*i+1] = nan; 202 | output[M*i+2] = nan; 203 | output[M*i+3] = nan; 204 | //output[M*i+4] = nan; 205 | } 206 | } 207 | 208 | // free storage 209 | for (int i = 0; i < MAX_IMG; i++) { 210 | cvReleaseImage(&(IMG[i])); IMG[i] = 0; 211 | cvReleaseImage(&(PYR[i])); PYR[i] = 0; 212 | } 213 | free(IMG); IMG = 0; 214 | free(PYR); PYR = 0; 215 | //mexPrintf("LK: deallocated\n"); 216 | cvFree(&ncc); 217 | cvFree(&ssd); 218 | cvFree(&fb ); 219 | cvFree(&status); 220 | cvFree(&backStatus); 221 | 222 | return; 223 | } 224 | 225 | 226 | -------------------------------------------------------------------------------- /3rd_party/TLD/lkcompile.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | function lkcompile() 18 | [void,opencv_args] = unix('pkg-config --cflags --libs opencv | sed "s|/usr/lib64/libopencv_superres.so||g"') 19 | cmd = ['mex -g 3rd_party/TLD/lk.cpp -O ' opencv_args] 20 | eval(cmd); 21 | 22 | lk(0); 23 | end 24 | 25 | -------------------------------------------------------------------------------- /3rd_party/TLD/tldTracking.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | % 18 | % JSS3 - 2012.6.19 19 | % Conf, now, comes from LK not from NN validator. 20 | function [BB2 conf Valid] = tldTracking(BB1,I,J) 21 | % Estimates motion of bounding box BB1 from frame I to frame J 22 | 23 | % initialize output variables 24 | BB2 = []; % estimated bounding 25 | conf = []; % confidence of prediction 26 | Valid = 0; % is the predicted bounding box valid? if yes, learning will take place ... 27 | 28 | % estimate BB2 29 | xFI = bb_points(BB1,10,10,5); % generate 10x10 grid of points within BB1 with margin 5 px 30 | xFJ = lk(2,I,J,xFI,xFI); % track all points by Lucas-Kanade tracker from frame I to frame J, estimate Forward-Backward error, and NCC for each point 31 | medFB = median2(xFJ(3,:)); % get median of Forward-Backward error 32 | medNCC = median2(xFJ(4,:)); % get median for NCC 33 | idxF = xFJ(3,:) <= medFB & xFJ(4,:)>= medNCC; % get indexes of reliable points 34 | BB2 = bb_predict(BB1,xFI(:,idxF),xFJ(1:2,idxF)); % estimate BB2 using the reliable points only 35 | % assert(~gt_occluded(BB2')) 36 | 37 | %tld.xFJ = xFJ(:,idxF); % save selected points (only for display purposes) 38 | 39 | % detect failures 40 | %if ~bb_isdef(BB2) || bb_isout(BB2,size(I)), BB2 = []; return; end % bounding box out of image 41 | %if medFB > 10, BB2 = []; return; end % too unstable predictions 42 | 43 | % JSS3 - compute the confidence 44 | % get the valid points. 45 | %keyboard; 46 | xFI = xFI(1:2,idxF); 47 | xFJ = xFJ(1:2,idxF); 48 | total = size(xFI',1); 49 | correct = sum(rect_contains(BB2',xFJ')); 50 | conf = correct/total; 51 | 52 | % failed prediction ? 53 | if total < 1 54 | BB2 = BB1(1:4,:); 55 | conf = 0; 56 | end 57 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/idx2id.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function id = idx2id(idx,N) 19 | 20 | id = zeros(1,N); 21 | id(idx) = 1; 22 | id = logical(id); -------------------------------------------------------------------------------- /3rd_party/TLD/utils/mat2img.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function img = mat2img(data,no_row) 19 | % 'Data' contains square images stored in columns. 20 | 21 | if ~exist('RATIO','var') 22 | RATIO = 1; 23 | end 24 | 25 | 26 | if isempty(data) 27 | img = []; return; 28 | end 29 | 30 | [M,N] = size(data); 31 | 32 | sM = sqrt(M); 33 | if ceil(sM) ~= sM 34 | img = []; disp('Wrong input!'); return; 35 | end 36 | 37 | W = sM; 38 | H = sM; 39 | 40 | if no_row > N, no_row = N; end 41 | no_col = ceil(N/no_row); 42 | %no_row = ceil(N/no_col); 43 | img = zeros(no_row*H,no_col*W); 44 | 45 | for i = 1:N 46 | 47 | [I, J] = ind2sub([no_row, no_col], i); 48 | 49 | row = 1+(I-1)*H:(I-1)*H+H; 50 | col = 1+(J-1)*W:(J-1)*W+W; 51 | 52 | img0 = reshape(data(:,i),sM,sM); 53 | img0 = (img0 - min(img0(:))) / (max(img0(:)) - min(img0(:))); 54 | img(row, col) = img0; 55 | 56 | end 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/maximize.m: -------------------------------------------------------------------------------- 1 | function maximize(fig) 2 | % MAXIMIZE Size a window to fill the entire screen. 3 | % 4 | % maximize(HANDLE fig) 5 | % Will size the window with handle fig such that it fills the entire screen. 6 | % 7 | 8 | % Modification History 9 | % ??/??/2001 WHF Created. 10 | % 04/17/2003 WHF Found 'outerposition' undocumented feature. 11 | % 12 | 13 | % Original author: Bill Finger, Creare Inc. 14 | % Free for redistribution as long as credit comments are preserved. 15 | % 16 | 17 | if nargin==0, fig=gcf; end 18 | 19 | units=get(fig,'units'); 20 | set(fig,'units','normalized','outerposition',[0 0 1 1]); 21 | set(fig,'units',units); 22 | 23 | % Old way: 24 | % These are magic numbers which are probably system dependent. 25 | dim=get(0,'ScreenSize')-[0 -5 0 72]; 26 | 27 | set(fig,'Position',dim); 28 | 29 | 30 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/median2.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function m = median2(x) 19 | % Median without nan 20 | 21 | x(isnan(x)) = []; 22 | m = median(x); 23 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/n2s.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function s = n2s(x,N) 19 | % Number to string. 20 | 21 | s = num2str(x,['%0' num2str(N) 'd']); 22 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/ntuples.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function ntuple = ntuples(varargin) 19 | % Computes all possible ntupples. 20 | 21 | x = varargin; 22 | 23 | ntuple = x{1}; 24 | for i = 2:length(x) 25 | num_col = size(ntuple,2); 26 | num_item = length(x{i}); 27 | ntuple = repcel(ntuple, 1, num_item); 28 | newline = repmat(x{i},1,num_col); 29 | ntuple = [ntuple;newline]; 30 | end 31 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/pseudorandom_indexes.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function idx = pseudorandom_indexes(N,k) 19 | 20 | start = randi(k,1,1); 21 | 22 | idx = start:k:N; -------------------------------------------------------------------------------- /3rd_party/TLD/utils/randvalues.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function out = randvalues(in,k) 19 | % Randomly selects 'k' values from vector 'in'. 20 | 21 | out = []; 22 | 23 | N = size(in,2); 24 | 25 | if k == 0 26 | return; 27 | end 28 | 29 | if k > N 30 | k = N; 31 | end 32 | 33 | if k/N < 0.0001 34 | i1 = unique(ceil(N*rand(1,k))); 35 | out = in(:,i1); 36 | 37 | else 38 | i2 = randperm(N); 39 | out = in(:,sort(i2(1:k))); 40 | end -------------------------------------------------------------------------------- /3rd_party/TLD/utils/repcel.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function out = repcel(in,M,N) 19 | % Repeats cells MxN times. 20 | 21 | out = in(repmat(1:size(in,1),M,1),repmat(1:size(in,2),N,1)); -------------------------------------------------------------------------------- /3rd_party/TLD/utils/uniquecount.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function out = uniquecount(in) 19 | % Replaces value with number of occurences. 20 | 21 | uin = unique(in); 22 | out = in; 23 | for i = 1:length(uin) 24 | 25 | id = in == uin(i); 26 | out(id) = sum(id); 27 | end 28 | 29 | -------------------------------------------------------------------------------- /3rd_party/TLD/utils/vnormp.m: -------------------------------------------------------------------------------- 1 | % Copyright 2011 Zdenek Kalal 2 | % 3 | % This file is part of TLD. 4 | % 5 | % TLD is free software: you can redistribute it and/or modify 6 | % it under the terms of the GNU General Public License as published by 7 | % the Free Software Foundation, either version 3 of the License, or 8 | % (at your option) any later version. 9 | % 10 | % TLD is distributed in the hope that it will be useful, 11 | % but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | % GNU General Public License for more details. 14 | % 15 | % You should have received a copy of the GNU General Public License 16 | % along with TLD. If not, see . 17 | 18 | function out = vnormp(in,p) 19 | % p-norm of columns 20 | 21 | out = (sum(abs(in).^p,1)).^(1/p); -------------------------------------------------------------------------------- /3rd_party/addpath/addpath_recurse.m: -------------------------------------------------------------------------------- 1 | function addpath_recurse(strStartDir, caStrsIgnoreDirs, strXorIntAddpathMode, blnRemDirs, blnDebug) 2 | %ADDPATH_RECURSE Adds (or removes) the specified directory and its subfolders 3 | % addpath_recurse(strStartDir, caStrsIgnoreDirs, strXorIntAddpathMode, blnRemDirs, blnDebug) 4 | % 5 | % By default, all hidden directories (preceded by '.'), overloaded method directories 6 | % (preceded by '@'), and directories named 'private' or 'CVS' are ignored. 7 | % 8 | % Input Variables 9 | % =============== 10 | % strStartDir:: 11 | % Starting directory full path name. All subdirectories (except ignore list) will be added to the path. 12 | % By default, uses current directory. 13 | % caStrsIgnoreDirs:: 14 | % Cell array of strings specifying directories to ignore. 15 | % Will also ignore all subdirectories beneath these directories. 16 | % By default, empty list. i.e. {''}. 17 | % strXorIntAddpathMode:: 18 | % Addpath mode, either 0/1, or 'begin','end'. 19 | % By default, prepends. 20 | % blnRemDirs:: 21 | % Boolean, when true will run function "in reverse", and 22 | % recursively removes directories from starting path. 23 | % By default, false. 24 | % blnDebug:: 25 | % Boolean, when true prints debug info. 26 | % By default, false. 27 | % 28 | % Output Variables 29 | % ================ 30 | % None. If blnDebug is specified, diagnostic information will print to the screen. 31 | % 32 | % Example(s) 33 | % ========== 34 | % (1) addpath_recurse(); %Take all defaults. 35 | % (2) addpath_recurse('strStartDir'); %Start at 'strStartDir', take other defaults. i.e. Do addpath(). 36 | % (3) addpath_recurse('strStartDir', '', 0, true); %Start at 'strStartDir', and undo example (2). i.e. Do rmpath(). 37 | % (4) addpath_recurse('strStartDir', '', 'end', false, true); %Do example (2) again, append to path, and display debug info. 38 | % (5) addpath_recurse('strStartDir', '', 1, true, true); %Undo example (4), and display debug info. 39 | 40 | % 41 | % See Also 42 | % ======== 43 | % addpath() 44 | % 45 | % Developers 46 | % =========== 47 | % Init Name Contact 48 | % ---- --------------- --------------------------------------------- 49 | % AK Anthony Kendall anthony [dot] kendall [at] gmail [dot] com 50 | % JMcD Joe Mc Donnell 51 | % 52 | % Modifications 53 | % ============= 54 | % Version Date Who What 55 | % -------- -------- ----- -------------------------------------------------------------------- 56 | % 00.00.00 20080808 AK First created. 57 | % 20090410 JMcD Redo input argument processing/checking. 58 | % Only do processing/checking once. Do recursion in separate function. 59 | % 20090411 JMcD Add debugging mode to display run info. 60 | % 20090414 AK Modified variable names, small edits to code, ignoring CSV by default 61 | % 20091104 AK Modified an optimization for Mac compatibility, 62 | % recursive calls to just build the string for 63 | % addpath/rmpath rather than call it each time 64 | 65 | %-------------------------------------------------------------------------- 66 | %Error messages. 67 | strErrStartDirNoExist = 'Start directory does not exist ???'; 68 | strErrIgnoreDirsType = 'Ignore directories must be a string or cell array. See HELP ???'; 69 | strErrIllAddpathMode = 'Illegal value for addpath() mode. See HELP ???'; 70 | strErrIllRevRecurseRemType = 'Illegal value for reverse recurse remove, must be a logical/boolean. See HELP ??'; 71 | 72 | strErrWrongNumArg = 'Wrong number of input arguments. See HELP ???'; 73 | strAddpathErrMessage = strErrIllAddpathMode; 74 | 75 | %Set input args defaults and/or check them. 76 | intNumInArgs = nargin(); 77 | assert(intNumInArgs <= 5, strErrWrongNumArg); 78 | 79 | if intNumInArgs < 1 80 | strStartDir = pwd(); 81 | end 82 | 83 | if intNumInArgs < 2 84 | caStrsIgnoreDirs = {''}; 85 | end 86 | 87 | if intNumInArgs >= 2 && ischar(caStrsIgnoreDirs) 88 | caStrsIgnoreDirs = { caStrsIgnoreDirs }; 89 | end 90 | 91 | if intNumInArgs < 3 || (intNumInArgs >= 3 && isempty(strXorIntAddpathMode)) 92 | strXorIntAddpathMode = 0; 93 | end 94 | 95 | if intNumInArgs >= 3 && ischar(strXorIntAddpathMode) %Use 0/1 internally. 96 | strAddpathErrMessage = sprintf('Input arg addpath() mode "%s" ???\n%s', strXorIntAddpathMode, strErrIllAddpathMode); 97 | assert(any(strcmpi(strXorIntAddpathMode, {'begin', 'end'})), strAddpathErrMessage); 98 | strXorIntAddpathMode = strcmpi(strXorIntAddpathMode, 'end'); %When 'end' 0 sets prepend, otherwise 1 sets append. 99 | end 100 | 101 | if intNumInArgs < 4 102 | blnRemDirs = false; 103 | end 104 | 105 | if intNumInArgs < 5 106 | blnDebug = false; 107 | end 108 | 109 | if size(caStrsIgnoreDirs, 1) > 1 110 | caStrsIgnoreDirs = caStrsIgnoreDirs'; %Transpose from column to row vector, in theory. 111 | end 112 | 113 | %Check input args OK, before we do the thing. 114 | strErrStartDirNoExist = sprintf('Input arg start directory "%s" ???\n%s', strStartDir, strErrStartDirNoExist); 115 | assert(exist(strStartDir, 'dir') > 0, strErrStartDirNoExist); 116 | assert(iscell(caStrsIgnoreDirs), strErrIgnoreDirsType); 117 | assert(strXorIntAddpathMode == 0 || strXorIntAddpathMode == 1, strAddpathErrMessage); 118 | assert(islogical(blnRemDirs), strErrIllRevRecurseRemType); 119 | assert(islogical(blnDebug), 'Debug must be logical/boolean. See HELP.'); 120 | 121 | if blnDebug 122 | intPrintWidth = 34; 123 | rvAddpathModes = {'prepend', 'append'}; 124 | strAddpathMode = char(rvAddpathModes{ fix(strXorIntAddpathMode) + 1}); 125 | strRevRecurseDirModes = { 'false', 'true' }; 126 | strRevRecurseDirs = char(strRevRecurseDirModes{ fix(blnRemDirs) + 1 }); 127 | strIgnoreDirs = ''; 128 | for intD = 1 : length(caStrsIgnoreDirs) 129 | if ~isempty(strIgnoreDirs) 130 | strIgnoreDirs = sprintf('%s, ', strIgnoreDirs); 131 | end 132 | strIgnoreDirs = sprintf('%s%s', strIgnoreDirs, char(caStrsIgnoreDirs{intD})); 133 | end 134 | strTestModeResults = sprintf('... Debug mode, start recurse addpath arguments ...'); 135 | strTestModeResults = sprintf('%s\n%*s: "%s"', strTestModeResults, intPrintWidth, 'Start directory', strStartDir); 136 | strTestModeResults = sprintf('%s\n%*s: "%s"', strTestModeResults, intPrintWidth, 'Ignore directories', strIgnoreDirs); 137 | strTestModeResults = sprintf('%s\n%*s: "%s"', strTestModeResults, intPrintWidth, 'addpath() mode', strAddpathMode); 138 | strTestModeResults = sprintf('%s\n%*s: "%s"', strTestModeResults, intPrintWidth, 'Reverse recurse remove directories', strRevRecurseDirs); 139 | disp(strTestModeResults); 140 | end 141 | 142 | %Don't print the MATLAB warning if remove path string is not found 143 | if blnRemDirs, warning('off', 'MATLAB:rmpath:DirNotFound'); end 144 | 145 | %Build the list of directories 146 | caAddRemDirs = {}; 147 | [caAddRemDirs] = addpath_recursively(caAddRemDirs, strStartDir, caStrsIgnoreDirs, strXorIntAddpathMode, blnRemDirs,blnDebug); 148 | 149 | %Remove or add the directory from the search path 150 | if blnRemDirs 151 | if blnDebug, fprintf('"%s", removing from search path ...', strStartDir); end 152 | rmpath(caAddRemDirs{:}) 153 | else 154 | if blnDebug, fprintf('"%s", adding to search path ...', strStartDir); end 155 | addpath(caAddRemDirs{:}, strXorIntAddpathMode); 156 | end 157 | 158 | %Restore the warning state for rmpath 159 | if blnRemDirs, warning('on', 'MATLAB:rmpath:DirNotFound'); end 160 | 161 | end % function addpath_recurse 162 | %-------------------------------------------------------------------------- 163 | 164 | %-------------------------------------------------------------------------- 165 | function [caAddRemDirs] = addpath_recursively(caAddRemDirs, strStartDir, caStrsIgnoreDirs, strXorIntAddpathMode, blnRemDirs, blnDebug) 166 | %Note:Don't need to check input arguments, because caller already has. 167 | 168 | %Add this directory to the add/remove path list 169 | caAddRemDirs = [caAddRemDirs,strStartDir]; 170 | 171 | strFileSep = filesep(); 172 | %Get list of directories beneath the specified directory, this two-step process is faster. 173 | if ispc 174 | saSubDirs = dir(sprintf('%s%s%s', strStartDir, strFileSep, '*.')); 175 | else 176 | saSubDirs = dir(strStartDir); 177 | end 178 | saSubDirs = saSubDirs([saSubDirs.isdir]); %Handles files without extensions that otherwise pass through previous filter 179 | 180 | %Loop through the directory list and recursively call this function. 181 | for intDirIndex = 1 : length(saSubDirs) 182 | strThisDirName = saSubDirs(intDirIndex).name; 183 | blnIgnoreDir = any(strcmpi(strThisDirName, { 'private', 'CVS', '.', '..', caStrsIgnoreDirs{:} })); 184 | blnDirBegins = any(strncmp(strThisDirName, {'@', '.'}, 1)); 185 | if ~(blnIgnoreDir || blnDirBegins) 186 | strThisStartDir = sprintf('%s%s%s', strStartDir, strFileSep, strThisDirName); 187 | if blnDebug, fprintf('"%s", recursing ...', strThisStartDir); end 188 | [caAddRemDirs] = addpath_recursively(caAddRemDirs, strThisStartDir, caStrsIgnoreDirs, strXorIntAddpathMode, blnRemDirs, blnDebug); 189 | end 190 | end % for each directory. 191 | 192 | end % function addpath_recursively 193 | %-------------------------------------------------------------------------- 194 | %__END__ 195 | -------------------------------------------------------------------------------- /3rd_party/addpath/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009, Anthony Kendall 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 | -------------------------------------------------------------------------------- /3rd_party/sfigure.m: -------------------------------------------------------------------------------- 1 | % SFIGURE Create figure window (minus annoying focus-theft). 2 | % 3 | % Usage is identical to figure. 4 | % 5 | % Daniel Eaton, 2005 6 | % JSS3 2012.5.16 : cleaned up the format. 7 | %% See also "help figure" 8 | function h = sfigure(h) 9 | % debug 10 | %'sfigure!' 11 | %keyboard; 12 | 13 | 14 | % functionality 15 | if nargin>=1 16 | if ishandle(h) 17 | set(0, 'CurrentFigure', h); 18 | else 19 | h = figure(h); 20 | end 21 | else 22 | h = figure; 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /3rd_party/uninit/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011, James Tursa 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 | -------------------------------------------------------------------------------- /3rd_party/uninit/uninit.m: -------------------------------------------------------------------------------- 1 | % UNINIT returns an unitialized array of specified size and class. 2 | %************************************************************************************* 3 | % 4 | % MATLAB (R) is a trademark of The Mathworks (R) Corporation 5 | % 6 | % Function: uninit 7 | % Filename: uninit.c 8 | % Programmer: James Tursa 9 | % Version: 1.00 10 | % Date: May 03, 2011 11 | % Copyright: (c) 2011 by James Tursa, All Rights Reserved 12 | % 13 | % Change Log: 14 | % 2011/May/03 --> 1.00, Initial Release 15 | % 16 | % This code uses the BSD License: 17 | % 18 | % Redistribution and use in source and binary forms, with or without 19 | % modification, are permitted provided that the following conditions are 20 | % met: 21 | % 22 | % * Redistributions of source code must retain the above copyright 23 | % notice, this list of conditions and the following disclaimer. 24 | % * Redistributions in binary form must reproduce the above copyright 25 | % notice, this list of conditions and the following disclaimer in 26 | % the documentation and/or other materials provided with the distribution 27 | % 28 | % THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 29 | % AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 | % IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 | % ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 32 | % LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 33 | % CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 34 | % SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 35 | % INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 36 | % CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 37 | % ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 38 | % POSSIBILITY OF SUCH DAMAGE. 39 | % 40 | % Building: 41 | % 42 | % UNINIT is typically self building. That is, the first time you call UNINIT, 43 | % the uninit.m file recognizes that the mex routine needs to be compiled and 44 | % then the compilation will happen automatically. UNINIT uses the undocumented 45 | % MATLAB API function mxCreateUninitNumericMatrix. It has been tested in PC 46 | % versions R2008b through R2011a, but may not work in future versions of MATLAB. 47 | % 48 | % Syntax (nearly identical to the ZEROS function) 49 | % 50 | % B = uninit 51 | % B = uninit(n) 52 | % B = uninit(m,n) 53 | % B = uninit([m n]) 54 | % B = uninit(m,n,p,...) 55 | % B = uninit([m n p ...]) 56 | % B = uninit(size(A)) 57 | % B = uninit(m, n,...,classname) 58 | % B = uninit([m,n,...],classname) 59 | % B = uninit(m, n,...,complexity) 60 | % B = uninit([m,n,...],complexity) 61 | % B = uninit(m, n,...,classname,complexity) 62 | % B = uninit([m,n,...],classname,complexity) 63 | % 64 | % Description 65 | % 66 | % B = uninit 67 | % Returns a 1-by-1 scalar uninitialized value. 68 | % 69 | % B = uninit(n) 70 | % Returns an n-by-n matrix of uninitialized values. An error message 71 | % appears if n is not a scalar. 72 | % 73 | % B = uninit(m,n) or B = uninit([m n]) 74 | % Returns an m-by-n matrix of uninitialized values. 75 | % 76 | % B = uninit(m,n,p,...) or B = uninit([m n p ...]) 77 | % Returns an m-by-n-by-p-by-... array of uninitialized values. The 78 | % size inputs m, n, p, ... should be nonnegative integers. Negative 79 | % integers are treated as 0. 80 | % 81 | % B = uninit(size(A)) 82 | % Returns an array the same size as A consisting of all uninitialized 83 | % values. 84 | % 85 | % If any of the numeric size inputs are empty, they are taken to be 0. 86 | % 87 | % The optional classname argument can be used with any of the above. 88 | % classname is a string specifying the data type of the output. 89 | % classname can have the following values: 90 | % 'double', 'single', 'int8', 'uint8', 'int16', 'uint16', 91 | % 'int32', 'uint32', 'int64', 'uint64', 'logical', or 'char'. 92 | % (Note: 'logical' and 'char' are not allowed in the ZEROS function) 93 | % The default classname is 'double'. 94 | % 95 | % The optional complexity argument can be used with any of the above. 96 | % complexity can be 'real' or 'complex', except that 'logical' and 'char' 97 | % outputs cannot be complex. (this option not allowed in the ZEROS function) 98 | % The default complexity is 'real'. 99 | % 100 | % UNINIT is very similar to the ZEROS function, except that UNINIT returns 101 | % an uninitialized array instead of a zero-filled array. Thus, UNINIT is 102 | % faster than the ZEROS function for large size arrays. Since the return 103 | % variable is uninitialized, the user must take care to assign values to 104 | % the elements before using them. UNINIT is useful for preallocation of an 105 | % array where you know the elements will be assigned values before using them. 106 | % 107 | % Example 108 | % 109 | % x = uninit(2,3,'int8'); 110 | % 111 | %***************************************************************************/ 112 | 113 | function varargout = uninit(varargin) 114 | fname = 'uninit'; 115 | disp(' '); 116 | disp(['Detected that the mex routine for ' fname ' is not yet built.']); 117 | disp('Attempting to do so now ...'); 118 | disp(' '); 119 | try 120 | mname = mfilename('fullpath'); 121 | catch 122 | mname = fname; 123 | end 124 | cname = [mname '.c']; 125 | if( isempty(dir(cname)) ) 126 | disp(['Cannot find the file ' fname '.c in the same directory as the']); 127 | disp(['file ' fname '.m. Please ensure that they are in the same']); 128 | disp('directory and try again. The following file was not found:'); 129 | disp(' '); 130 | disp(cname); 131 | disp(' '); 132 | error(['Unable to compile ' fname '.c']); 133 | else 134 | disp(['Found file ' fname '.c in ' cname]); 135 | disp(' '); 136 | disp('Now attempting to compile ...'); 137 | disp('(If prompted, please press the Enter key and then select any C/C++'); 138 | disp('compiler that is available, such as lcc.)'); 139 | disp(' '); 140 | disp(['mex(''' cname ''',''-output'',''',mname,''')']); 141 | disp(' '); 142 | try 143 | mex(cname,'-output',mname); 144 | disp([ fname ' mex build completed ... you may now use ' fname '.']); 145 | disp(' '); 146 | catch 147 | disp(' '); 148 | error(['Unable to compile ' fname ' ... Contact author.']); 149 | end 150 | [varargout{1:nargout}] = uninit(varargin{:}); 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /3rd_party/uninit/uninit.mexa64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsupancic/SPLTT-Release/40c1723b7958ea3068c37effa5d9f3d4edf4f426/3rd_party/uninit/uninit.mexa64 -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | To actually get this beast to run on your computer, you'll probably have to 2 | edit some of the matlab files in the config/ subdirectory. 3 | (1) config/datapath.m should return the path where you have your videos stored. 4 | The path should point to a directory which includes a subdirectory for each video. 5 | E.g. $(datapath)/tiger2/. 6 | Each subdirectory should contain files with ground truth labelings and images similar 7 | to what MIL-Track uses. 8 | As an example, see my track-data.zip file. 9 | (2) cluster_ctl is called like so cluster_ctl('on',...) or cluster_ctl('off',...) 10 | to enable or disable the matlab pool. I have three pools, with different characteristics, 11 | available to me so this function, heuristically, selects the best one. Depending on what 12 | type of MATLAB pools you have, you'll need to rewrite this function. The simplest option 13 | would be to call "matlabpool open" when called with "on" and "matlabpool close" when 14 | called with "off". 15 | (3) You should be able to compile by simplying calling "compile.m". I've tested this on Linux 16 | and it should work on other OSs... I welcome patches. 17 | (4) config/cfg.m : lets you stitch many of the parameters of the tracker. Of particular 18 | interest will be the option 'tmp_dir'. You'll want to point this to an empty directory 19 | which is writable. It is used for caching results. 20 | 21 | Then, you "should" be able to run it with a command similar to the following: 22 | addpath(genpath('.')); matlab_init('coke11'); track = track_online('coke11'); 23 | 24 | Alternatively, you might just use track_tbd('coke11'); which doesn't do any learning (after 25 | the first frame) or use a motion model. It is much faster and still performs quite well. 26 | 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SPLTT-Release 2 | ============= 3 | 4 | The Release Code for our CVPR 2013 Submission "Self-paced learning for long-term tracking". -------------------------------------------------------------------------------- /compile.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-11 2 | % rebuild the compiled components 3 | function compile() 4 | % compile TLD's LK module. 5 | addpath('3rd_party/TLD/'); 6 | 7 | % Compile mex files 8 | % (a) mex version of features.m 9 | % (b) mex version of matlab's image resize 10 | % (c) QP solver 11 | mex CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS" detection/features_c.cc 12 | mex CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS" detection/mex_resize.cc 13 | mex CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS" detection/reduce.cc; 14 | mex CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS" detection/nms_c.cc 15 | mex CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS" -g -O -largeArrayDims qp/qp_one_c.cc 16 | mex CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS" track_dp/dynprog_chain.cc 17 | lkcompile; 18 | 19 | % compile hashMat which requires openssl 20 | [void,args] = unix(['pkg-config --cflags --libs ' ... 21 | 'openssl']) 22 | cmd = sprintf('mex %s -g video/hashMat.cc -O %s','CXXFLAGS="-pedantic -Werror -I mex/ -O3 \$CXXFLAGS"',args); 23 | eval(cmd); 24 | end 25 | -------------------------------------------------------------------------------- /config/cfg.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-30 2 | % function which returns configuration information 3 | function p = cfg(option) 4 | if strcmp(option,'correct_overlap') 5 | p = .25; 6 | elseif strcmp(option,'tmp_dir') 7 | p = '~/tmp/matlabTrack/'; 8 | elseif strcmp(option,'sample_negatives') 9 | % sample some negatives from around the positive 10 | % rather than search over all possible negatives. 11 | p = 0; 12 | elseif strcmp(option,'C') 13 | p = .1; % default is .1; 14 | elseif strcmp(option,'cluster_name') 15 | p = 'wildHOG'; 16 | elseif strcmp(option,'dp_min_time_occluded') 17 | p = 25; 18 | elseif strcmp(option,'use_lk') 19 | p = 1; 20 | elseif strcmp(option,'cost_dp_lcl'); 21 | % this is meaningless legacy option 22 | p = 1; 23 | else 24 | fprintf('bad option name\n'); 25 | assert(false); 26 | end 27 | end -------------------------------------------------------------------------------- /config/cluster_ctl.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.6.15 2 | % function to turn the cluster on or off. 3 | % jobDesc: small, large, local (largest on one machine) 4 | % This file has to be tuned to *your* computational resources. 5 | % 6 | % This simplest way to configure this is to just use a single 7 | % parallel pool, in which case you just want to do 8 | % "matlabpool open" when option is "on" 9 | % "matlabpool close" when option is "off" 10 | % 11 | % For me, 12 | % "small" opens a small 8 to 12 processor pool using parallel 13 | % MATLAB toolbox. 14 | % "local" opens a local pool of maximum size 48 cores on one 15 | % machine using the distributed toolbox. 16 | % "large" opens a multi-machine distributed pool. This may be 17 | % undesirable for some tasks because (1) this pool can become a 18 | % bottleneck and (2) distributing data over the network is slow. 19 | function on = cluster_ctl(option,jobDesc,cores) 20 | % NOP on a worker... 21 | if ~isempty(getCurrentTask) || ~usejava('jvm') 22 | return 23 | end 24 | 25 | % default arguments 26 | if nargin < 2 27 | jobDesc = 'large'; 28 | end 29 | if nargin < 3 30 | cores = inf; 31 | end 32 | 33 | % don't give the client more cores than it requested. 34 | if strcmp(option,'on') 35 | matlabpool open; 36 | elseif strcmp(option,'off') && matlabpool('size') > 0 37 | matlabpool close; 38 | elseif strcmp(option,'killall') 39 | matlabpool close; 40 | end 41 | end 42 | 43 | -------------------------------------------------------------------------------- /config/datapath.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-5-29 2 | % define the global data storage location 3 | function dp = datapath() 4 | HOSTNAME = getenv('HOSTNAME'); 5 | 6 | if strcmp(HOSTNAME,'wildHOG') 7 | HOME = '/home/jsupanci/'; 8 | else 9 | HOME = getenv('HOME'); 10 | end 11 | 12 | dp = [HOME '/workspace/data/tracking/']; 13 | %dp 14 | end 15 | -------------------------------------------------------------------------------- /config/matlab_init.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-15 2 | % function to configure MATLAB for my code to run. 3 | function [model,Jpos,C] = matlab_init(vidName) 4 | % don't re-initialize unless we are just starting up or 5 | % switching videos. 6 | global G_VID_NAME; 7 | if strcmp(G_VID_NAME,vidName) && nargout < 1 8 | % already initialized 9 | return; 10 | end 11 | G_VID_NAME = vidName; 12 | 13 | global G_HOME; 14 | G_HOME = getenv('HOME') 15 | 16 | % model details... 17 | global ORI_BINS; 18 | ORI_BINS = 18; 19 | 20 | % where to save stuff? 21 | global G_LOG_PREFIX; 22 | G_LOG_PREFIX = [cfg('tmp_dir') date() num2str(now()) ... 23 | '-' vidName '-']; 24 | 25 | % compile? 26 | compile(); 27 | 28 | % clear the display 29 | format compact; 30 | %close all; 31 | lk(0); 32 | % the code uses a random number generator in qp_one.m 33 | % it is important that results be reproducible. 34 | if exist('rng') == 2 35 | rng(09221986,'twister'); 36 | else 37 | rand('seed',09221986); 38 | end 39 | if hasDisplay() 40 | % configure the image processing toolbox 41 | iptsetpref('ImshowInitialMagnification', 'fit'); 42 | % Don't open to many windows... 43 | set(0,'DefaultFigureWindowStyle','docked'); 44 | end 45 | % configure the paths 46 | setpath(); 47 | % protect against crashes without explanation... 48 | dbstop if error; 49 | 50 | % (a) Initialize model 51 | % (b) Train linear SVM with dual coordinate descent 52 | % (c) Run model on test images 53 | if nargout >= 1 54 | [model,Jpos,C] = genModel(vidName,nan); 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /config/setpath.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.6.15 2 | % configure the paths... 3 | function setpath(force) 4 | if nargin < 1 5 | force = 0; 6 | end 7 | 8 | fprintf('+setpath\n'); 9 | persistent paths_set; 10 | if isempty(paths_set) || force 11 | restoredefaultpath 12 | addpath(genpath('./3rd_party')); 13 | addpath_recurse('.','','end'); 14 | paths_set = 1; 15 | end 16 | fprintf('-setpath\n'); 17 | end 18 | -------------------------------------------------------------------------------- /detection/cost_lcl_tsvm.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-5-30 2 | % the transductive local cost computation 3 | function ei = cost_lcl_tsvm(model,vidName,frameIter,k_det,pos,neg) 4 | % dissallow training rectangles larger than the image. 5 | imsz = rect_size(rect_image(get_frame(vidName,frameIter))); 6 | dtsz = rect_size(k_det); 7 | if any(dtsz >= imsz) 8 | ei = inf; 9 | return; 10 | end 11 | 12 | if nargin < 5 13 | pos = 1; 14 | end 15 | if nargin < 6 16 | neg = 1; 17 | end 18 | 19 | ub0 = model.qp.ub; 20 | lb0 = model.qp.lb; 21 | modelPrime = updateModel(model,model.Jpos); 22 | modelPrime = modelPrime.train_one(vidName,get_frame(vidName,frameIter),... 23 | rectKtoB(k_det),pos,neg); 24 | %keyboard; 25 | %[modelPrime.ub, ub0, modelPrime.lb, lb0] 26 | % UB is an estimate, LB is correct 27 | ei = max(modelPrime.qp.lb-lb0,0); 28 | if gt_occluded(k_det) 29 | % add a 'fake' occluded example. 30 | ei = ei + model.qp.C*2; % 2 = worst case, 1 = 31 | % average case, 0 = best case. 32 | end 33 | assert(~isnan(ei)); 34 | end 35 | -------------------------------------------------------------------------------- /detection/feat_code.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-6-1 2 | % Convert string to code number 3 | function code = feat_code(featName) 4 | if strcmp(featName,'color') 5 | code = 2; 6 | elseif strcmp(featName,'hog') 7 | code = 1; 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /detection/featpyramid.m: -------------------------------------------------------------------------------- 1 | function [feat, scale] = featpyramid(im, sbin, interval,f_features) 2 | if nargin < 4 3 | f_features = @(scaled,sbin) features(scaled,sbin,feat_code('hog')); 4 | end 5 | if nargin >= 4 && isstr(f_features) 6 | f_features = @(scaled,sbin) features(scaled,sbin,feat_code(f_features)); 7 | end 8 | 9 | % [feat, scale] = featpyramid(im, sbin, interval); 10 | % Compute feature pyramid. 11 | % 12 | % sbin is the size of a HOG cell - it should be even. 13 | % interval is the number of scales in an octave of the pyramid. 14 | % feat{i} is the i-th level of the feature pyramid. 15 | % scale(i) is the scaling factor used for the i-th level. 16 | % feat{i+interval} is computed at exactly half the resolution of feat{i}. 17 | 18 | sc = 2^(1/interval); 19 | imsize = [size(im, 1) size(im, 2)]; 20 | max_scale = 1 + floor(log(min(imsize)/(5*sbin))/log(sc)); 21 | feat = cell(max_scale, 1); 22 | scale = zeros(max_scale, 1); 23 | 24 | % our resize function wants floating point values 25 | im = double(im); 26 | for i = 1:interval 27 | %im 28 | sf = 1/sc^(i-1); 29 | scaled = mex_resize(im, sf); 30 | % "first" 2x interval 31 | feat{i} = f_features(scaled, sbin); 32 | scale(i) = sc^(i-1); 33 | % remaining interals 34 | for j = i+interval:interval:max_scale 35 | scaled = reduce(scaled); 36 | feat{j} = f_features(scaled, sbin); 37 | scale(j) = 2 * scale(j-interval); 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /detection/feature_get_for_svm.m: -------------------------------------------------------------------------------- 1 | % JSS3 function to get the HoG feature describing 2 | % a region in the format the SVM requires. 3 | function [feat,featIm] = feature_get_for_svm(model,im,b_bb) 4 | if ~check_rect_size(rectBtoK(b_bb),rect_image(im)) 5 | error('logicError','b_bb is to large'); 6 | end 7 | 8 | % drop parts of the bounding box multiple of model.sbin? 9 | %bb_width = b_bb(3); 10 | %bb_height = b_bb(4); 11 | % bb_excess_width = mod(bb_width,model.sbin); 12 | % bb_excess_height = mod(bb_height,model.sbin); 13 | % b_bb(1) = b_bb(1) - bb_excess_width/2; 14 | % b_bb(2) = b_bb(2) - bb_excess_height/2; 15 | % b_bb(3) = b_bb(3) - bb_excess_width; 16 | % b_bb(4) = b_bb(4) - bb_excess_height; 17 | 18 | % get the template... 19 | k_bb = rectBtoK(b_bb); 20 | % the next line changes -.6637 to -.8861 when 21 | % -.8918 is the goal. An improvement, a different 22 | % resize algorithm may account for the rest... 23 | dbg_im = im; 24 | crop_bb = [(k_bb(1)-model.sbin) (k_bb(2)-model.sbin) ... 25 | (k_bb(3)+model.sbin) (k_bb(4)+model.sbin)]; 26 | im = imcropr(im,crop_bb); 27 | nx = model.nx; 28 | ny = model.ny; 29 | na = model.nx .* model.ny; 30 | imx = size(im,2); 31 | imy = size(im,1); 32 | im_area = imx .* imy; 33 | sbins = round(sqrt(im_area/na)); 34 | im = imresize(im,[(model.ny+2)*model.sbin,(model.nx+2)*model.sbin]); 35 | 36 | % get the feature 37 | featIm = features(double(im),model.sbin,feat_code('hog')); 38 | %keyboard; 39 | 40 | zSize = size(model.w,3); % throw out extra components (work 41 | % with color or not). 42 | feat = featIm(:,:,1:zSize); 43 | feat = [feat(:); model.sb]; 44 | 45 | if isfield(model,'qp') 46 | assert(~isfield(model.qp,'x') || size(model.qp.x,1) == numel(feat)) 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /detection/features.m: -------------------------------------------------------------------------------- 1 | function feat = features(im,sbin,featCode) 2 | % res = features(im,sbin) 3 | % Let [imy,imx] = size(impatch) 4 | % -Result will be (imy/8-1) by (imx/8-1) by (4+9) for 5 | % 9 orientation bins and 4 normalizations for every 8x8 pixel-block 6 | % -This won't produce exact same results as features.cc because this 7 | % uses hard-binning rather than soft binning 8 | memo = [cfg('tmp_dir') 'features/' ... 9 | 'imHash=' hashMat(im) ... 10 | 'sbin=' num2str(sbin) ... 11 | 'featCode=' num2str(featCode) '.mat']; 12 | MEMO = 0; 13 | if exist(memo,'file') && MEMO 14 | load(memo,'feat'); 15 | return; 16 | end 17 | 18 | MEX = 1; 19 | if MEX 20 | feat = features_c(im,sbin,featCode); 21 | if MEMO 22 | save(memo,'feat'); 23 | end 24 | return; 25 | end 26 | 27 | % Crop/pad image to make its size a multiple of sbin 28 | [ty,tx,tz] = size(im); 29 | imy = round(ty/sbin)*sbin; 30 | if imy > ty, 31 | im = padarray(im,[imy-ty 0 0],'post'); 32 | elseif imy < ty, 33 | im = im(1:imy,:,:); 34 | end 35 | imx = round(tx/sbin)*sbin; 36 | if imx > tx, 37 | im = padarray(im,[0 imx-tx 0],'post'); 38 | elseif imx < tx, 39 | im = im(:,1:imx,:); 40 | end 41 | im = double(im); 42 | n = (imy-2)*(imx-2); 43 | 44 | % Pick the strongest gradient across color channels 45 | dy = im(3:end,2:end-1,:) - im(1:end-2,2:end-1,:); dy = reshape(dy,n,3); 46 | dx = im(2:end-1,3:end,:) - im(2:end-1,1:end-2,:); dx = reshape(dx,n,3); 47 | len = dx.^2 + dy.^2; 48 | [len,I] = max(len,[],2); 49 | len = sqrt(len); 50 | I = sub2ind([n 3],[1:n]',I); 51 | dy = dy(I); dx = dx(I); 52 | 53 | % Snap each gradient to an orientation 54 | [uu,vv] = pol2cart([0:pi/9:pi-.01],1); 55 | v = dy./(len+eps); u = dx./(len+eps); 56 | [dummy,I] = max(abs(u(:)*uu + v(:)*vv),[],2); 57 | 58 | % Spatially bin orientation channels 59 | ssiz = [imy imx]/sbin; 60 | feat = zeros(prod(ssiz), 9); 61 | for i = 1:9, 62 | tmp = reshape(len.*(I == i),imy-2,imx-2); 63 | tmp = padarray(tmp,[1 1]); 64 | feat(:,i) = sum(im2col(tmp,[sbin sbin],'distinct'))'; 65 | end 66 | 67 | % Compute features for all overlapping 2x2 windows 68 | ind = reshape(1:prod(ssiz),ssiz); 69 | ind = im2col(ind,[2 2])'; 70 | n = size(ind,1); 71 | feat = reshape(feat(ind,:),n,4*9); 72 | 73 | % Normalize and clip to .2 74 | nn = sqrt(sum(feat.^2,2)) + eps; 75 | feat = bsxfun(@times,feat,1./nn); 76 | feat = min(feat,.2); 77 | 78 | % Re-align features so that 4*9 values refer to same 8x8 spatial bin 79 | % Take projections along 4 normalization regions and 9 orientations 80 | feat = reshape(feat,[ssiz-1 4 9]); 81 | feat = cat(3,feat(2:end,2:end,1,:),feat(1:end-1,2:end,2,:),... 82 | feat(2:end,1:end-1,3,:),feat(1:end-1,1:end-1,4,:)); 83 | feat = cat(3,.5*reshape(sum(feat,3),[ssiz-2 9]),.2357*sum(feat,4)); 84 | -------------------------------------------------------------------------------- /detection/gt_filter_detections.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-03-24 2 | % Filter out the detections which overlap the ground 3 | % truth 4 | function [box,feat] = gt_filter_detections(box,feat,gt) 5 | % filter out the positives if any 6 | if(~gt_occluded(gt)) 7 | width = gt(3); 8 | height = gt(4); 9 | halfThePixels = .5*width*height; 10 | 11 | rectB = rectKtoB(box); 12 | posneg = rectint(rectB,gt) < halfThePixels; 13 | box = box(posneg,:); 14 | feat = feat(:,posneg); 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /detection/mex_resize.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mex.h" 5 | 6 | #ifndef bzero(s,n) 7 | #define bzero(s,n) memset ((s), 0, (n)) 8 | #endif 9 | #ifndef round(x) 10 | #define round(x) (x<0?ceil((x)-0.5):floor((x)+0.5)) 11 | #endif 12 | 13 | // struct used for caching interpolation values 14 | struct alphainfo { 15 | int si, di; 16 | double alpha; 17 | }; 18 | 19 | // copy src into dst using pre-computed interpolation values 20 | void alphacopy(double *src, double *dst, struct alphainfo *ofs, int n) { 21 | struct alphainfo *end = ofs + n; 22 | while (ofs != end) { 23 | dst[ofs->di] += ofs->alpha * src[ofs->si]; 24 | ofs++; 25 | } 26 | } 27 | 28 | // resize along each column 29 | // result is transposed, so we can apply it twice for a complete resize 30 | void resize1dtran(double *src, int sheight, double *dst, int dheight, 31 | int width, int chan) { 32 | double scale = (double)dheight/(double)sheight; 33 | double invscale = (double)sheight/(double)dheight; 34 | 35 | // we cache the interpolation values since they can be 36 | // shared among different columns 37 | int len = (int)ceil(dheight*invscale) + 2*dheight; 38 | alphainfo*ofs = static_cast(calloc(len,sizeof(alphainfo))); 39 | int k = 0; 40 | for (int dy = 0; dy < dheight; dy++) { 41 | double fsy1 = dy * invscale; 42 | double fsy2 = fsy1 + invscale; 43 | int sy1 = (int)ceil(fsy1); 44 | int sy2 = (int)floor(fsy2); 45 | 46 | if (sy1 - fsy1 > 1e-3) { 47 | assert(k < len); 48 | //assert(sy-1 >= 0); 49 | ofs[k].di = dy*width; 50 | ofs[k].si = sy1-1; 51 | ofs[k++].alpha = (sy1 - fsy1) * scale; 52 | } 53 | 54 | for (int sy = sy1; sy < sy2; sy++) { 55 | assert(k < len); 56 | assert(sy < sheight); 57 | ofs[k].di = dy*width; 58 | ofs[k].si = sy; 59 | ofs[k++].alpha = scale; 60 | } 61 | 62 | if (fsy2 - sy2 > 1e-3) { 63 | assert(k < len); 64 | assert(sy2 < sheight); 65 | ofs[k].di = dy*width; 66 | ofs[k].si = sy2; 67 | ofs[k++].alpha = (fsy2 - sy2) * scale; 68 | } 69 | } 70 | 71 | // resize each column of each color channel 72 | bzero(dst, chan*width*dheight*sizeof(double)); 73 | for (int c = 0; c < chan; c++) { 74 | for (int x = 0; x < width; x++) { 75 | double *s = src + c*width*sheight + x*sheight; 76 | double *d = dst + c*width*dheight + x; 77 | alphacopy(s, d, ofs, k); 78 | } 79 | } 80 | 81 | free(ofs); 82 | } 83 | 84 | // main function 85 | // takes a double color image and a scaling factor 86 | // returns resized image 87 | mxArray *resize(const mxArray *mxsrc, const mxArray *mxscale) { 88 | double *src = (double *)mxGetPr(mxsrc); 89 | const int *sdims = mxGetDimensions(mxsrc); 90 | if (mxGetNumberOfDimensions(mxsrc) != 3 || 91 | mxGetClassID(mxsrc) != mxDOUBLE_CLASS) 92 | mexErrMsgTxt("image doens't have 3 dimensions (x,y,rgb) or isn't double"); 93 | 94 | double scale = mxGetScalar(mxscale); 95 | if (scale > 1) 96 | mexErrMsgTxt("Invalid scaling factor"); 97 | 98 | int ddims[3]; 99 | ddims[0] = (int)round(sdims[0]*scale); 100 | ddims[1] = (int)round(sdims[1]*scale); 101 | ddims[2] = sdims[2]; 102 | mxArray *mxdst = mxCreateNumericArray(3, ddims, mxDOUBLE_CLASS, mxREAL); 103 | double *dst = (double *)mxGetPr(mxdst); 104 | 105 | double *tmp = (double *)mxCalloc(ddims[0]*sdims[1]*sdims[2], sizeof(double)); 106 | resize1dtran(src, sdims[0], tmp, ddims[0], sdims[1], sdims[2]); 107 | resize1dtran(tmp, sdims[1], dst, ddims[1], ddims[0], sdims[2]); 108 | mxFree(tmp); 109 | 110 | return mxdst; 111 | } 112 | 113 | // matlab entry point 114 | // dst = resize(src, scale) 115 | // image should be color with double values 116 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 117 | if (nrhs != 2) 118 | mexErrMsgTxt("Wrong number of inputs"); 119 | if (nlhs != 1) 120 | mexErrMsgTxt("Wrong number of outputs"); 121 | plhs[0] = resize(prhs[0], prhs[1]); 122 | } 123 | 124 | 125 | 126 | -------------------------------------------------------------------------------- /detection/nms.m: -------------------------------------------------------------------------------- 1 | % res = nms(boxes,overlap) 2 | % Greedily removes blobs that intersect by more than overlap 3 | function res = nms(boxes,overlap,scalex,scaley) 4 | boxes = shrink(boxes,scalex,scaley); 5 | 6 | res = nms_c(boxes,overlap); 7 | res = flipdim(sortrows(res,5),1); 8 | return; 9 | 10 | if isempty(boxes), 11 | res = []; 12 | else 13 | x1 = boxes(:,1); 14 | y1 = boxes(:,2); 15 | x2 = boxes(:,3); 16 | y2 = boxes(:,4); 17 | r = boxes(:,5); 18 | area = (x2-x1+1) .* (y2-y1+1); 19 | 20 | [vals,I] = sort(r); 21 | pick = []; 22 | while ~isempty(I), 23 | last = length(I); 24 | i = I(last); 25 | pick = [pick; i]; 26 | suppress = [last]; 27 | for pos = 1:last-1, 28 | j = I(pos); 29 | xx1 = max(x1(i), x1(j)); 30 | yy1 = max(y1(i), y1(j)); 31 | xx2 = min(x2(i), x2(j)); 32 | yy2 = min(y2(i), y2(j)); 33 | w = xx2-xx1+1; 34 | h = yy2-yy1+1; 35 | if w > 0 && h > 0 36 | % compute overlap 37 | o = w * h / area(j); 38 | % VOC criterion for overlap 39 | % o = w*h/ (area(i) + area(j) - w*h); 40 | if o > overlap 41 | suppress = [suppress; pos]; 42 | end 43 | end 44 | end 45 | I(suppress) = []; 46 | end 47 | res = boxes(pick,:); 48 | end 49 | 50 | function box = shrink(box,sx,sy) 51 | % box = shrink(box,scalex,scaley) 52 | 53 | x1 = box(:,1); 54 | y1 = box(:,2); 55 | x2 = box(:,3); 56 | y2 = box(:,4); 57 | w = x2-x1+1; 58 | h = y2-y1+1; 59 | 60 | x1 = x1 + (w-1)/2 - (w*sx-1)/2; 61 | y1 = y1 + (h-1)/2 - (h*sy-1)/2; 62 | x2 = x1 + w*sx - 1; 63 | y2 = y1 + h*sy - 1; 64 | 65 | box(:,1:4) = [x1 y1 x2 y2]; 66 | -------------------------------------------------------------------------------- /detection/nms_c.cc: -------------------------------------------------------------------------------- 1 | /** 2 | * JSS3 2012-5-28 3 | * Do greedy non-maximumal suppression 4 | **/ 5 | 6 | #include "mex.h" 7 | #include "math.h" 8 | #include 9 | #include 10 | #include "../mex/compat.h" 11 | 12 | static const mwSize boxWidth = 5; 13 | 14 | using std::numeric_limits; 15 | using std::vector; 16 | using std::min; 17 | using std::max; 18 | 19 | static int maxUnsuppressed( 20 | vector&suppressed,double*boxes, 21 | int nBoxes,vector&used) 22 | { 23 | double max = -numeric_limits::infinity(); 24 | int maxIdx = -1; 25 | for(int iter = 0; iter < nBoxes; iter++) 26 | { 27 | double max_rp = *(boxes + nBoxes*4 + iter); 28 | if(max_rp >= max && !suppressed[iter] && !used[iter]) 29 | { 30 | max = max_rp; 31 | maxIdx = iter; 32 | } 33 | } 34 | 35 | return maxIdx; 36 | } 37 | 38 | void trySuppressOther( 39 | double*boxes,mwSize nBoxes, int otherIdx, 40 | double max_x1, double max_y1, double max_x2, double max_y2, double overlap, 41 | vector&suppressed) 42 | { 43 | double other_x1 = *(boxes + nBoxes*0 + otherIdx); 44 | double other_y1 = *(boxes + nBoxes*1 + otherIdx); 45 | double other_x2 = *(boxes + nBoxes*2 + otherIdx); 46 | double other_y2 = *(boxes + nBoxes*3 + otherIdx); 47 | double other_rp = *(boxes + nBoxes*4 + otherIdx); 48 | double other_wd = other_x2 - other_x1 + 1; 49 | double other_hi = other_y2 - other_y1 + 1; 50 | double other_ar = other_wd*other_hi; 51 | 52 | // intersection 53 | double xx1 = max(other_x1,max_x1); 54 | double yy1 = max(other_y1,max_y1); 55 | double xx2 = min(other_x2,max_x2); 56 | double yy2 = min(other_y2,max_y2); 57 | double w = xx2-xx1+1; 58 | double h = yy2-yy1+1; 59 | 60 | // occlusion 61 | bool max_occ = isnan(max_x1); 62 | bool other_occ = isnan(other_x1); 63 | bool occCmpat = max_occ == other_occ; 64 | 65 | double o = w*h/other_ar; 66 | if(w > 0 && h > 0 && o > overlap && occCmpat) 67 | { 68 | // mexPrintf("nms_c.cc: suppressing %d\n",otherIdx); 69 | suppressed[otherIdx] = true; 70 | // mexPrintf("nms_c.cc: suppressed %d\n",otherIdx); 71 | } 72 | } 73 | 74 | /** 75 | * MEX main... 76 | * function res = nms(boxes,overlap) 77 | **/ 78 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 79 | // check arguments 80 | if (nrhs != 2) 81 | mexErrMsgTxt("Wrong number of inputs"); 82 | if (nlhs != 1) 83 | mexErrMsgTxt("Wrong number of outputs"); 84 | 85 | // get the input. 86 | double overlap = mxGetScalar(prhs[1]); 87 | double*boxes = mxGetPr(prhs[0]); 88 | mwSize nBoxes = mxGetM(prhs[0]); 89 | 90 | // do the computation. 91 | vector suppressed(nBoxes,false), used(nBoxes,false); 92 | int maxIter = 0; 93 | while(true) 94 | { 95 | maxIter++; 96 | // mexPrintf("nms_c.cc: maxIter = %d\n",maxIter); 97 | // find max... 98 | int maxIdx = maxUnsuppressed(suppressed,boxes,nBoxes,used); 99 | // mexPrintf("nms_c.cc: maxIdx = %d\n",maxIdx); 100 | if(maxIdx < 0) 101 | { 102 | // mexPrintf("nms_c.cc: Breaking out of calcs\n"); 103 | break; 104 | } 105 | used[maxIdx] = true; 106 | // mexPrintf("nms_c.cc: starting next iteration!\n"); 107 | 108 | // MATLAB data is columknwise, so incrementing by one moves us 109 | // down the current column (from row to row). 110 | double max_x1 = *(boxes + nBoxes*0 + maxIdx); 111 | double max_y1 = *(boxes + nBoxes*1 + maxIdx); 112 | double max_x2 = *(boxes + nBoxes*2 + maxIdx); 113 | double max_y2 = *(boxes + nBoxes*3 + maxIdx); 114 | double max_rp = *(boxes + nBoxes*4 + maxIdx); 115 | double max_wd = max_x2 - max_x1 + 1; 116 | double max_hi = max_y2 - max_y1 + 1; 117 | double max_ar = max_wd*max_hi; 118 | 119 | for(int otherIdx = 0; otherIdx < nBoxes; otherIdx++) 120 | { 121 | trySuppressOther( 122 | boxes,nBoxes, otherIdx, 123 | max_x1, max_y1, max_x2, max_y2, overlap, 124 | suppressed); 125 | } 126 | } 127 | // mexPrintf("nms_c.cc: calculations complete\n"); 128 | 129 | // produce the output. 130 | // count the number of boxes which are used after NMS 131 | int outCt = 0; 132 | for(int iter = 0; iter < used.size(); iter++) 133 | if(used[iter]) 134 | outCt++; 135 | 136 | // mexPrintf("boxCt = %d\noutCt = %d\n",nBoxes,outCt); 137 | plhs[0] = mxCreateDoubleMatrix(outCt,boxWidth,mxREAL); 138 | double* out = mxGetPr(plhs[0]); 139 | for(int iter = 0, outIter = 0; iter < used.size(); iter++) 140 | if(used[iter]) 141 | { 142 | *(out + outCt*0 + outIter) = *(boxes + nBoxes*0 + iter); 143 | *(out + outCt*1 + outIter) = *(boxes + nBoxes*1 + iter); 144 | *(out + outCt*2 + outIter) = *(boxes + nBoxes*2 + iter); 145 | *(out + outCt*3 + outIter) = *(boxes + nBoxes*3 + iter); 146 | *(out + outCt*4 + outIter) = *(boxes + nBoxes*4 + iter); 147 | outIter++; 148 | } 149 | } 150 | 151 | -------------------------------------------------------------------------------- /detection/reduce.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "mex.h" 5 | 6 | #ifndef bzero(s,n) 7 | #define bzero(s,n) memset ((s), 0, (n)) 8 | #endif 9 | #ifndef round(x) 10 | #define round(x) (x<0?ceil((x)-0.5):floor((x)+0.5)) 11 | #endif 12 | 13 | // reduce(im) resizes im to half its size, using a 5-tap binomial filter for anti-aliasing 14 | // (see Burt & Adelson's Laplacian Pyramid paper) 15 | 16 | // reduce each column 17 | // result is transposed, so we can apply it twice for a complete reduction 18 | void reduce1dtran(double *src, int sheight, double *dst, int dheight, 19 | int width, int chan) { 20 | // resize each column of each color channel 21 | bzero(dst, chan*width*dheight*sizeof(double)); 22 | int y; 23 | double *s, *d; 24 | 25 | for (int c = 0; c < chan; c++) { 26 | for (int x = 0; x < width; x++) { 27 | s = src + c*width*sheight + x*sheight; 28 | d = dst + c*dheight*width + x; 29 | 30 | // First row 31 | *d = s[0]*.6875 + s[1]*.2500 + s[2]*.0625; 32 | 33 | for (y = 1; y < dheight-2; y++) { 34 | s += 2; 35 | d += width; 36 | *d = s[-2]*0.0625 + s[-1]*.25 + s[0]*.375 + s[1]*.25 + s[2]*.0625; 37 | } 38 | 39 | // Last two rows 40 | s += 2; 41 | d += width; 42 | if (dheight*2 <= sheight) { 43 | *d = s[-2]*0.0625 + s[-1]*.25 + s[0]*.375 + s[1]*.25 + s[2]*.0625; 44 | } else { 45 | *d = s[1]*.3125 + s[0]*.3750 + s[-1]*.2500 + s[-2]*.0625; 46 | } 47 | s += 2; 48 | d += width; 49 | *d = s[0]*.6875 + s[-1]*.2500 + s[-2]*.0625; 50 | } 51 | } 52 | } 53 | 54 | // main function 55 | // takes a double color image and a scaling factor 56 | // returns resized image 57 | mxArray *reduce(const mxArray *mxsrc) { 58 | double *src = (double *)mxGetPr(mxsrc); 59 | 60 | const int *sdims = mxGetDimensions(mxsrc); 61 | if (mxGetNumberOfDimensions(mxsrc) != 3 || 62 | mxGetClassID(mxsrc) != mxDOUBLE_CLASS) 63 | mexErrMsgTxt("Invalid input"); 64 | 65 | int ddims[3]; 66 | ddims[0] = (int)round(sdims[0]*.5); 67 | ddims[1] = (int)round(sdims[1]*.5); 68 | ddims[2] = sdims[2]; 69 | 70 | if (sdims[0] < 5|| sdims[1] < 5) 71 | mexErrMsgTxt("Minimum size of image is 5x5"); 72 | 73 | mxArray *mxdst = mxCreateNumericArray(3, ddims, mxDOUBLE_CLASS, mxREAL); 74 | double *dst = (double *)mxGetPr(mxdst); 75 | 76 | double *tmp = (double *)mxCalloc(ddims[0]*sdims[1]*sdims[2], sizeof(double)); 77 | reduce1dtran(src, sdims[0], tmp, ddims[0], sdims[1], sdims[2]); 78 | reduce1dtran(tmp, sdims[1], dst, ddims[1], ddims[0], sdims[2]); 79 | mxFree(tmp); 80 | 81 | return mxdst; 82 | } 83 | 84 | // matlab entry point 85 | // dst = resize(src, scale) 86 | // image should be color with double values 87 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { 88 | if (nrhs != 1) 89 | mexErrMsgTxt("Wrong number of inputs"); 90 | if (nlhs != 1) 91 | mexErrMsgTxt("Wrong number of outputs"); 92 | plhs[0] = reduce(prhs[0]); 93 | } 94 | 95 | /********** 96 | d = repmat([1:6]',[1 5 3]); 97 | a = reduce(d); 98 | *********/ 99 | 100 | -------------------------------------------------------------------------------- /detection/scoreBox.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-20 2 | % get the response for a given box. 3 | function score = scoreBox(model,im,k_rect) 4 | %fprintf('+scoreBox\n'); 5 | imsz = rect_size(rect_image(im)); 6 | bbsz = rect_size(k_rect); 7 | sz = rect_size(k_rect); 8 | if any(bbsz > 2.*imsz) 9 | score = -1; % bad bb because it is to large. 10 | elseif gt_occluded(k_rect) || sz(1) < 2 || sz(2) < 2 ... 11 | || rect_area(k_rect) > rect_area(rect_image(im)) 12 | score = -1; 13 | else 14 | %fprintf('scoreBox: getting SVM feature\n'); 15 | %keyboard; 16 | feat = feature_get_for_svm(model,im,rectKtoB(k_rect)); 17 | %fprintf('scoreBox: got SVM feature\n'); 18 | featSz = numel(feat)-1; 19 | score = feat(1:featSz)'*model.w(1:featSz)' + model.b*model.sb; 20 | end 21 | %fprintf('-scoreBox\n'); 22 | end 23 | -------------------------------------------------------------------------------- /evalOnVids.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash -x 2 | 3 | FUNC=$1 4 | INIT=$2 5 | 6 | echo "starting evaluation..." 7 | VIDS=$(ls ~/workspace/data) 8 | SUITE='coke11 david motocross tiger2 girl panda pedestrian1 sylv tiger1 volkswagen faceocc faceocc2' 9 | #SUITE='panda' 10 | MATLAB=matlab 11 | SERIAL='0' 12 | 13 | # configure our X server 14 | # Xnest still crashes randomly :-( 15 | #nohup Xnest :1 -geometry 1280x1024 & 16 | #export DISPLAY=:1 17 | #wmaker & 18 | 19 | # compile shared components 20 | # 21 | # clear existing jobs 22 | # $MATLAB -nodesktop -r "matlabpool close force; " 23 | # compile the shared components. 24 | # -nodisplay? 25 | $MATLAB -nodesktop -r "addpath(genpath('.'),'-END'); cluster_ctl('killall'); compile; exit;" 26 | 27 | # test the vids 28 | #for VID in 'volkswagen' 29 | #for VID in $VIDS 30 | for VID in $SUITE 31 | do 32 | ID="$FUNC-$VID-$(date +%Y%m%d)" 33 | 34 | if [ $SERIAL == 1 ] 35 | then 36 | SETUP="$INIT addpath(genpath('.')); cluster_ctl('on'); vidName='$VID';" 37 | else 38 | SETUP="$INIT addpath(genpath('.')); vidName='$VID';" 39 | fi 40 | RUN="track = $FUNC(vidName);" 41 | FINISH="save([cfg('tmp_dir') 'track_$ID.mat'],'vidName','track'); " 42 | F1FILE="[cfg('tmp_dir') 'f1=' num2str(f1) '_$ID.mat']" 43 | CMP_F1="f1 = score_track_file(vidName,track); save($F1FILE,'f1');" 44 | PROG="$SETUP $RUN $FINISH $CMP_F1 cluster_ctl('off'); exit;" 45 | echo $PROG 46 | #$MATLAB -nosplash -nodesktop -r '$PROG' 47 | screen -d -m -S $FUNC$VID nice -n 10 $MATLAB -nodisplay -nosplash -nodesktop -r "$PROG" 48 | sleep 5 49 | #screen -d -m -S $FUNC$VID $MATLAB -nodesktop -r "$FUNC('$VID');" 50 | done 51 | 52 | # restore the terimanl... 53 | reset 54 | -------------------------------------------------------------------------------- /hashMat_mat.m: -------------------------------------------------------------------------------- 1 | % if you can't compile hashMat.cc 2 | % you can just use this. The caching feature 3 | % won't work properly but it's mainly usefull for 4 | % development anyway. 5 | function h = hashMat_mat(m) 6 | chars = ['a':'z' 'A':'Z' '0':'9']; 7 | idxs = randi(numel(chars),[1 32]); 8 | h = chars(idxs); 9 | end 10 | 11 | -------------------------------------------------------------------------------- /learning/compute_tsvm_deltas.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.8.7 2 | % Simplified interface to learn_tsvm_score. 3 | function deltas = compute_tsvm_deltas(vidName,model,k_track) 4 | evalFrames = zeros(size(k_track(:,1))); 5 | [top_detections,NStates] = getDetsEst(vidName,model, ... 6 | k_track); 7 | deltas = learn_tsvm_score(evalFrames,NStates,top_detections,... 8 | vidName,model); 9 | end 10 | -------------------------------------------------------------------------------- /learning/getDetsEst.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.3 2 | function [top_detections,NStates] = getDetsEst(vidName,model, ... 3 | k_track) 4 | NStates = 1; 5 | num_top_dets = min(vidLen(vidName),size(k_track,1)); 6 | top_detections = cell(num_top_dets,1); 7 | for detIter = 1:numel(top_detections) 8 | top_detections{detIter} = k_track(detIter,:); 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /learning/learn_tsvm_score.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.31 2 | % Computes the true TSVM delta for a set of lambda. 3 | function scores = learn_tsvm_score(lambda,NStates,top_detections,... 4 | vidName,model) 5 | % try to find the result in our cache 6 | wHash = hashMat(model.w); 7 | lHash = hashMat(lambda); 8 | vidName; 9 | filename = [cfg('tmp_dir') 'learn_tsvm_score' ... 10 | vidName wHash lHash '.mat']; 11 | if exist(filename,'file') 12 | load(filename,'scores'); 13 | return; 14 | end 15 | 16 | % what is the original score? 17 | ub0 = model.qp.ub; 18 | lb0 = model.qp.lb; 19 | 20 | % score matrix Frames by Detections 21 | scoresComp = inf(numel(lambda),NStates); 22 | 23 | % use the SVM objective function to, in parallel, fill the 24 | % matrix. 25 | cluster_ctl('on'); 26 | spmd 27 | %setpath(); 28 | progFrames = labindex:numlabs:(numel(top_detections)); 29 | for frameIter = progFrames 30 | fprintf('learn_tsvm: computing scores for frame %d of %d\n',frameIter,numel(top_detections)); 31 | for detectionIdx = 1:NStates 32 | cur_det = ... 33 | top_detections{frameIter}... 34 | (detectionIdx,:); 35 | 36 | if lambda(frameIter) 37 | continue; 38 | end 39 | 40 | scoresComp(frameIter,detectionIdx) = ... 41 | cost_lcl_tsvm(model,vidName,frameIter-1,cur_det); 42 | end 43 | end 44 | end 45 | fprintf('learn_tsvm_score.m: DONE\n'); 46 | 47 | % collect the scores composite into a scores matrix... 48 | scores = inf(numel(lambda),NStates); 49 | for iter = 1:numel(scoresComp) 50 | subScores = scoresComp{iter}; 51 | scores(subScores ~= inf) = subScores(subScores ~= inf); 52 | end 53 | cluster_ctl('off'); 54 | 55 | % save to the cache 56 | save(filename,'scores'); 57 | end 58 | -------------------------------------------------------------------------------- /mex/compat.h: -------------------------------------------------------------------------------- 1 | // file which tries to add compatibility with other operating 2 | // systems (aside from Linux) 3 | 4 | #ifdef _MSC_VER 5 | // code for windows 6 | typedef __int32 int32_t; 7 | typedef unsigned __int32 uint32_t; 8 | #define isnan _isnan 9 | #else 10 | // code for Linux 11 | #include 12 | #endif 13 | -------------------------------------------------------------------------------- /model/Model.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.30 2 | % I'm finally making the big change; converting the model to a 3 | % class. 4 | classdef Model 5 | properties(SetAccess = private) 6 | gt_width; 7 | gt_height; 8 | aspect; 9 | Jpos; 10 | nx; 11 | ny; 12 | nf; 13 | featType; 14 | w; 15 | b; 16 | sb; 17 | scalex; 18 | scaley; 19 | interval; 20 | sbin; 21 | sym; 22 | thresh; 23 | qp; 24 | end 25 | 26 | methods 27 | % use of this method is strongly discouraged 28 | % as it breaks encapsulation. 29 | function qp = qp_get(obj) 30 | qp = obj.qp; 31 | end 32 | 33 | % use of this method is strongly discouraged 34 | % as it breaks encapsulation. 35 | function obj = qp_set(obj,qp) 36 | obj.qp = qp; 37 | obj = updateModel(obj,obj.Jpos); 38 | end 39 | 40 | function aspect = getAspect(obj) 41 | aspect = obj.aspect; 42 | end 43 | 44 | function scalex = getScaleX(obj) 45 | scalex = obj.scalex; 46 | end 47 | 48 | function scaley = getScaleY(obj) 49 | scaley = obj.scaley; 50 | end 51 | 52 | function Jpos = getJpos(obj) 53 | Jpos = obj.Jpos; 54 | end 55 | 56 | function C = getC(obj) 57 | C = obj.qp.getC(); 58 | end 59 | 60 | function qp = getQP(obj) 61 | qp = obj.qp; 62 | end 63 | 64 | function model = setThresh(model,thresh) 65 | model.thresh = thresh; 66 | end 67 | 68 | function d = detector(obj) 69 | d = Detector(obj.w,obj.thresh,obj.sbin,obj.interval,... 70 | obj.b,obj.sb,obj.scalex,obj.scaley,obj.Jpos,... 71 | obj.nx,obj.ny); 72 | end 73 | 74 | function top_detections = detect_all(obj,frames,vidName, ... 75 | NDetStates) 76 | d = obj.detector(); 77 | top_detections = d.detect_all(frames,vidName,NDetStates); 78 | end 79 | 80 | function [box,feat] = detect(obj,im,model,maxdet) 81 | [box,feat] = detect(im,model,maxdet); 82 | end 83 | 84 | function h = hash(obj) 85 | h = hashMat(obj.w); 86 | end 87 | 88 | % score some boxes! Oh Yea! 89 | function score = score_box(obj,im,k_rect) 90 | boxCt = size(k_rect,1); 91 | score = zeros(boxCt,1); 92 | for iter = 1:boxCt 93 | score(iter,1) = scoreBox(obj,im,k_rect(iter,:)); 94 | end 95 | end 96 | 97 | % support two different construtction methods. 98 | function obj = Model(ctor,varargin) 99 | if strcmp(ctor,'init') 100 | obj = obj.init(varargin{:}); 101 | elseif strcmp(ctor,'gen') 102 | obj = obj.generate(varargin{:}); 103 | elseif strcmp(ctor,'copy') 104 | obj = obj.copy(varargin{:}); 105 | else 106 | error('Model::Model invalid constructor'); 107 | end 108 | end 109 | 110 | function obj = copy(obj,other) 111 | props = properties(other); 112 | for iter = 1:length(props) 113 | obj.(props{iter}) = other.(props{iter}); 114 | end 115 | end 116 | 117 | function model = init(model,sbins,nx,ny,Jpos,~,gt_width,gt_height) 118 | featType = 'hog'; 119 | 120 | % model = initmodel(bigbox,smallbox,sbin) 121 | % Initialize model given size of bounding boxes in positive images 122 | model.gt_width = gt_width; 123 | model.gt_height = gt_height; 124 | model.aspect = gt_width/gt_height; 125 | 126 | model.Jpos = Jpos; 127 | 128 | model.nx = nx; 129 | model.ny = ny; 130 | model.nf = length(features(zeros([3 3 3]),1,feat_code(featType))); 131 | model.featType = featType; 132 | 133 | % Main parameters; linearly-scored template and bias 134 | model.w = zeros([model.ny model.nx model.nf]) 135 | model.b = 0; 136 | 137 | % Encode scale factor for bias, width and height 138 | model.sb = 10; 139 | model.scalex = gt_width/(nx*sbins); % needed because hog templates cannot exactly 140 | model.scaley = gt_height/(ny*sbins); % have same aspect ratio as image templates. 141 | 142 | % Default number of scales in a 2X octave for image pyramid 143 | model.interval = 4; 144 | 145 | % Size of spatial bin 146 | model.sbin = sbins; 147 | 148 | % Enforce symmetry 149 | model.sym = true; 150 | 151 | % default threshold... 152 | model.thresh = -1; 153 | end 154 | 155 | function model = generate(model,vidName,~,AREA, trainOn) 156 | if nargin < 4 || isempty(AREA) 157 | AREA = 36; 158 | end 159 | featType = 'hog'; 160 | if nargin < 5 161 | trainOn = [0]; 162 | end 163 | 164 | C = cfg('C'); 165 | Jpos = 1; 166 | b_gts = gt_load(vidName); 167 | b_gt1 = b_gts(1,:); 168 | gt_width = b_gt1(3) 169 | gt_height = b_gt1(4) 170 | gt_area = gt_width*gt_height; 171 | % compute 172 | nx = round(sqrt(AREA)*sqrt(gt_width)/sqrt(gt_height)) 173 | ny = round(sqrt(AREA)*sqrt(gt_height)/sqrt(gt_width)) 174 | na = nx*ny; 175 | sbins = round(sqrt(gt_area/na)); 176 | 177 | model = model.init(sbins,nx,ny,Jpos,featType,gt_width,gt_height); 178 | model.qp = qp_init(model,C); 179 | 180 | % set the variance filter 181 | imM = get_frame(vidName,0); 182 | T0 = imcropr(imM,rectBtoK(b_gts(1,:))); 183 | 184 | model_cache_file = [cfg('tmp_dir') 'model_' ... 185 | featType num2str(AREA) hashMat(trainOn) ... 186 | vidName '.mat']; 187 | if exist(model_cache_file,'file') 188 | load(model_cache_file,'model'); 189 | else 190 | for trainIter = 1:numel(trainOn) 191 | trainFrame = trainOn(trainIter); 192 | imM = get_frame(vidName,trainFrame); 193 | 194 | % train on frame 195 | for tIter = 1:5 196 | fprintf('track_dp: training iteration %d of %d\n',tIter,5); 197 | model = model.train_one(vidName,imM,b_gts(trainFrame+1,:)); 198 | showModel(model.w); 199 | drawnow; 200 | end 201 | end 202 | save(model_cache_file,'model'); 203 | end 204 | end 205 | 206 | % Train the SVM on one frame. 207 | function [model] = train_one(model,vidName,im,B_bb,p,n) 208 | % default args 209 | if nargin < 5 210 | p = 1; 211 | end 212 | if nargin < 6 213 | n = 1; 214 | end 215 | qp_out = @qp_write; 216 | update_model = 1; 217 | featSrc = @featpyramid; 218 | weight = 1; 219 | maxneg = inf; 220 | Jpos = model.Jpos; 221 | 222 | % dissallow training rectangles larger than the image. 223 | imsz = rect_size(rect_image(im)); 224 | dtsz = rect_size(rectBtoK(B_bb)); 225 | if any(dtsz > imsz) 226 | dtsz = dtsz 227 | assert(~any(dtsz > imsz)); 228 | end 229 | 230 | featpyr = []; 231 | scales = []; 232 | if n >= 1 233 | [featpyr,scales] = featSrc(im,model.sbin,model.interval); 234 | end 235 | 236 | % add the positive examples... 237 | [model] = train_one_pos(model,B_bb,im,update_model,p,qp_out,weight); 238 | 239 | % now add the negative examples... 240 | model.thresh = -weight; 241 | %model.minVar = -inf; 242 | for i = 1:n 243 | [model] = train_one_neg... 244 | (model,im,featpyr,scales,B_bb,qp_out,update_model,weight,maxneg); 245 | end 246 | %showModel(model.w,1); 247 | %keyboard; 248 | end 249 | 250 | function [model] = train_one_neg... 251 | (model,im,featpyr,scales,B_bb,qp_out,update_model,weight,maxneg) 252 | model.qp = qp_prune(model.qp); 253 | maxnum = model.qp.nmax - model.qp.n; 254 | detor = model.detector(); 255 | feat = detor.training_neg(B_bb,im,weight,featpyr,scales,min(maxnum,maxneg)); 256 | 257 | % make sure we don't overfill the cache... 258 | if size(feat,2)+model.qp.n >= model.qp.nmax 259 | model.qp = qp_prune(model.qp); 260 | end 261 | assert(size(feat,2)+model.qp.n <= model.qp.nmax); 262 | 263 | % model.qp = qp_out(model.qp,-feat,1,1+box(:,end)); 264 | model.qp = qp_out(model.qp,weight.*-feat,weight.*1,1,0); 265 | model.qp = qp_opt(model.qp); 266 | if update_model 267 | model = updateModel(model,model.Jpos); 268 | end 269 | end 270 | 271 | function [model] = train_one_pos(model,B_bb,im,update_model,p,qp_out,weight) 272 | Jpos = model.Jpos; 273 | 274 | % add the positive examples 275 | for iter = 1:p 276 | % if we don't have enough room for the sample try to prune non-svs 277 | if model.qp.n + 1 >= model.qp.nmax 278 | model.qp = qp_prune(model.qp); 279 | end 280 | % if pruning doesn't work, quit. 281 | if model.qp.n + 1 >= model.qp.nmax 282 | break; 283 | end 284 | 285 | feat = model.detector().training_pos(B_bb,im,weight); 286 | if isempty(feat) 287 | continue; 288 | end 289 | model.qp = qp_out(model.qp,weight.*Jpos*feat,weight.*Jpos,Jpos,1); 290 | model.qp = qp_opt(model.qp); 291 | end 292 | 293 | % update model and show template 294 | if update_model 295 | model = updateModel(model,Jpos); 296 | end 297 | end 298 | 299 | % Update model with current QP solution 300 | function model = updateModel(model,Jpos) 301 | model.w = reshape(model.qp.w(1:end-1),size(model.w)); 302 | model.b = model.qp.w(end); 303 | 304 | model.interval = 14; 305 | end 306 | 307 | function ot = occ_thresh(obj) 308 | ot = -1; 309 | return; 310 | 311 | posProb = .95; 312 | 313 | % Store model threshold that allows us to find 95% of training 314 | % positives 315 | qp = obj.qp; 316 | r = qp.w'*qp.x(:,find(qp.pos)); 317 | r = sort(r); 318 | idx = round(clamp(1,length(r)*(1-posProb),numel(r))); 319 | ot = double(r(idx)/obj.Jpos); 320 | end 321 | 322 | function c = cost(obj) 323 | c = obj.qp.lb; 324 | end 325 | 326 | function obj = train_all(obj,vidName,k_track,lambda) 327 | trainer = SVM_trainer; 328 | obj = trainer.train_all(vidName,k_track,lambda,[],obj); 329 | end 330 | end 331 | end 332 | -------------------------------------------------------------------------------- /model/SVM_trainer.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.25 Class to train an SVM and produce a model. 2 | classdef SVM_trainer 3 | properties(SetAccess = private) 4 | % configuration (number of positive and negative passes to 5 | % do with each frame). 6 | p = 1; 7 | n = 1; 8 | 9 | % State 10 | passes; 11 | PASS_CT; 12 | frameCt; 13 | weights; 14 | track; 15 | vidName; 16 | 17 | % to cumbersome to pass around 18 | new_poss; 19 | new_poss_weights; 20 | new_negs; 21 | new_negs_weights; 22 | end 23 | 24 | methods 25 | % How many positive passes to do for each frame? 26 | function obj = setP(obj,p) 27 | obj.p = p; 28 | end 29 | 30 | % How many negative passes to do for each frame? 31 | function obj = setN(obj,n) 32 | obj.n = n; 33 | end 34 | 35 | % CTOR 36 | function obj = SVM_trainer() 37 | end 38 | 39 | function model = train_all(obj,vidName,track,weights,passes,model) 40 | memo = [cfg('tmp_dir') 'train_all_' ... 41 | hashMat(track) ... 42 | hashMat(weights) '.mat']; 43 | if exist(memo,'file') 44 | load(memo,'model') 45 | return; 46 | end 47 | 48 | if nargin < 6 || isempty(model) 49 | model = Model('gen',vidName,[],[],[]); 50 | end 51 | 52 | if sum(weights > 0) == 1 53 | % we are only training on a single frame, don't 54 | % make things to complicated. 55 | frameIter = find(weights)-1; 56 | im = get_frame(vidName,frameIter); 57 | b_bb = rectKtoB(track(frameIter+1,:)); 58 | model = model.train_one(vidName,im,b_bb,5,5); 59 | else 60 | % handle default arguments 61 | if nargin < 5 || isempty(passes) 62 | passes = obj.default_passes(track,weights); 63 | end 64 | obj.PASS_CT = numel(passes); 65 | obj.passes = passes; 66 | 67 | % assert valid arguments 68 | assert(~all(weights <= 0)); 69 | 70 | % store arguments on object 71 | obj.track = track; 72 | obj.vidName = vidName; 73 | obj.weights = weights; 74 | 75 | % ensure we don't try to train without any positive SVs. 76 | if weights(1) > .5 77 | model = model.train_one(vidName,... 78 | get_frame(vidName,0),... 79 | rectKtoB(track(1,:)),... 80 | 1,1); 81 | end 82 | 83 | % update for frame 2 to N (transduce) 84 | obj.frameCt = size(track,1); 85 | % start with an empty model... 86 | for pass = 1:obj.PASS_CT 87 | model = obj.one_training_pass(pass,model); 88 | end 89 | end 90 | 91 | save(memo,'model'); 92 | end 93 | 94 | % if the user doesn't tell us how our pass structure 95 | % should be, then generate a sensible default. 96 | function passes = default_passes(obj,k_track,weights) 97 | trainingSetSize = sum(weights > 0); 98 | base = 2; 99 | iter = 1; 100 | 101 | passes = {}; 102 | while 2.^iter < trainingSetSize 103 | passes{end+1} = 2.^iter; 104 | iter = iter+1; 105 | end 106 | 107 | FULL_CT = 2; 108 | % final passes with the full set. 109 | for iter = 1:FULL_CT 110 | passes{end+1} = trainingSetSize; 111 | end 112 | end 113 | 114 | % default sizes for a fixed number of passes. 115 | function passes = default_passes_fixed_ct(obj,k_track,weights) 116 | DEFAULT_PASS_CT = 5; 117 | passes = {}; 118 | base = nthroot(size(k_track,1),DEFAULT_PASS_CT); 119 | % trainingSetSize = size(k_track,1); 120 | trainingSetSize = sum(weights > 0); 121 | 122 | % build the default pass sequence. 123 | for pass = 1:DEFAULT_PASS_CT 124 | if pass == DEFAULT_PASS_CT 125 | passSize = trainingSetSize; 126 | else 127 | passSize = clamp(1,round(base.^pass),trainingSetSize); 128 | end 129 | 130 | passes{end+1} = passSize; 131 | end 132 | end 133 | 134 | function model = one_training_pass(obj,pass,model) 135 | % compute the new feats for each frame 136 | bj.new_negs = {}; 137 | obj.new_negs_weights = {}; 138 | obj.new_poss = {}; 139 | obj.new_poss_weights = {}; 140 | passSize = obj.passes{pass}; 141 | if passSize >= 32 142 | % use a local cluster because of network overhead. 143 | cluster_ctl('on','local'); 144 | end 145 | frames = find(obj.weights > 0) - 1; 146 | rand_frame_order = frames(randi([1,numel(frames)],size(obj.track,1),1)); 147 | maxneg = round((model.qp.nmax - model.qp.n)./passSize); 148 | detector = model.detector(); 149 | parfor pFrameIter = 1:passSize 150 | [np,npw,nn,nnw] = obj.svs_for_pass... 151 | (detector,pFrameIter,rand_frame_order,maxneg,passSize,frames,pass); 152 | new_poss{pFrameIter} = np; 153 | new_poss_weights{pFrameIter} = npw; 154 | new_negs{pFrameIter} = nn; 155 | new_negs_weights{pFrameIter} = nnw; 156 | end 157 | % copy into the object 158 | obj.new_poss = new_poss; 159 | obj.new_poss_weights = new_poss_weights; 160 | obj.new_negs = new_negs; 161 | obj.new_negs_weights = new_negs_weights; 162 | cluster_ctl('off'); 163 | 164 | % train with the new feats 165 | %keyboard; 166 | model = obj.train_all_commit(model); 167 | %keyboard; 168 | end 169 | 170 | function [np,npw,nn,nnw] = svs_for_pass... 171 | (obj,detector,pFrameIter,rand_frame_order,maxneg,passSize,frames,pass) 172 | if passSize == numel(frames) 173 | frameIter = frames(pFrameIter); 174 | else 175 | frameIter = rand_frame_order(pFrameIter); 176 | end 177 | fprintf('train_all pass %d: visiting %d of %d\n',... 178 | pass,frameIter,size(obj.track,1)); 179 | curPos = obj.track(frameIter+1,:); 180 | b_pos = rectKtoB(curPos); 181 | 182 | % find margin violators. 183 | weight = obj.weights(frameIter+1); 184 | if weight > 0 185 | imN = get_frame(obj.vidName,frameIter); 186 | imsz = rect_size(rect_image(imN)); 187 | dtsz = rect_size(curPos); 188 | end 189 | 190 | new_pos = []; 191 | new_neg = []; 192 | if weight > 0 && all(dtsz < imsz) && gt_valid(curPos); 193 | [featPyr,scale] = featpyramid(imN, detector.sbin, detector.interval); 194 | if obj.p > 0 195 | new_pos = detector.training_pos(b_pos,imN,weight); 196 | np = weight.*new_pos.*detector.getJpos(); 197 | npw = double(repmat(weight.*detector.getJpos(),[size(new_pos,2),1])); 198 | end 199 | if obj.n > 0 200 | new_neg = detector.training_neg(b_pos,imN,weight,featPyr,scale,maxneg); 201 | nn = weight.*-new_neg; 202 | nnw = double(repmat(weight,[size(new_neg,2),1])); 203 | end 204 | %showBox(imN,curPos); 205 | end 206 | 207 | xlen = numel(detector.getW())+1; 208 | if isempty(new_pos) 209 | np = zeros(xlen,0); 210 | npw = double([]); 211 | end 212 | if isempty(new_neg) 213 | nn = single(zeros(xlen,0)); 214 | nnw = double([]); 215 | end 216 | 217 | % the first frame must always contain one positive 218 | % support vector. 219 | assert(~(frameIter == 0 && isempty(np) && obj.p > 0)); 220 | end 221 | 222 | % add all the Support Vectors we found into the cache and optimize. 223 | function model = train_all_commit... 224 | (obj,model) 225 | function c = c2d(c) 226 | c = cellfun(@(x) double(x), c, 'UniformOutput', false); 227 | end 228 | 229 | %keyboard; 230 | new_neg = cell2mat(c2d(obj.new_negs)); 231 | new_pos = cell2mat(c2d(obj.new_poss)); 232 | neg_weight = cell2mat(obj.new_negs_weights'); 233 | pos_weight = cell2mat(obj.new_poss_weights'); 234 | fprintf('train_all: writing %d new examples\n',size(new_neg,2)+size(new_pos,2)); 235 | qp = model.qp_get(); 236 | % pos 237 | qp = qp_write(qp,new_pos,pos_weight,model.Jpos,1); 238 | % neg 239 | qp = qp_write(qp,new_neg,neg_weight,1,0); 240 | % opt 241 | qp = qp_opt(qp); 242 | qp = qp_prune(qp); 243 | % update 244 | model = model.qp_set(qp); 245 | model = model.updateModel(model.Jpos); 246 | fprintf('train_all_commit: model updated\n'); 247 | 248 | % Show the updated model... 249 | showModel(model.w); drawnow; 250 | end 251 | end 252 | end 253 | 254 | -------------------------------------------------------------------------------- /model/genModel.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.5.29 2 | % high level, give a valid blank model for the video. 3 | function [model,Jpos,C] = genModel(varargin) 4 | model = Model('gen',varargin{:}); 5 | Jpos = model.getJpos(); 6 | C = model.getQP().getC(); 7 | end 8 | 9 | % with AREA = 80 10 | % 11 | % C = .01 gives .6549 on coke11 12 | % C = .05 gives .7080 on coke11 13 | % C = .5 gives .72 14 | 15 | % with AREA = 40 16 | % C = .5 17 | -------------------------------------------------------------------------------- /qp/QP.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.26 2 | % This is a class defining a Quadratic Program 3 | % OOP interface to the methods in this directory 4 | % (Primal) min_{w,e} .5*||w||^2 + C*sum_i e_i 5 | % s.t. w*x_i >= b_i - e_i 6 | % e_i >= 0 7 | % 8 | % (Dual) max_{a} -.5*sum_ij a_i(x_ix_j)a_j + sum_i b_i*a_i 9 | % s.t. 0 <= a_i <= C 10 | classdef QP 11 | properties(SetAccess = protected) 12 | % Define global QP problem using 1GB of memory 13 | % 2e7 = 2GB 14 | % 5e6 = 500 MB 15 | QP_SIZE; 16 | nmax; 17 | x; 18 | b; 19 | d; 20 | a; 21 | sv; 22 | % JSS3 2012-5-26, which examples are positive? 23 | pos; 24 | w; 25 | n; 26 | ub; 27 | lb; 28 | l; 29 | C; 30 | svfix; 31 | lb_old; 32 | obj; 33 | 34 | % prevent addition of duplicate features using a map of md5 35 | % hashes 36 | containment; 37 | end 38 | 39 | methods 40 | % getter for n 41 | function n = get_n(obj) 42 | n = obj.n; 43 | end 44 | 45 | % getter for nmax 46 | function nmax = get_nmax(obj) 47 | nmax = obj.nmax; 48 | end 49 | 50 | function C = getC(obj) 51 | C = obj.C; 52 | end 53 | 54 | % CTOR 55 | function obj = QP(model,C) 56 | if nargin == 1 57 | % Copy CTOR 58 | prps = properties(model); 59 | for iter = 1:length(prps) 60 | obj.(prps{iter}) = model.(prps{iter}); 61 | end 62 | elseif nargin == 2 63 | obj = obj.init(model,C); 64 | end 65 | end 66 | 67 | function obj = init(obj,model,C) 68 | % Define model length 69 | len = numel(model.w) + numel(model.b); 70 | 71 | % 2e7 = 2GB 72 | % 5e6 = 500 MB 73 | QP_SIZE = 2e7; 74 | nmax = floor(QP_SIZE/len); 75 | obj.nmax = nmax; 76 | obj.x = zeros(len,nmax,'single'); 77 | obj.b = zeros(nmax,1,'single'); 78 | obj.d = zeros(nmax,1,'double'); 79 | obj.a = zeros(nmax,1,'double'); 80 | obj.sv = logical(zeros(1,nmax)); 81 | % JSS3 2012-5-26, which examples are positive? 82 | obj.pos= logical(zeros(1,nmax)); 83 | obj.w = zeros(len,1); 84 | obj.n = 0; 85 | obj.ub = 0; 86 | obj.lb = 0; 87 | obj.l = 0; 88 | obj.C = C; 89 | obj.svfix = []; 90 | 91 | % prevent addition of duplicate features using a map of md5 92 | % hashes 93 | obj.containment = containers.Map(); 94 | end 95 | 96 | function obj = assert(obj,feat,margin,slack,pos) 97 | if isempty(feat) 98 | return 99 | end 100 | 101 | % Add constraints to QP 102 | % w*feat(:,i) >= margin(i) - slack(i) 103 | i = obj.n+1:obj.n + size(feat,2); 104 | obj.x(:,i) = feat; 105 | obj.d(i) = sum(feat.^2); 106 | obj.b(i) = margin; 107 | obj.sv(i) = 1; 108 | obj.pos(i) = pos; 109 | obj.ub = obj.ub + obj.C*sum(max(slack,0)); 110 | obj.n = obj.n + size(feat,2); 111 | assert(obj.n <= obj.nmax); 112 | end 113 | 114 | function obj = opt_one(obj) 115 | MEX = true; 116 | 117 | % Random ordering of support vectors 118 | I = find(obj.sv); 119 | I = I(randperm(length(I))); 120 | assert(~isempty(I)); 121 | 122 | % Mex file is much faster 123 | if MEX, 124 | bSize = size(obj.b); 125 | 126 | [loss,obj.a,obj.w,obj.sv,obj.l] = qp_one_c(obj.x,obj.b,obj.d,obj.a,obj.w,obj.sv,obj.l,obj.C,I); 127 | %keyboard; 128 | 129 | assert(all(bSize == size(obj.b))); 130 | else 131 | loss = 0; 132 | for i = I, 133 | % Compute clamped gradient 134 | G = obj.w'*obj.x(:,i) - obj.b(i); 135 | if (obj.a(i) == 0 && G >= 0) || (obj.a(i) == obj.C && G <= 0), 136 | PG = 0; 137 | else 138 | PG = G; 139 | end 140 | if (obj.a(i) == 0 && G > 0), 141 | obj.sv(i) = 0; 142 | end 143 | if G < 0, 144 | loss = loss - G; 145 | end 146 | % Update alpha,w, dual objective, support vector 147 | if (abs(PG) > 1e-12) 148 | a = obj.a(i); 149 | obj.a(i) = min(max(obj.a(i) - G/obj.d(i),0),obj.C); 150 | obj.w = obj.w + (obj.a(i) - a)*obj.x(:,i); 151 | obj.l = obj.l + (obj.a(i) - a)*obj.b(i); 152 | end 153 | end 154 | end 155 | 156 | % Update objective 157 | obj.sv(obj.svfix) = 1; 158 | obj.lb_old = obj.lb; 159 | obj.lb = obj.l - obj.w'*obj.w*.5; 160 | obj.ub = obj.w'*obj.w*.5 + obj.C*loss; 161 | assert(all(obj.a(1:obj.n) >= 0 - 1e-5)); 162 | assert(all(obj.a(1:obj.n) <= obj.C + 1e-5)); 163 | 164 | %{ 165 | % Sanity check (expensive to commute) 166 | J = find(mask); 167 | K = obj.x(:,J)*obj.a(J); 168 | dual = obj.b(J)'*obj.a(J) - K'*K*.5; 169 | fprintf('obj=(%.3f,%.3f)',obj.obj,dual); 170 | assert(abs(obj.obj - dual) < .1); 171 | %} 172 | end 173 | 174 | function obj = opt(obj,tol,iter) 175 | % obj_opt(tol,iter) 176 | % Optimize QP until relative difference between lower and upper bound is below 'tol' 177 | 178 | if nargin < 2 || isempty(tol) 179 | tol = .05; 180 | end 181 | 182 | if nargin < 3 || isempty(iter) 183 | iter = 1000; 184 | end 185 | 186 | slack = obj.b' - obj.w'*obj.x; 187 | loss = sum(max(slack,0)); 188 | ub = obj.w'*obj.w*.5 + obj.C*loss; 189 | lb = obj.lb; 190 | %fprintf('\n LB=%.4f,UB=%.4f [',lb,ub); 191 | %fprintf('['); 192 | 193 | % Iteratively apply coordinate descent, pruning active set (support vectors) 194 | % If we've possible converged over active set 195 | % 1) Compute true upper bound over full set 196 | % 2) If we haven't actually converged, 197 | % reinitialize optimization to full set 198 | obj.sv(1:obj.n) = 1; 199 | for t = 1:iter, 200 | obj = qp_one(obj); 201 | lb = obj.lb; 202 | ub_est = min(obj.ub,ub); 203 | %fprintf('.'); 204 | if lb > 0 && 1 - lb/ub_est < tol, 205 | slack = obj.b' - obj.w'*obj.x; 206 | loss = sum(max(slack,0)); 207 | ub = min(ub,obj.w'*obj.w*.5 + obj.C*loss); 208 | if 1 - lb/ub < tol, 209 | break; 210 | end 211 | obj.sv(1:obj.n) = 1; 212 | end 213 | %fprintf('t=%d: LB=%.4f,UB_true=%.5f,UB_est=%.5f,#SV=%d\n',t,lb,ub,ub_est,sum(obj.sv)); 214 | end 215 | 216 | obj.ub = ub; 217 | %fprintf(']'); 218 | %fprintf('] LB=%.4f,UB=%.4f\n',lb,ub); 219 | 220 | end 221 | 222 | % Re-indexes qp.x to begin with active consrtaints (eg, the support vectors) 223 | function [obj,n] = prune(obj) 224 | % if cache is full of support vectors, only keep non-zero (and fixed) ones 225 | if all(obj.sv), 226 | obj.sv = obj.a > 0; 227 | obj.sv(obj.svfix) = 1; 228 | end 229 | 230 | I = find(obj.sv > 0); 231 | n = length(I); 232 | assert(n > 0); 233 | 234 | % remove the non-support vectors from the 235 | NI = find(obj.sv(1:obj.n) <= 0); 236 | for i = 1:numel(NI) 237 | feat = obj.x(:,NI(i)); 238 | hash = hashMat(feat); 239 | if obj.containment.isKey(hash) 240 | remove(obj.containment,hash); 241 | end 242 | end 243 | 244 | % move svs into the front of the cache 245 | obj.l = 0; 246 | obj.w = zeros(size(obj.w)); 247 | for j = 1:n, 248 | i = I(j); 249 | obj.x(:,j) = obj.x(:,i); 250 | obj.b(j) = obj.b(i); 251 | obj.d(j) = obj.d(i); 252 | obj.a(j) = obj.a(i); 253 | obj.sv(j) = obj.sv(i); 254 | obj.pos(j) = obj.pos(i); 255 | obj.l = obj.l + double(obj.b(j))*obj.a(j); 256 | obj.w = obj.w + double(obj.x(:,j))*obj.a(j); 257 | end 258 | 259 | % clear the rest of the cache 260 | obj.sv(1:n) = 1; 261 | j = n+1:length(obj.a); 262 | obj.sv(j) = 0; 263 | obj.a(j) = 0; 264 | obj.b(j) = 0; 265 | obj.pos(j) = 0; 266 | obj.x(:,j) = 0; 267 | obj.obj = obj.l - obj.w'*obj.w*.5; 268 | obj.n = n; 269 | %fprintf('\n Pruned to %d/%d with dual=%.4f \n',obj.n,length(obj.a),obj.obj); 270 | end 271 | 272 | function obj = retract(obj,what,margin,slack) 273 | if numel(what) == 1 274 | num = what; 275 | else 276 | feat = what; 277 | num = size(feat,2); 278 | end 279 | 280 | index = obj.n:-1:(obj.n-num+1); 281 | obj.x(:,index) = 0; 282 | obj.d(index) = 0; 283 | obj.b(index) = 0; 284 | obj.sv(index) = 0; 285 | obj.ub = obj.ub - obj.C*sum(max(slack,0)); 286 | obj.n = obj.n - num; 287 | assert(obj.n <= obj.nmax); 288 | end 289 | 290 | function obj = write(obj,feat,margin,slack,isPos) 291 | % Compute the (md5) hash code for the feature vector. 292 | %keyboard; 293 | hashCode = hashMat(feat); 294 | 295 | % make sure we don't overfill the cache... 296 | assert(size(feat,2) == numel(margin) || numel(margin) == 1); 297 | if size(feat,2)+obj.n >= obj.nmax 298 | obj = obj.prune(); 299 | end 300 | num_keep = clamp(0,obj.nmax-obj.n,size(feat,2)); 301 | feat = feat(:,1:num_keep); 302 | if numel(margin) ~= 1 303 | margin = margin(1:num_keep); 304 | end 305 | 306 | % only add the feature to the cache if it hasn't 307 | % already been added.... 308 | if ~obj.containment.isKey(hashCode) 309 | % function obj_write(feat,margin,slack) 310 | obj = obj.assert(feat,margin,slack,isPos); 311 | 312 | obj.containment(hashCode) = 1; 313 | else 314 | 'would add duplicate key'; 315 | end 316 | end 317 | 318 | % JSS3 - 2012.8.15 319 | % quick estimate for UB given a w 320 | function loss = compute_loss(obj,w) 321 | if nargin < 2 322 | w = obj.w; 323 | end 324 | 325 | % compute loss 326 | is = 1:obj.n; 327 | resp = w' * obj.x(:,is); 328 | margins = obj.b(is); 329 | slacks = max(margins' - resp,0); 330 | %.5*||w||^2 + C*sum_i e_i 331 | % loss = .5.*w'*w + obj.C .* sum(slacks); 332 | loss = obj.C .* sum(slacks); 333 | end 334 | end 335 | end 336 | -------------------------------------------------------------------------------- /qp/qp_assert.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-21 2 | function qp = qp_assert(qp,feat,margin,slack,pos) 3 | qp = qp.assert(feat,margin,slack,pos); 4 | end 5 | -------------------------------------------------------------------------------- /qp/qp_clear.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.5.14 2 | % remove most of the data in the qp for storage. 3 | function qpPrime = qp_clear(qp) 4 | qpPrime = QP_fixed(qp); 5 | end 6 | -------------------------------------------------------------------------------- /qp/qp_init.m: -------------------------------------------------------------------------------- 1 | % Deva Ramanan 2012-03-19 2 | % qp_init(len,nmax,C) 3 | % 4 | % 5 | % Define global QP problem 6 | % 2012-04-25 JSS3 made it local for parfor. 7 | % 8 | % (Primal) min_{w,e} .5*||w||^2 + C*sum_i e_i 9 | % s.t. w*x_i >= b_i - e_i 10 | % 11 | % (Dual) max_{a} -.5*sum_ij a_i(x_ix_j)a_j + sum_i b_i*a_i 12 | % s.t. 0 <= a_i <= C 13 | % 14 | % where w = sum_i a_i x_i 15 | % 16 | % qp.x(:,i) = x_i where size(qp.x) = [len nmax] 17 | % qp.b(:,i) = b_i 18 | % qp.d(i) = ||x(i)||^2 19 | % qp.a(i) = a_i 20 | % qp.w = sum_i a_i x_i 21 | % qp.l = sum_i b_i a_i 22 | % qp.n = number of constraints 23 | % qp.ub = .5*||qp.w||^2 + C*sum_i e_i 24 | % qp.lb = -.5*sum_ij a_i(x_ix_j)a_j + sum_i b_i*a_i 25 | % qp.C = C 26 | % qp.svfix = pointers to examples that are always kept in memory 27 | % JSS3 2012-03-18 28 | % init a blank Quadratic Program... 29 | function [qp,nmax] = qp_init(model,C) 30 | qp = QP(model,C); 31 | nmax = qp.nmax; 32 | end 33 | -------------------------------------------------------------------------------- /qp/qp_one.m: -------------------------------------------------------------------------------- 1 | % Perform one pass through current set of support vectors 2 | function qp = qp_one(qp) 3 | qp = qp.opt_one(); 4 | end 5 | -------------------------------------------------------------------------------- /qp/qp_one_c.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../mex/compat.h" 3 | #include "mex.h" 4 | #include "matrix.h" 5 | 6 | #define MAX(A,B) ((A) < (B) ? (B) : (A)) 7 | #define MIN(A,B) ((A) > (B) ? (B) : (A)) 8 | 9 | // Undocumented Features! 10 | //extern int mxUnshareArray(mxArray *pr, int noDeepCopy); // true if not successful 11 | //extern bool mxUnshareArray(const mxArray *pr, const bool noDeepCopy); 12 | extern "C" int mxUnshareArray(mxArray *pa, int level); 13 | extern "C" int mxIsSharedArray(mxArray* pa); 14 | extern "C" mxArray *mxCreateSharedDataCopy(const mxArray *pr); 15 | 16 | // x(:,1:length(I)) = x(:,I); 17 | // qp_one_c(qp.x,qp.b,qp.d,qp.a,qp.w,qp.sv,qp.l,qp.C,I); 18 | void mexFunction( int nlhs, mxArray *plhs[], 19 | int nrhs, const mxArray *prhs[] ) 20 | { 21 | if (nlhs < 5) mexErrMsgTxt("qp_one_c.cc: Incorrect number of output arguments."); 22 | if (nrhs < 9) mexErrMsgTxt("qp_one_c.cc: Incorrect number of input arguments."); 23 | 24 | // prevent erronous sharing. 25 | mxArray *Areturn, *Wreturn, *SVreturn, *Lreturn; 26 | Areturn = mxCreateSharedDataCopy(prhs[3]); 27 | Wreturn = mxCreateSharedDataCopy(prhs[4]); 28 | SVreturn = mxCreateSharedDataCopy(prhs[5]); 29 | Lreturn = mxCreateSharedDataCopy(prhs[6]); 30 | mxUnshareArray(Areturn, 0); 31 | mxUnshareArray(Wreturn, 0); 32 | mxUnshareArray(SVreturn, 0); 33 | mxUnshareArray(Lreturn, 0); 34 | 35 | float const *X = (float *)mxGetPr(prhs[0]); 36 | float const *B = (float *)mxGetPr(prhs[1]); 37 | double const *D = (double *)mxGetPr(prhs[2]); 38 | double *A = (double *)mxGetPr(Areturn); 39 | double *W = (double *)mxGetPr(Wreturn); 40 | bool *SV = (bool *)mxGetPr(SVreturn); 41 | double *L = (double *)mxGetPr(Lreturn); 42 | double C = (double )mxGetScalar(prhs[7]); 43 | double const *I = (double *)mxGetPr(prhs[8]); 44 | 45 | if (mxIsSingle(prhs[0]) == false) mexErrMsgTxt("Argument 0 is not single."); 46 | if (mxIsSingle(prhs[1]) == false) mexErrMsgTxt("Argument 1 is not single."); 47 | if (mxIsDouble(prhs[2]) == false) mexErrMsgTxt("Argument 2 is not double."); 48 | if (mxIsDouble(prhs[3]) == false) mexErrMsgTxt("Argument 3 is not double."); 49 | if (mxIsDouble(prhs[4]) == false) mexErrMsgTxt("Argument 4 is not double."); 50 | if (mxIsLogical(prhs[5]) == false) mexErrMsgTxt("Argument 6 is not logical."); 51 | if (mxIsDouble(prhs[6]) == false) mexErrMsgTxt("Argument 7 is not double."); 52 | if (mxIsDouble(prhs[7]) == false) mexErrMsgTxt("Argument 8 is not double."); 53 | if (mxIsDouble(prhs[8]) == false) mexErrMsgTxt("Argument 9 is not double."); 54 | 55 | mwSize m = mxGetM(prhs[0]); 56 | mwSize n = MAX(mxGetN(prhs[8]),mxGetM(prhs[8])); 57 | 58 | double loss = 0; 59 | //printf("Intro: (m,n,C) = (%d,%d,%g)\n",m,n,C); 60 | 61 | for (int cnt = 0; cnt < n; cnt++) { 62 | // Use C indexing 63 | int i = (int)I[cnt] - 1; 64 | double G = -(double)B[i]; 65 | float const *x = X + m*i; 66 | 67 | for (int d = 0; d < m; d++) { 68 | G += W[d] * (double)x[d]; 69 | //printf("(%g,%g,%g)",G,W[d],x[d]); 70 | } 71 | 72 | double PG = G; 73 | 74 | if ((A[i] == 0 && G >= 0) || (A[i] == C && G <= 0)) { 75 | PG = 0; 76 | } 77 | 78 | if (A[i] == 0 && G > 0) { 79 | SV[i] = false; 80 | } 81 | 82 | if (G < 0) { 83 | loss -= G; 84 | } 85 | 86 | //printf("[%d,%d,%g,%g,%g]\n",cnt,i,G,PG,A[i]); 87 | if (PG > 1e-12 || PG < -1e-12) { 88 | double dA = A[i]; 89 | A[i] = MIN ( MAX ( A[i] - G/D[i], 0 ) , C ); 90 | dA = A[i] - dA; 91 | L[0] += dA * (double) B[i]; 92 | //printf("%g,%g,%g,%g\n",A[i],B[i],dA,*L); 93 | for (int d = 0; d < m; d++) { 94 | W[d] += dA * (double) x[d]; 95 | } 96 | } 97 | } 98 | 99 | // pack the output arguments... 100 | plhs[0] = mxCreateDoubleScalar(loss); 101 | plhs[1] = Areturn; 102 | plhs[2] = Wreturn; 103 | plhs[3] = SVreturn; 104 | plhs[4] = Lreturn; 105 | } 106 | 107 | /* Mex code equivalent to below 108 | % Perform one pass through variables indicated by binary mask 109 | for i = I, 110 | % Compute clamped gradient 111 | G = qp.w'*qp.x(:,i) - qp.b(i); 112 | if (qp.a(i) == 0 && G >= 0) || (qp.a(i) == qp.C && G <= 0), 113 | PG = 0; 114 | else 115 | PG = G; 116 | end 117 | if (qp.a(i) == 0 && G > 0), 118 | qp.sv(i) = 0; 119 | end 120 | if G < 0, 121 | loss = loss - G; 122 | end 123 | % Update alpha,w, dual objective, support vector 124 | if (abs(PG) > 1e-12) 125 | a = qp.a(i); 126 | qp.a(i) = min(max(qp.a(i) - G/qp.d(i),0),qp.C); 127 | qp.w = qp.w + (qp.a(i) - a)*qp.x(:,i); 128 | qp.l = qp.l + (qp.a(i) - a)*qp.b(i); 129 | end 130 | */ 131 | -------------------------------------------------------------------------------- /qp/qp_opt.m: -------------------------------------------------------------------------------- 1 | function qp = qp_opt(qp,tol,iter) 2 | qp = qp.opt(); 3 | end 4 | -------------------------------------------------------------------------------- /qp/qp_prune.m: -------------------------------------------------------------------------------- 1 | % Re-indexes qp.x to begin with active consrtaints (eg, the support vectors) 2 | function [qp,n] = qp_prune(qp) 3 | [qp,n] = qp.prune(); 4 | end 5 | -------------------------------------------------------------------------------- /qp/qp_write.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.3 2 | % To weight a sample, 3 | % (Primal) min_{w,e} .5*||w||^2 + C*sum_i v_i*e_i 4 | % s.t. w*x_i >= b_i - e_i 5 | % if u_i = v_i * e_i 6 | % then w*x_i >= b_i - u_i/v_i or 7 | % w*v_i*x_i >= v_i*b_i - u_i with .5*||w||^2 + C*sum_i u_i 8 | % so multiply the feature and the margin by the weight (2nd and 3rd arguments) 9 | function qp = qp_write(qp,feat,margin,slack,isPos) 10 | qp = qp.write(feat,margin,slack,isPos); 11 | end 12 | -------------------------------------------------------------------------------- /rect/check_rect_size.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.8.31 2 | % return 1 if a bb is ok, 3 | % 0 other (maybe it is to large or truncated) 4 | function ok = check_rect_size(k_bb,k_im) 5 | % size constraints 6 | n = size(k_bb,1); 7 | imsz = repmat(rect_size(k_im),[n,1]); 8 | bbsz = rect_size(k_bb); 9 | ok = all(bbsz <= 2.*imsz,2); 10 | end 11 | -------------------------------------------------------------------------------- /rect/csvBtoK.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.6.28 2 | % convert Babenko BBs to Kalal BBs in a CSV file 3 | function csvBtoK(filename) 4 | b_track = csvread(filename); 5 | k_track = rectBtoK(b_track); 6 | csvwrite(filename,k_track); 7 | end 8 | -------------------------------------------------------------------------------- /rect/rectBtoK.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-03-18 2 | % convert rectnalge from [x1 y1 w h] format 3 | % to [x1 y1 x2 y2] 4 | function K = rectKtoB(B) 5 | K = [B(:,1) B(:,2) (B(:,1)+B(:,3)) (B(:,2)+B(:,4))]; 6 | end 7 | -------------------------------------------------------------------------------- /rect/rectKtoB.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-03-18 2 | % convert rectnalge from [x1 y1 x2 y2] format 3 | % to [x1 y1 w h] 4 | function B = rectKtoB(K) 5 | B = [K(:,1) K(:,2) (K(:,3)-K(:,1)) (K(:,4)-K(:,2))]; 6 | end 7 | -------------------------------------------------------------------------------- /rect/rect_area.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.10 2 | % Return area of a rectangle 3 | function ar = rect_area(k_rect) 4 | width = k_rect(:,3) - k_rect(:,1); 5 | height = k_rect(:,4) - k_rect(:,2); 6 | ar = width .* height; 7 | end 8 | -------------------------------------------------------------------------------- /rect/rect_aspect.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.10 2 | % Return aspect ratio of a rectangle 3 | function aspect = rect_aspect(k_rect) 4 | width = k_rect(:,3) - k_rect(:,1); 5 | height = k_rect(:,4) - k_rect(:,2); 6 | aspect = width ./ height; 7 | end 8 | -------------------------------------------------------------------------------- /rect/rect_center.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-14 2 | % return the center of a Kalal format rectangle... 3 | function center = rect_center(k_rect) 4 | x = (k_rect(:,1)+k_rect(:,3))./2; 5 | y = (k_rect(:,2)+k_rect(:,4))./2; 6 | 7 | center = [x y]; 8 | end 9 | -------------------------------------------------------------------------------- /rect/rect_contains.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.6.19 2 | function c = rect_contains(k_rect,k_pts) 3 | c = k_pts(:,1) >= k_rect(:,1) & k_pts(:,1) <= k_rect(:,3) & ... 4 | k_pts(:,2) >= k_rect(:,2) & k_pts(:,2) <= k_rect(:,4); 5 | end 6 | -------------------------------------------------------------------------------- /rect/rect_correct_aspect.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-13 2 | % rect_correct_aspect changes the aspect ratio of a rectangle to 3 | % the desired aspect ratio without changing its area. 4 | function k_rect2 = rect_correct_aspect(k_rect,newAspectRatio) 5 | % aspect = width/height 6 | 7 | % find the new size 8 | oldWidth = k_rect(3) - k_rect(1); 9 | oldHeight = k_rect(4) - k_rect(2); 10 | oldArea = oldWidth.*oldHeight; 11 | % newArea = newWidth * newHeight 12 | % newArea = oldArea 13 | % newAspectRatio = newWidth/newHeight 14 | % newWidth = newAspectRatio * newHeight 15 | % oldArea = newHeight * newAspectRatio * newHeight 16 | % oldArea = newHeight^2 * newAspectRatio 17 | % newHeight = sqrt(oldArea/newAspectRatio) 18 | %newAspectRatio 19 | newHeight = sqrt(oldArea/newAspectRatio); 20 | newWidth = newAspectRatio*newHeight; 21 | 22 | % find the old center 23 | oldCenX = (k_rect(1)+k_rect(3))./2; 24 | oldCenY = (k_rect(2)+k_rect(4))./2; 25 | 26 | k_rect2 = rect_from_center([oldCenX,oldCenY],[newWidth,newHeight]); 27 | end 28 | -------------------------------------------------------------------------------- /rect/rect_equal.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-06-03 2 | % Are two rectangles equal? 3 | function eq = rect_equal(rect1,rect2) 4 | eq = (gt_occluded(rect1) && gt_occluded(rect2)) || ... 5 | all(rect1(:,1:4) == rect2(:,1:4)); 6 | end 7 | -------------------------------------------------------------------------------- /rect/rect_from_center.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-13 2 | % rect_from_center takes a center and a size and returns a 3 | % Kalal format rectangle. 4 | function k_rect = rect_from_center(cen,sz) 5 | % find the extreme pts. 6 | x1 = cen(:,1) - sz(:,1)./2; 7 | y1 = cen(:,2) - sz(:,2)./2; 8 | x2 = cen(:,1) + sz(:,1)./2; 9 | y2 = cen(:,2) + sz(:,2)./2; 10 | 11 | % return 12 | k_rect = [x1 y1 x2 y2]; 13 | end 14 | -------------------------------------------------------------------------------- /rect/rect_image.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.10 2 | % Return the rectnagle bounding an image 3 | function rect = rect_image(im) 4 | [h,w,d] = size(im); 5 | rect = [0 0 w h]; 6 | end 7 | -------------------------------------------------------------------------------- /rect/rect_overlap.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-14 2 | % JSS3 multiple rectangle support 2012-5-14 3 | % Computes the intersection over union overlap 4 | % for two Kalal format rectangles 5 | function overlap = rect_overlap(k_rect1, k_rect2) 6 | if gt_occluded(k_rect1) && gt_occluded(k_rect2) 7 | overlap = 1; 8 | elseif xor(gt_occluded(k_rect1),gt_occluded(k_rect2)) 9 | overlap = 0; 10 | else 11 | rect1 = rectKtoB(k_rect1); 12 | rect2 = rectKtoB(k_rect2); 13 | 14 | % intersection of rectangle 1 and rectangle 2 15 | intersection = rectint(rect1,rect2); 16 | % area of rectangle 1 17 | area1 = rect1(:,3) .* rect1(:,4); % a = w*h 18 | % area of rectangle 2 19 | area2 = rect2(:,3) .* rect2(:,4); % a = w*h 20 | 21 | % union over intersection 22 | overlap = intersection ./ (area1+area2-intersection); 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /rect/rect_scale.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-20 2 | % scale a rect by the given factors 3 | function k_rect = rect_scale(k_rect,xScale,yScale) 4 | center = rect_center(k_rect); 5 | width = k_rect(:,3) - k_rect(:,1); 6 | height = k_rect(:,4) - k_rect(:,2); 7 | k_rect = rect_from_center(center,[xScale.*width yScale.*height]); 8 | end 9 | -------------------------------------------------------------------------------- /rect/rect_size.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-05-04 2 | function sz = rect_size(k_rect) 3 | sz = zeros(size(k_rect,1),2); 4 | % width 5 | sz(:,1) = k_rect(:,3) - k_rect(:,1); 6 | % height 7 | sz(:,2) = k_rect(:,4) - k_rect(:,2); 8 | end 9 | -------------------------------------------------------------------------------- /rect/rect_trans.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-13 2 | % Translate a Kalal rectangle 3 | function k_rect = rect_trans(k_rect,offset) 4 | k_rect([1,3]) = k_rect([1,3]) + offset(1); 5 | k_rect([2,4]) = k_rect([2,4]) + offset(2); 6 | end 7 | -------------------------------------------------------------------------------- /rect/rect_zero_orig.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-13 2 | % rect_zero_orig translates a rectangle so that it is rooted at the 3 | % origin 4 | function k_rect = rect_zero_orig(k_rect) 5 | k_rect([1,3]) = k_rect([1,3]) - k_rect(1); 6 | k_rect([2,4]) = k_rect([2,4]) - k_rect(2); 7 | end 8 | -------------------------------------------------------------------------------- /rect/rects_overlap.m: -------------------------------------------------------------------------------- 1 | %% JSS3 2012.8.20 2 | % Compute overlap between two lists of rectangles 3 | function ols = rects_overlap(k_A,k_B) 4 | ols = zeros(size(k_A,1),1); 5 | for iter = 1:numel(ols) 6 | ols(iter) = rect_overlap(k_A(iter,:),k_B(iter,:)); 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /show/hasDisplay.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-05-27 2 | % predicate function to indicate if the current MATLAB 3 | % has a display to show graphics on... 4 | function yes = hasDisplay() 5 | yes = ~usejava('jvm') || feature('ShowFigureWindows'); 6 | end 7 | -------------------------------------------------------------------------------- /show/linWidth.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.7.5 2 | % Compute the proper line with when showing N boxes 3 | function width = linWidth(N) 4 | a = 7.5; 5 | b = -.05; 6 | width = a*exp(b*N); 7 | width = ceil(width); 8 | end 9 | -------------------------------------------------------------------------------- /show/plot_resp.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-06 2 | % MATLAB function to plot the response values 3 | % against some other useful information. 4 | function [p,r] = plot_resp(b_gts,k_boxes,vidName,show) 5 | if nargin < 4 6 | show = 0; 7 | end 8 | 9 | makePlot = isempty(getCurrentTask) && show; 10 | if makePlot 11 | clf; 12 | hold on; 13 | end 14 | 15 | % compute the graph, frame by frame 16 | [cAccept,gAccept,nAccept,... 17 | goodIdx,goodResp,badIdx,badResp,... 18 | gtVisIdx,gtVisResp,trVisIdx,trVisResp] ... 19 | = plot_resp_accum(b_gts,k_boxes,vidName); 20 | 21 | if makePlot 22 | % plot visibilities 23 | phs = []; 24 | phs(end+1) = plot(gtVisIdx,gtVisResp,' o','DisplayName','gt accept'); 25 | phs(end+1) = plot(trVisIdx,trVisResp,' s','DisplayName','tracker accept'); 26 | % generate the plot 27 | phs(end+1) = plot(goodIdx,goodResp,'b+','DisplayName','Correct'); 28 | phs(end+1) = plot(badIdx,badResp,'r+','DisplayName','Incorrect'); 29 | legend show; 30 | 31 | % label the plot 32 | title(vidName); 33 | xlabel('Frame Number'); 34 | ylabel('Cost'); 35 | 36 | hold off; 37 | 38 | PRESENTATION = 1; 39 | if PRESENTATION 40 | legend hide; 41 | set(gca,'position',[0 0 1 1]) ; 42 | h = gca; 43 | set(h,'XTick',[]); 44 | set(h,'YTick',[]); 45 | for iter = 1:numel(phs) 46 | set(phs(iter),'MarkerSize',12); 47 | end 48 | end 49 | end 50 | 51 | % report p and r 52 | cAccept 53 | gAccept 54 | nAccept 55 | p = cAccept/nAccept; 56 | r = cAccept/gAccept; 57 | end 58 | 59 | function [cAccept,gAccept,nAccept,... 60 | goodIdx,goodResp,badIdx,badResp,... 61 | gtVisIdx,gtVisResp,trVisIdx,trVisResp] ... 62 | = plot_resp_accum(b_gts,k_boxes,vidName) 63 | % precision = correctly accepted / number accepted 64 | % recall = correctly accepted / gt accepted 65 | cAccept = 0; 66 | gAccept = 0; 67 | nAccept = 0; 68 | 69 | % error plotting 70 | goodIdx = []; 71 | goodResp = []; 72 | badIdx = []; 73 | badResp = []; 74 | % occlusion plotting 75 | gtVisIdx = []; 76 | gtVisResp = []; 77 | trVisIdx = []; 78 | trVisResp = []; 79 | 80 | for i = 2:size(b_gts,1) 81 | gt = b_gts(i,:); 82 | box = k_boxes(i,:); 83 | derivative = 0; 84 | if derivative 85 | lastBox = k_boxes(i-1,:); 86 | else 87 | lastBox = 2.*box; 88 | end 89 | 90 | % update the counts for p/r 91 | [l,c,g,n] = score_track_one(gt,box); 92 | cAccept = cAccept + c; 93 | gAccept = gAccept + g; 94 | nAccept = nAccept + n; 95 | 96 | % plot pt 97 | if l > 0 98 | if c > 0 99 | % correct 100 | goodIdx(end+1) = i; 101 | goodResp(end+1) = lastBox(5)-box(5); 102 | else 103 | % incorrect 104 | badIdx(end+1) = i; 105 | badResp(end+1) = lastBox(5)-box(5); 106 | end 107 | 108 | if g > 0 109 | gtVisIdx(end+1) = i; 110 | gtVisResp(end+1) = lastBox(5)-box(5); 111 | end 112 | 113 | if n > 0 114 | trVisIdx(end+1) = i; 115 | trVisResp(end+1) = lastBox(5)-box(5); 116 | end 117 | end 118 | end 119 | end 120 | -------------------------------------------------------------------------------- /show/showBox.m: -------------------------------------------------------------------------------- 1 | % showBox(im,rect) 2 | % Input: 3 | % im is a N X M grayscale image 4 | % rect is a 1 X 4 array of rectangle coordinates 5 | % ([x1 y1 x2 y2] coordinates assumed) 6 | % Output: None 7 | % This function shows an image with a rectangle on it 8 | % Hint: use Matlab's "imshow.m", "hold.m" and "line.m" functions 9 | function showBox(im,rect,clean) 10 | if nargin < 3 11 | clean = 0; 12 | end 13 | 14 | if clean 15 | set(gca,'position',[0 0 1 1]) ; 16 | % im and rect must be fixed 17 | crop_r = rect_scale(rect,2,2); 18 | rect([1 3]) = rect([1 3]) - crop_r(1); 19 | rect([2 4]) = rect([2 4]) - crop_r(2); 20 | im = imcropr(im,crop_r); 21 | end 22 | 23 | % can't show on the cluster worker. 24 | if ~isempty(getCurrentTask) 25 | return 26 | end 27 | 28 | showBoxes(im,rect,clean); 29 | end 30 | -------------------------------------------------------------------------------- /show/showBoxVia.m: -------------------------------------------------------------------------------- 1 | function showBoxVia(im,rect,via) 2 | % extract the params 3 | x1 = rect(1); y1 = rect(2); 4 | x2 = rect(3); y2 = rect(4); 5 | % draw the image 6 | colormap gray(256); 7 | via(im); 8 | hold on; 9 | % draw the box. 10 | line([x1 x2],[y1 y1]) % top 11 | line([x1 x2],[y2 y2]) % bottom 12 | line([x1 x1],[y1 y2]) % left 13 | line([x2 x2],[y1 y2]) % right 14 | hold off; 15 | drawnow; 16 | end 17 | -------------------------------------------------------------------------------- /show/showBoxes.m: -------------------------------------------------------------------------------- 1 | function showBoxes(im,boxes,clean) 2 | % showBoxes(im,boxes) 3 | if nargin < 3 4 | clean = 0; 5 | end 6 | 7 | cla; 8 | if clean 9 | set(gca,'position',[0 0 1 1]) ; 10 | end 11 | imagesc(im); 12 | 13 | width = linWidth(size(boxes,1)); 14 | 15 | if ~isempty(boxes), 16 | % use light red line to show everyone 17 | if size(boxes,1) > 1 18 | showGhostBoxes(boxes(2:end,:),'r',width); 19 | end 20 | 21 | % plot the best box in dark blue. 22 | x1 = boxes(1,1); 23 | y1 = boxes(1,2); 24 | x2 = boxes(1,3); 25 | y2 = boxes(1,4); 26 | line([x1 x1 x2 x2 x1]',[y1 y2 y2 y1 y1]','color','b','linewidth', ... 27 | width*2); 28 | 29 | % plot numbers... 30 | if clean 31 | return; 32 | end 33 | for boxIter = 1:size(boxes,1) 34 | boxTexts = {}; 35 | curBox = boxes(boxIter,:); 36 | cen = deal(rect_center(curBox)); 37 | % add the response? 38 | if size(boxes,2) > 4 39 | boxTexts{end+1} = ['resp = ' num2str(curBox(:,5))]; 40 | end 41 | %if size(boxes,2) >= 6 42 | % boxTexts{end+1} = ['occ = ' num2str(curBox(:,6))]; 43 | %end 44 | %if size(boxes,2) >= 7 45 | % boxTexts{end+1} = ['emg = ' num2str(curBox(:,7))]; 46 | %end 47 | text(cen(1),cen(2),boxTexts,'Color','g'); 48 | end 49 | end 50 | 51 | drawnow; 52 | -------------------------------------------------------------------------------- /show/showGhostBoxes.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.10.9 2 | % advanced box drawing function with support for alpha transparency 3 | function showGhostBoxes(boxes,color,width) 4 | % compute coordinates 5 | D = max(.5,width./4); 6 | x1 = boxes(:,1); 7 | y1 = boxes(:,2); 8 | x2 = boxes(:,3); 9 | y2 = boxes(:,4); 10 | 11 | % compute alphas 12 | N = size(boxes,1); 13 | %alphas = ((N:-1:1)./N)'; 14 | alphas = ((1:N)./N)'; 15 | 16 | % draw the top and bottom 17 | patch([x1-D x2+D x2+D x1-D]',[y1-D y1-D y1+D y1+D]',color,'edgecolor','none',... 18 | 'FaceAlpha','flat','FaceVertexAlphaData',alphas); 19 | patch([x1-D x2+D x2+D x1-D]',[y2+D y2+D y2-D y2-D]',color,'edgecolor','none',... 20 | 'FaceAlpha','flat','FaceVertexAlphaData',alphas); 21 | % draw left and right 22 | patch([x1-D x1+D x1+D x1-D]',[y1+D y1+D y2-D y2-D]',color,'edgecolor','none',... 23 | 'FaceAlpha','flat','FaceVertexAlphaData',alphas); 24 | patch([x2-D x2+D x2+D x2-D]',[y1+D y1+D y2-D y2-D]',color,'edgecolor','none',... 25 | 'FaceAlpha','flat','FaceVertexAlphaData',alphas); 26 | end 27 | -------------------------------------------------------------------------------- /show/showModel.m: -------------------------------------------------------------------------------- 1 | % Display the HOG template 2 | % Only the first argument is required. 3 | function [hogPos,hogNeg] = showModel(ww,n,sc) 4 | 5 | % can't show on the cluster worker. 6 | if ~isempty(getCurrentTask) 7 | return 8 | end 9 | 10 | % the second two arguments are optinal. 11 | if nargin >= 2 12 | sfigure(n); 13 | clf; 14 | else 15 | n = 1; 16 | end 17 | if nargin < 3, 18 | %Set the scale so that the maximum weight is 255 19 | sc = max(abs(ww(:))); 20 | end 21 | 22 | sc = 255/sc; 23 | 24 | siz = 20; 25 | 26 | im1 = HOGpicture( ww,siz)*sc; 27 | hogPos = im1; 28 | im2 = HOGpicture(-ww,siz)*sc; 29 | hogNeg = im2; 30 | 31 | %Combine into 1 image 32 | buff = 10; 33 | im1 = padarray(im1,[buff buff],200,'both'); 34 | im2 = padarray(im2,[buff buff],200,'both'); 35 | im = cat(2,im1,im2); 36 | im = uint8(im); 37 | imagesc(im); colormap gray; 38 | title(['HoG Model: ' n]); 39 | %keyboard; 40 | 41 | function im = HOGpicture(w, bs) 42 | % HOGpicture(w, bs) 43 | % Make picture of positive HOG weights. 44 | global ORI_BINS; 45 | 46 | % construct a "glyph" for each orientaion 47 | bim1 = zeros(bs, bs); 48 | %bim1(:,round(bs/2):round(bs/2)+1) = 1; 49 | bim1(1:(round(size(bim1,1)./2)+1),round(20/2):round(20/2)+1) = 1; 50 | bim = zeros([size(bim1) ORI_BINS]); 51 | bim(:,:,1) = bim1; 52 | for i = 2:ORI_BINS, 53 | bim(:,:,i) = imrotate(bim1, -(i-1)*20, 'crop'); 54 | end 55 | 56 | % make pictures of positive weights bs adding up weighted glyphs 57 | s = size(w); 58 | w(w < 0) = 0; 59 | im = zeros(bs*s(1), bs*s(2),3); 60 | for i = 1:s(1), 61 | iis = (i-1)*bs+1:i*bs; 62 | for j = 1:s(2), 63 | jjs = (j-1)*bs+1:j*bs; 64 | % draw the background 65 | if(size(w,3) > ORI_BINS+4) 66 | im(iis,jjs,1) = w(i,j,ORI_BINS+4+1); 67 | im(iis,jjs,2) = w(i,j,ORI_BINS+4+2); 68 | im(iis,jjs,3) = w(i,j,ORI_BINS+4+3); 69 | end 70 | 71 | % draw the lines 72 | for k = 1:ORI_BINS, 73 | im(iis,jjs,1) = im(iis,jjs,1) + bim(:,:,k) * w(i,j,k); 74 | im(iis,jjs,2) = im(iis,jjs,2) + bim(:,:,k) * w(i,j,k); 75 | im(iis,jjs,3) = im(iis,jjs,3) + bim(:,:,k) * w(i,j,k); 76 | end 77 | end 78 | end 79 | 80 | 81 | -------------------------------------------------------------------------------- /track_dp/dynprog_chain.cc: -------------------------------------------------------------------------------- 1 | // JSS3 - 2012-6-21 2 | #include "mex.h" 3 | #include "matrix.h" 4 | #include "../mex/compat.h" 5 | #include 6 | #include 7 | #include 8 | 9 | using std::numeric_limits; 10 | using std::max; 11 | using std::min; 12 | 13 | // Undocumented Features! 14 | extern "C" int mxUnshareArray(mxArray *pa, int level); 15 | extern "C" int mxIsSharedArray(mxArray* pa); 16 | extern "C" mxArray *mxCreateSharedDataCopy(const mxArray *pr); 17 | 18 | #define OCCLUDED isnan 19 | #define INF (numeric_limits::infinity()) 20 | 21 | #ifndef round(x) 22 | #define round(x) (x<0?ceil((x)-0.5):floor((x)+0.5)) 23 | #endif 24 | 25 | static double rect_overlap(double newX1, double newY1, double newX2, double newY2, 26 | double oldX1, double oldY1, double oldX2, double oldY2) 27 | { 28 | // intersection 29 | double 30 | int_x1 = max(newX1,oldX1), 31 | int_y1 = max(newY1,oldY1), 32 | int_x2 = min(newX2,oldX2), 33 | int_y2 = min(newY2,oldY2); 34 | double 35 | int_w = int_x2 - int_x1 + 1, 36 | int_h = int_y2 - int_y1 + 1; 37 | double int_ar = int_w*int_h; 38 | 39 | // area new 40 | double 41 | new_w = newX2 - newX1 + 1, 42 | new_h = newY2 - newY1 + 1; 43 | double new_ar= new_w*new_h; 44 | 45 | // area old 46 | double 47 | old_w = oldX2 - oldX1 + 1, 48 | old_h = oldY2 - oldY1 + 1; 49 | double old_ar= old_w*old_h; 50 | 51 | if(int_w <= 0 || int_h <= 0) 52 | return -1; 53 | else 54 | return int_ar/(new_ar+old_ar-int_ar); 55 | } 56 | 57 | static double cost_pw_corner(double newX1, double newY1, double newX2, double newY2, 58 | double oldX1, double oldY1, double oldX2, double oldY2) 59 | { 60 | double cost; 61 | if(!OCCLUDED(newX1) && !OCCLUDED(oldX1)) 62 | { 63 | // neither is occluded 64 | double cost_tl = (newX1-oldX1)*(newX1-oldX1)+(newY1-oldY1)*(newY1-oldY1); 65 | double cost_br = (newX2-oldX2)*(newX2-oldX2)+(newY2-oldY2)*(newY2-oldY2); 66 | cost = (cost_tl+cost_br)/2; 67 | } 68 | else 69 | { 70 | cost = 0.0; 71 | } 72 | return cost; 73 | } 74 | 75 | static double cost_pw_infi(double newX1, double newY1, double newX2, double newY2, 76 | double newOcc, double newEmg, 77 | double oldX1, double oldY1, double oldX2, double oldY2, 78 | double oldOcc, double oldEmg) 79 | { 80 | int dp_min_time_occluded = 25; 81 | int oldTime = round(oldY2); 82 | int newTime = round(newY2); 83 | 84 | if(!OCCLUDED(newX1) && OCCLUDED(oldX1)) 85 | { 86 | // leaving occlusion 87 | if(oldTime >= dp_min_time_occluded && newEmg > .5) 88 | return 0; 89 | else 90 | return INF; 91 | } 92 | else if(OCCLUDED(newX1) && !OCCLUDED(oldX1)) 93 | { 94 | // moving into occlusion 95 | if(newTime == 0 && oldOcc > .5) 96 | return 0; 97 | else 98 | return INF; 99 | } 100 | else if(OCCLUDED(oldX1)) 101 | { 102 | // staying in occlusion 103 | if(oldTime + 1 == newTime || (newTime == oldTime && newTime >= dp_min_time_occluded)) 104 | return 0.0; 105 | else 106 | return INF; 107 | } 108 | else 109 | { 110 | // staying visible 111 | //double maxDist = 25; 112 | //double cost_pw = sqrt(cost_pw_corner(newX1, newY1, newX2, newY2, 113 | // oldX1, oldY1, oldX2, oldY2)); 114 | //if(cost_pw > maxDist) 115 | // return INF; 116 | // else 117 | // return 0.0; 118 | 119 | double o = rect_overlap(newX1, newY1, newX2, newY2, 120 | oldX1, oldY1, oldX2, oldY2); 121 | if(o > .25) 122 | return 0.0; 123 | else 124 | return INF; 125 | } 126 | } 127 | 128 | static void do_dynprog_chain(int newStates_count,int oldStates_count, 129 | double*new_states,uint32_t*bps, 130 | double*old_states,double*new_dets,double*projRects) 131 | { 132 | // relax each edge 133 | for(int newIter = 0; newIter < newStates_count; newIter++) 134 | { 135 | // extract the new state 136 | double newX1 = *(new_states + newStates_count*0 + newIter); 137 | double newY1 = *(new_states + newStates_count*1 + newIter); 138 | double newX2 = *(new_states + newStates_count*2 + newIter); 139 | double newY2 = *(new_states + newStates_count*3 + newIter); 140 | double newCost = *(new_states + newStates_count*4 + newIter); 141 | // extract the corresponding detection 142 | double detX1 = *(new_dets + newStates_count*0 + newIter); 143 | double detY1 = *(new_dets + newStates_count*1 + newIter); 144 | double detX2 = *(new_dets + newStates_count*2 + newIter); 145 | double detY2 = *(new_dets + newStates_count*3 + newIter); 146 | double detResp = *(new_dets + newStates_count*4 + newIter); 147 | double detOcc = *(new_dets + newStates_count*5 + newIter); 148 | double detEmg = *(new_dets + newStates_count*6 + newIter); 149 | // extract the back pointer 150 | uint32_t*backPtr = &bps[newIter]; 151 | 152 | for(int oldIter = 0; oldIter < oldStates_count; oldIter++) 153 | { 154 | // extract the old state 155 | double oldX1 = *(old_states + oldStates_count*0 + oldIter); 156 | double oldY1 = *(old_states + oldStates_count*1 + oldIter); 157 | double oldX2 = *(old_states + oldStates_count*2 + oldIter); 158 | double oldY2 = *(old_states + oldStates_count*3 + oldIter); 159 | double oldCost = *(old_states + oldStates_count*4 + oldIter); 160 | double oldOcc = *(old_states + oldStates_count*5 + oldIter); 161 | double oldEmg = *(old_states + oldStates_count*6 + oldIter); 162 | if(isnan(oldCost)) 163 | continue; 164 | // extract the old LK Projection 165 | double projX1 = *(projRects + (oldStates_count)*0 + oldIter); 166 | double projY1 = *(projRects + (oldStates_count)*1 + oldIter); 167 | double projX2 = *(projRects + (oldStates_count)*2 + oldIter); 168 | double projY2 = *(projRects + (oldStates_count)*3 + oldIter); 169 | 170 | // compute the cost 171 | double lcl_cost = -detResp; 172 | //double corner_cost = cost_pw_corner(detX1, detY1, detX2, detY2, 173 | // projX1, projY1, projX2, projY2); 174 | double pw_cost = cost_pw_infi(detX1, detY1, detX2, detY2, detOcc, detEmg, 175 | projX1, projY1, projX2, projY2, oldOcc, oldEmg); 176 | double cost = lcl_cost + pw_cost + oldCost; 177 | 178 | // relax 179 | if(cost <= newCost) 180 | { 181 | //mexPrintf("allowing connection from: %f %f %f %f\n",oldX1,oldY1,oldX2,oldY2); 182 | //mexPrintf("\t to: %f %f %f %f\n",detX1,detY1,detX2,detY2); 183 | //mexPrintf("\tcorner_cost = %f\n",corner_cost); 184 | //mexPrintf("\t pwCost = %f\n",pw_cost); 185 | newCost = *(new_states + newStates_count*4 + newIter) = cost; 186 | *backPtr = (uint32_t)(oldIter+1); 187 | } 188 | } 189 | } 190 | } 191 | 192 | // do dynamic programming on a markov chain. 193 | // [states,bp] = dynprog_chain(states,projRects,new_detections); 194 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 195 | { 196 | // check arguments 197 | if (nrhs != 3) 198 | mexErrMsgTxt("usage: [states,bp] = dynprog_chain(states,oldRects,new_detections)"); 199 | if (nlhs != 2) 200 | mexErrMsgTxt("usage: [states,bp] = dynprog_chain(states,oldRects,new_detections)"); 201 | if (mxIsDouble(prhs[0]) == false) mexErrMsgTxt("states is not double."); 202 | if (mxIsDouble(prhs[1]) == false) mexErrMsgTxt("projRects is not double."); 203 | if (mxIsDouble(prhs[2]) == false) mexErrMsgTxt("new_detections is not double."); 204 | 205 | // get sizes 206 | mwSize newStates_count = mxGetM(prhs[2]); 207 | mwSize oldStates_count = mxGetM(prhs[0]); 208 | 209 | // init the output matrices 210 | plhs[0] = mxCreateDoubleMatrix(newStates_count,5,mxREAL); 211 | plhs[1] = mxCreateNumericMatrix(newStates_count,1,mxUINT32_CLASS,mxREAL); 212 | 213 | // get out ptrs 214 | double *new_states = mxGetPr(plhs[0]); // 5 column 215 | uint32_t*bps = (uint32_t*)mxGetData(plhs[1]); 216 | // get in ptrs 217 | double *old_states = mxGetPr(prhs[0]); // 5 column 218 | double *new_dets = mxGetPr(prhs[2]); // 5 column 219 | double *projRects = mxGetPr(prhs[1]); // 4 column 220 | 221 | // init the outputs to defautl values 222 | for(int newIter = 0; newIter < newStates_count; newIter++) 223 | { 224 | *(new_states + newStates_count*0 + newIter) = *(new_dets + newStates_count*0 + newIter); 225 | *(new_states + newStates_count*1 + newIter) = *(new_dets + newStates_count*1 + newIter); 226 | *(new_states + newStates_count*2 + newIter) = *(new_dets + newStates_count*2 + newIter); 227 | *(new_states + newStates_count*3 + newIter) = *(new_dets + newStates_count*3 + newIter); 228 | *(new_states + newStates_count*4 + newIter) = INF; 229 | } 230 | for(int bIter = 0; bIter < newStates_count; bIter++) 231 | bps[bIter] = 0; 232 | 233 | // now we can actually do some dynamic programming? 234 | do_dynprog_chain(newStates_count,oldStates_count, 235 | new_states,bps, 236 | old_states,new_dets,projRects); 237 | } 238 | 239 | -------------------------------------------------------------------------------- /track_dp/track_dp.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-14 2 | % Dynamic Programming Motion Model for HoG-SVM 3 | % based tracker. 4 | % old_boxes : [0 0 0 0 0] if we don't know the position for the 5 | % frame otherwise we put [x y w h r]. 6 | % track_dp(vidName,model,old_boxes,weights) 7 | function [trajectory,model,f1,backPtrs,track_forward] = track_dp(varargin) 8 | tracker = DPTracker; 9 | [trajectory,model,f1,backPtrs,track_forward] = tracker.track_dp(varargin{:}); 10 | end 11 | -------------------------------------------------------------------------------- /track_dp/track_dp_backward.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-14 2 | % backwards pass of a dynamic program 3 | function boxes = track_dp_backward(vidName,backPtrs,show) 4 | if nargin < 3 5 | show = 1; 6 | end 7 | 8 | % find the index of the least cost bb 9 | bbs = backPtrs{numel(backPtrs)}.boxes; 10 | ptrs= backPtrs{numel(backPtrs)}.bPtr; 11 | [void,idx] = min(bbs(:,5)); 12 | assert(idx > 0); 13 | k_gts = rectBtoK(gt_load(vidName)); % so we can live plot f1 score 14 | 15 | % init the output... 16 | boxes = zeros(numel(backPtrs),5); 17 | backBox = backPtrs{numel(backPtrs)}.boxes(idx,:); 18 | boxes(end,:) = backBox(:,1:size(boxes,2)); 19 | scorer = track_scorer(); 20 | 21 | % backwards pass 22 | for frameIter = (numel(backPtrs)-1):-1:0 23 | % 24 | fprintf('\n Dynamic Program Backward %d of %d',frameIter,numel(backPtrs)); 25 | 26 | % current frame info... 27 | bbs = backPtrs{frameIter+1}.boxes; 28 | ptrs= backPtrs{frameIter+1}.bPtr; 29 | 30 | % walk back 31 | bb = bbs(idx,:); 32 | if numel(ptrs) == 1 33 | idx = ptrs(1); 34 | else 35 | idx = ptrs(idx,:); 36 | end 37 | assert(idx > 0 || isnan(idx)); 38 | 39 | % yield it! 40 | boxes(frameIter+1,:) = bb(:,1:size(boxes,2)); 41 | % plot 42 | scorer = scorer.put(k_gts(frameIter+1,:),bb); 43 | if show 44 | showBox(get_frame(vidName,frameIter),bb); 45 | f1 = scorer.score(); 46 | xlabel(['f1 = ' num2str(f1)]); 47 | drawnow; 48 | end 49 | 50 | if isnan(idx) 51 | break; 52 | end 53 | end 54 | fprintf('\n\n') 55 | end 56 | -------------------------------------------------------------------------------- /track_dp/track_dp_forward.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-14 2 | % old_boxes contains information we assume about the trajectory. 3 | % If we don't know the location of an object at a point of time, 4 | % we set that row of old_boxes to [0 0 0 0 0]. 5 | function [boxes,detections,backPtrs] = track_dp_forward(vidName, ... 6 | model,gts, ... 7 | old_boxes,weights) 8 | if nargin < 2 9 | model = Model('gen',vidName,[],[],[0]); 10 | end 11 | if nargin < 3 12 | gts = rectBtoK(gt_load(vidName)); 13 | end 14 | if nargin < 4 15 | old_boxes = []; 16 | end 17 | if nargin < 5 18 | weights = []; 19 | end 20 | 21 | tracker = DPTracker; 22 | [boxes,detections,backPtrs] = tracker.forward(vidName,model,gts,old_boxes,weights); 23 | end 24 | -------------------------------------------------------------------------------- /track_dp/track_dp_forward_augment_states.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012.5.10 2 | % new_detections : the states detected in the current frame 3 | % detections : the states in the previous frame. 4 | function new_detections = track_dp_forward_augment_states(model, ... 5 | new_detections,detections,vidName,frameIter) 6 | %fprintf('+track_dp_forward_augment_states\n'); 7 | assert(isscalar(frameIter)); 8 | imM = get_frame(vidName,frameIter-1); 9 | imN = get_frame(vidName,frameIter); 10 | 11 | % HERE BE DRAGONS (PARAMS) 12 | % add the occluded state 13 | % OCC_COST = cfg('hog_svm/occlusion_cost'); 14 | OCC_COST = model.occ_thresh(); 15 | % generate occlusion states 16 | new_detections = track_dp_gen_occlusions... 17 | (detections,new_detections,cfg('dp_min_time_occluded'),OCC_COST); 18 | 19 | % generate the LK tracked state... 20 | visibleDetections = ... 21 | detections(find(~gt_occluded(detections)),:); 22 | % shrink scales are only required for detections. 23 | visibleDetections = flipdim(nms(visibleDetections,.75,model.getScaleX(),model.getScaleY()),1); 24 | lkImax = min(5,size(visibleDetections,1)); 25 | for lkI = 1:lkImax 26 | %fprintf('track_dp_forward_augment_states: LK State %d\n',... 27 | % lkI); 28 | if lkI > size(visibleDetections,1) 29 | break; 30 | end 31 | best_det = visibleDetections(lkI,:); 32 | if cfg('use_lk') 33 | % it seems my implementation is quite slow... 34 | %[lk_rect,failed] = LucasKanade(best_det(1:4),imM,imN,0,0); % Use *my* implementation 35 | lk_rect = tldTracking(best_det',imM,imN)'; 36 | lk_rect = rect_correct_aspect(lk_rect,model.getAspect()); 37 | else 38 | lk_rect = best_det(:,1:4); 39 | end 40 | %fprintf('track_dp_forward_augment_states: LK Projection Complete\n'); 41 | 42 | % add LK state with score and occ prob. 43 | lk_out_of_frame = rect_overlap(lk_rect,[0 0 size(imM,2) size(imN,1)]) <= 0; 44 | imsz = rect_size(rect_image(imN)); 45 | dtsz = rect_size(lk_rect); 46 | lk_too_large = any(dtsz >= imsz); 47 | if lk_out_of_frame || lk_too_large 48 | %new_detections = [new_detections; NaN NaN NaN NaN -OCC_COST]; 49 | else 50 | %fprintf('track_dp_forward_augment_states: computing poc\n'); 51 | poc = 1; 52 | %fprintf('track_dp_forward_augment_states: computing poe\n'); 53 | poe = 1; 54 | %fprintf('track_dp_forward_augment_states: lk score computing\n'); 55 | lk_score = model.score_box(imN,lk_rect); 56 | %fprintf('track_dp_forward_augment_states: appending result\n'); 57 | new_detections = [new_detections; ... 58 | lk_rect lk_score ... 59 | poc poe]; 60 | %fprintf('track_dp_forward_augment_states: iteration complete\n'); 61 | end 62 | end 63 | %fprintf('-track_dp_forward_augment_states\n'); 64 | end 65 | -------------------------------------------------------------------------------- /track_dp/track_dp_forward_one.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-10 2 | % one forward step of the dynamic program for tracking. 3 | % one iteration of the dynamic program forward pass 4 | % states = states from the previous frame 5 | % (:,5) = responce = -cost 6 | % new_detections = detections in the current frame 7 | % (:,5) = cost = -response 8 | % imM, imN = the previous and current frames, respectively. 9 | % NStates = the number of states 10 | % (Number of Detections + Occluded + LK State) 11 | function [states,backPtrs,states_unsorted] = track_dp_forward_one... 12 | (states, new_detections,imM,imN,~,backPtrs) 13 | %fprintf('+track_dp_forward_one\n'); 14 | % predict bbs 15 | oldRects = track_dp_forward_one_predict_rects(states,imM,imN); 16 | 17 | % if all equal inf, all are equally likely. 18 | if all(states(:,5) == inf) 19 | states(:,5) = 0; 20 | end 21 | 22 | % disable occ/emrg constraints 23 | % new_detections(:,6:7) = 1; 24 | 25 | oldRects = cell2mat(oldRects'); 26 | oldRects = oldRects(:,1:4); 27 | %keyboard; 28 | assert(size(new_detections,2) >= 7); 29 | assert(size(states,2) >= 7); 30 | [states,bp] = dynprog_chain(states,oldRects,new_detections); 31 | states = [states(:,1:5) new_detections(:,6:end)]; 32 | %keyboard; 33 | 34 | % update the backptrs for a backwards pass if required. 35 | states_unsorted = states; 36 | [states,dIdx] = sortrows(states,5); 37 | if nargin >= 6 38 | backPtrs{end+1} = ... 39 | struct('boxes',states,'bPtr',bp(dIdx)); 40 | else 41 | backPtrs = []; 42 | end 43 | 44 | %fprintf('-track_dp_forward_one\n'); 45 | end 46 | 47 | function oldRects = track_dp_forward_one_predict_rects(states,imM,imN) 48 | %fprintf('+track_dp_forward_one_predict_rects\n'); 49 | % compute the flows for each old rect 50 | oldRects = {}; 51 | parfor oldIter = 1:size(states,1) 52 | oldRect = states(oldIter,1:4); 53 | 54 | if ~gt_occluded(oldRect) 55 | if cfg('use_lk') 56 | %Use LK CRF 57 | projection = tldTracking(oldRect',imM,imN)'; 58 | if gt_occluded(projection) 59 | % LK failed 60 | projection = oldRect; 61 | end 62 | else 63 | % use use MRF. 64 | projection = oldRect; 65 | end 66 | 67 | % only use LK if it doens't fail. 68 | if ~gt_occluded(projection) 69 | oldRect = projection; 70 | end 71 | end 72 | oldRects{oldIter} = oldRect; 73 | end 74 | %fprintf('-track_dp_forward_one_predict_rects\n'); 75 | end 76 | 77 | -------------------------------------------------------------------------------- /track_dp/track_dp_gen_occlusions.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-6-5 Genreate occluded states for a DP tracker 2 | % stash the time occluded in the 4th element. 3 | function [boxes] = track_dp_gen_occlusions(states,boxes,max_occlusions,occ_cost) 4 | numStates = size(states,1); 5 | for stateIter = 1:numStates 6 | curState = states(stateIter,:); 7 | if gt_occluded(curState) 8 | occlusionTime = curState(:,4); 9 | curState(:,4) = occlusionTime + 1; 10 | curState(:,5) = occ_cost; 11 | if occlusionTime <= max_occlusions 12 | boxes(end+1,:) = nan(size(boxes(end,:))); 13 | boxes(end,1:size(curState,2)) = curState; 14 | end 15 | end 16 | end 17 | boxExtraData = size(boxes,2) - 5; 18 | boxes = [boxes; nan(1,3) 0 occ_cost nan(1,boxExtraData)]; 19 | %keyboard; 20 | end 21 | -------------------------------------------------------------------------------- /track_dp/track_dp_init.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.5.14 2 | % Setup the data structures for a dynamic program tracker 3 | function [NDetStates,NStates,detections,boxes,backPtrs] = ... 4 | track_dp_init(k_gts,extraStates) 5 | if nargin < 2 6 | extraStates = 2; 7 | end 8 | 9 | NDetStates = 25; 10 | NStates = NDetStates + extraStates; % Occluded State and LK Projected State 11 | detections = repmat([k_gts(1,:) 0 0 0],NStates,1); 12 | 13 | boxes = [k_gts(1,1:4), inf]; 14 | backPtrs = {struct('boxes',detections,'bPtr',nan)}; 15 | %backPtrs = {struct('boxes',detections,'bPtr',NaN(NStates,1))}; 16 | end 17 | -------------------------------------------------------------------------------- /track_dp/track_dp_lcl.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-15 2 | % get the local score weight 3 | function L = track_dp_lcl() 4 | % HERE BE DRAGONS (paramters) 5 | global GBL_PARM_TRACK_DP_L; 6 | if isempty(GBL_PARM_TRACK_DP_L) 7 | %L = 15625; 8 | L = cfg('cost_dp_lcl'); 9 | %L = 625; 10 | else 11 | L = GBL_PARM_TRACK_DP_L; 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /trackers/track_offline.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.8.6 2 | % Track Online 3 | function [k_track,f1s] = track_offline(vidName) 4 | % DP Track until we find enough new data to learn, then learn 5 | % and track. 6 | model = genModel(vidName); 7 | [k_track,~,f1s,~,~] = track_dp(vidName,model); % DP-online 8 | tracks = {k_track}; 9 | lambda = zeros(vidLen(vidName),1); 10 | lambda(1) = 1; 11 | 12 | % run the offline algorithm 13 | batch_count = 6; 14 | for iter = 1:batch_count 15 | % SELECT:A 16 | last_lambda = lambda; 17 | % remove retained *NEW* occlusions. 18 | if iter > 1 19 | retained = last_lambda & lambda; 20 | ret_occ = retained & ... 21 | gt_occluded(tracks{end}) & ... 22 | ~gt_occluded(tracks{end-1}); 23 | fprintf('select purne: removing %d retained occlusions\n',sum(lambda(ret_occ))); 24 | lambda(ret_occ) = 0; 25 | end 26 | % SELECT: B 27 | % how much should we add? 28 | total_ct = .5 .* vidLen(vidName); 29 | b = nthroot(total_ct,batch_count); 30 | cur_ct = clamp(1,round(b.^iter),total_ct); 31 | fprintf('will select %d frames\n',cur_ct); 32 | % add that many 33 | deltas = compute_tsvm_deltas(vidName,model,k_track); 34 | [~,addI] = sort(deltas); 35 | lambda = zeros(vidLen(vidName),1); 36 | lambda(1) = 1; % never drop the first frame 37 | lambda(addI(1:ceil(cur_ct))) = 1; 38 | % SELECT: C 39 | % remove excessive drift 40 | if iter > 1 41 | retained = last_lambda; 42 | for frameIter = (find(retained)-1)' 43 | k_old = tracks{end-1}(frameIter+1,:); 44 | k_new = tracks{end}(frameIter+1,:); 45 | if rect_overlap(k_old,k_new) < .95 46 | fprintf('select_prune: to much drift to retain\n'); 47 | obj.lambda(frameIter+1) = 0; 48 | end 49 | end 50 | end 51 | 52 | % learn 53 | model = Model('gen',vidName,[],[],[]); 54 | model = model.train_all(vidName,k_track,lambda); 55 | 56 | % track 57 | [k_track,~,f1,~] = track_dp(vidName,model); % DP-offline 58 | tracks{end+1} = k_track; 59 | f1s = [f1s f1]; 60 | end 61 | 62 | % show the f1s. 63 | f1s = f1s 64 | end 65 | 66 | 67 | -------------------------------------------------------------------------------- /trackers/track_online.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.8.6 2 | % Track Online 3 | function [k_track,f1s] = track_online(vidName) 4 | % DP Track until we find enough new data to learn, then learn 5 | % and track. 6 | model = genModel(vidName); 7 | [~,~,f1s,~,k_track] = track_dp(vidName,model); % DP-online 8 | k_track2 = k_track; 9 | 10 | % wait until we've seen enough to learn... 11 | for frameIter = 0:size(k_track,1)-1 12 | fprintf('track_olol %d of %d\n',frameIter,size(k_track,1)); 13 | 14 | % See if we are ready to update w. 15 | [f,e] = log2(frameIter); 16 | powOf2 = f == .5; 17 | if powOf2 && frameIter >= 4 18 | % select 19 | deltas = compute_tsvm_deltas(vidName,model,k_track2(1:frameIter+1,:)); 20 | [~,addI] = sort(deltas); 21 | lambda = zeros(vidLen(vidName),1); 22 | lambda(addI(1:ceil(.50.*frameIter))) = 1; 23 | 24 | % learn 25 | fprintf('track_olol: learning\n'); 26 | model = Model('gen',vidName,[],[],[]); 27 | model = model.train_all(vidName,k_track2,lambda); 28 | 29 | % track 30 | [~,~,f1,~,k_track2] = track_dp(vidName,model); % DP-online 31 | f1s = [f1s f1]; 32 | k_track(frameIter+1:end,:) = k_track2(frameIter+1:end,:); 33 | end 34 | end 35 | 36 | % show the f1s. 37 | f1s = f1s 38 | end 39 | 40 | -------------------------------------------------------------------------------- /trackers/track_tbd.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012-6-13 2 | % simple track by detection algorithm. 3 | function [track,model,f1] = track_tbd(vidName,model) 4 | matlab_init(vidName); 5 | % init paths, prngs, mex etc. etc. 6 | gts = rectBtoK(gt_load(vidName)); 7 | imM = get_frame(vidName,0); 8 | if nargin < 2 || isempty(model) 9 | model = Model('gen',vidName,[],[],[0]); 10 | end 11 | track = []; 12 | NDetStates = 5; 13 | showModel(model.w); 14 | top_detections = model.detect_all(size(gts,1),vidName,NDetStates); 15 | 16 | scorer = track_scorer(); 17 | for frameIter = 0:(size(gts,1)-1) 18 | imN = get_frame(vidName,frameIter); 19 | top_dets = [top_detections{frameIter+1}; nan(1,4) -1 1 1]; 20 | %keyboard; 21 | top_dets = flipdim(sortrows(top_dets,5),1); 22 | top_det = top_dets(1,:); 23 | showBoxes(imN,top_detections{frameIter+1}); 24 | track(end+1,:) = top_det; 25 | 26 | % show the score 27 | scorer = scorer.put(gts(frameIter+1,:),top_det); 28 | f1 = scorer.score(); 29 | xlabel(['f1 = ' num2str(f1)]); 30 | drawnow; 31 | end 32 | 33 | [p,r] = plot_resp(rectKtoB(gts),track,vidName); 34 | f1 = f1score(p,r) 35 | end 36 | -------------------------------------------------------------------------------- /video/clamp.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-13 2 | % restrict a value to a range... 3 | function val = clamp(var_min,val,var_max) 4 | val = max(var_min,val); 5 | val = min(var_max,val); 6 | end 7 | -------------------------------------------------------------------------------- /video/f1score.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-03-20 2 | function f1 = f1score(prec,recl) 3 | f1 = 2*prec*recl/(prec+recl); 4 | end 5 | -------------------------------------------------------------------------------- /video/get_frame.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-06 2 | % function to grab a frame from a video 3 | % frame zero is the first frame. 4 | function [im,filename] = get_frame(vidName,frameNum) 5 | % get the frames filename 6 | global G_HOME; 7 | persistent firstFrame lastFrame lastVidName; 8 | if isempty(firstFrame) || ~strcmp(vidName,lastVidName) 9 | [firstFrame,lastFrame] = get_vid_range(vidName); 10 | lastVidName = vidName; 11 | end 12 | frameNum = frameNum + firstFrame; 13 | 14 | % debug 15 | assert(frameNum <= lastFrame); 16 | 17 | % read the image 18 | filename = sprintf('%s%s/imgs/img%.5d.png', ... 19 | datapath(),vidName,frameNum); 20 | im = imrgb(imread(filename)); 21 | end 22 | -------------------------------------------------------------------------------- /video/get_vid_range.m: -------------------------------------------------------------------------------- 1 | % JSS3 - 2012.8.27 2 | % return the first and last frame to use for a labeled video. 3 | function [first,last] = get_vid_range(vidName) 4 | frames_filename = sprintf('%s%s/%s_frames.txt', ... 5 | datapath(),vidName,vidName); 6 | framesData = csvread(frames_filename); 7 | first = framesData(1); 8 | last = framesData(2); 9 | end 10 | -------------------------------------------------------------------------------- /video/gt_load.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-06 2 | % function to load the gt for a video. 3 | % format should be 1 gt per row 4 | % each row should be [x1 y1 w h] 5 | function gts = gt_load(vidName) 6 | % prep the gt 7 | gt_file = [datapath() vidName '/' vidName ... 8 | '_gt.txt']; 9 | gts = importdata(gt_file); 10 | 11 | % pad handle short gts. 12 | [first,last] = get_vid_range(vidName); 13 | pad = (last - first + 1) - size(gts,1); 14 | gts = [gts; zeros(pad,size(gts,2))]; 15 | 16 | % handle Kalal [x1 y1 x2 y2] format files. 17 | if exist(['~/workspace/data/tracking/' vidName '/kalal'],'file') 18 | %'kalal format gt' 19 | gts = rectKtoB(gts); 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /video/gt_occluded.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-03-20 2 | % JSS3 2012-5-14 extended to support multiple inputs. 3 | % Function to tell if a gt matrix is valid 4 | function occluded = gt_occluded(gt) 5 | % only examine the first four elements 6 | gt = gt(:,1:4); 7 | 8 | % check for nan 9 | occluded = zeros(size(gt,1),1); 10 | 11 | % nan => occlusion 12 | occluded = occluded | any(isnan(gt),2); 13 | end 14 | 15 | -------------------------------------------------------------------------------- /video/gt_valid.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-03-20 2 | % JSS3 2012-5-14 : added support for multiple ground truths 3 | % Function to tell if a gt matrix is valid 4 | function valid = gt_valid(gt) 5 | valid = ones(size(gt,1),1); 6 | 7 | % check for bad size 8 | if(size(gt,2) < 4) 9 | valid = zeros(size(gt,1),1); 10 | return; 11 | end 12 | 13 | % check for all zero 14 | valid = valid & any(gt ~= 0,2); 15 | end 16 | -------------------------------------------------------------------------------- /video/hashMat.cc: -------------------------------------------------------------------------------- 1 | // JSS3 2012-5-29 2 | // fast hash using OpenSSL 3 | 4 | #include "mex.h" 5 | #include 6 | 7 | typedef unsigned char uchar; 8 | 9 | // hash = hashMat(mat); 10 | void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 11 | { 12 | // check args 13 | if(nrhs != 1 || nlhs != 1) 14 | mexErrMsgTxt("syntax: hash = hashMat(mat)"); 15 | 16 | // get data 17 | // mxGetData 18 | void * data = mxGetData(prhs[0]); 19 | // mxGetNumberOfElements 20 | size_t numel = mxGetNumberOfElements(prhs[0]); 21 | // mxGetElementSize 22 | size_t elSz = mxGetElementSize(prhs[0]); 23 | 24 | // compute hash 25 | uchar hash[MD5_DIGEST_LENGTH+1/*in bytes*/]; 26 | MD5((uchar*)data,elSz*numel,(uchar*)hash); 27 | hash[MD5_DIGEST_LENGTH] = 0; 28 | 29 | // extract hash to string 30 | // 1 8-bit byte 31 | // 4 bits per hex char. 32 | char hashString[2*MD5_DIGEST_LENGTH+1]; 33 | for(int iter = 0; iter < MD5_DIGEST_LENGTH; iter++) 34 | { 35 | snprintf(hashString+2*iter,3,"%02x",hash[iter]); 36 | //mexPrintf("hash[iter] = %02x\n",hash[iter]); 37 | //mexPrintf("hashString = %s\n",hashString); 38 | } 39 | hashString[2*MD5_DIGEST_LENGTH] = 0; 40 | 41 | // return 42 | plhs[0] = mxCreateString(hashString); 43 | } 44 | -------------------------------------------------------------------------------- /video/imcropr.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-25 2 | % simple crop with replication to maintain size... 3 | function IC = imcropr(I,k_cr) 4 | % validate that the input is of resonable size... 5 | imsz = rect_size(rect_image(I)); 6 | bbsz = rect_size(k_cr); 7 | if any(bbsz > 2.*imsz) 8 | warning('failed to crop image due to size error'); 9 | % return an invalid crop for something to massive 10 | % (trying to compute the massive crop would result in out 11 | % of memory crashes). 12 | IC = []; 13 | return; 14 | end 15 | 16 | % extract stats 17 | iSize = size(I); 18 | i_h = iSize(1); 19 | i_w = iSize(2); 20 | 21 | % find the padding 22 | pad_t = round(max(0,0-k_cr(2))); 23 | pad_b = round(max(0,k_cr(4)-i_h)); 24 | pad_l = round(max(0,0-k_cr(1))); 25 | pad_r = round(max(0,k_cr(2)-i_w)); 26 | 27 | % do the crop! 28 | IC = imcrop(I,rectKtoB(k_cr)); 29 | IC = padarray(IC,[pad_t pad_l],'replicate','pre'); 30 | IC = padarray(IC,[pad_b pad_r],'replicate','post'); 31 | end 32 | -------------------------------------------------------------------------------- /video/imgray.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-11 2 | % color to grayscale. 3 | function im2 = imgray(im) 4 | [H,W,D] = size(im); 5 | if D == 3 6 | im2 = mean(im,3); 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /video/imrgb.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-06 2 | % function to make rgb or grayscale image rgb. 3 | function im = imrgb(im) 4 | [H,W,D] = size(im); 5 | if D == 1 6 | % we need to duplicate channels 7 | im(:,:,2) = im(:,:,1); 8 | im(:,:,3) = im(:,:,1); 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /video/score_track_file.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-25 2 | % load a track file and return it's f1 score 3 | function [f1,p,r,displacement,OR_OCC,acc] = score_track_file(vidName,trackFile,interpolate_occlusion) 4 | % default args 5 | if nargin < 3 6 | interpolate_occlusion = 0; 7 | end 8 | 9 | % memoize 10 | memo = [cfg('tmp_dir') 'score_track_file_' ... 11 | vidName '-' ... 12 | hashMat(trackFile) '-' ... 13 | num2str(interpolate_occlusion) '.mat']; 14 | if exist(memo,'file') 15 | load(memo); 16 | return; 17 | end 18 | 19 | % get the track data 20 | if ischar(trackFile) 21 | S = load(trackFile); 22 | if isstruct(S) 23 | % .mat files load struct 24 | k_track = S.track; 25 | else 26 | % .csv files load a mat 27 | k_track = S; 28 | end 29 | else 30 | k_track = trackFile; 31 | end 32 | % do we need to interpolate occlusions? 33 | if nargin > 2 && interpolate_occlusion 34 | fprintf('interpolating occlusion\n'); 35 | %keyboard; 36 | k_track = interp_occ(k_track); 37 | end 38 | 39 | % load the ground truth. 40 | k_gts = rectBtoK(gt_load(vidName)); 41 | 42 | % check the sizes 43 | if(size(k_track,1) ~= size(k_gts,1)) 44 | fprintf('%d ~= %d\n',size(k_track,1),size(k_gts,1)); 45 | warning('score_track_file: length mismatch'); 46 | end 47 | 48 | % score the track 49 | scorer = track_scorer(); 50 | to = min(vidLen(vidName)-1,size(k_track,1)-1); 51 | for frameIter = 0:to 52 | scorer = scorer.put(k_gts(frameIter+1,:),... 53 | k_track(frameIter+1,:)); 54 | end 55 | [f1,p,r,displacement,OR_OCC,acc] = scorer.score(); 56 | 57 | % cache the results 58 | save(memo,'f1','p','r','displacement','OR_OCC','acc'); 59 | end 60 | -------------------------------------------------------------------------------- /video/score_track_one.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-04-06 2 | % update the counts for the p/r calcuation 3 | function [l, c, g, n] = score_track_one(b_gt,k_box,thresh) 4 | if nargin < 3 5 | thresh = cfg('correct_overlap'); 6 | end 7 | 8 | % correctly accepted 9 | c = zeros(size(k_box,1),1); 10 | % ground truth accepted 11 | g = 0; 12 | % accepted by tracker 13 | n = zeros(size(k_box,1),1); 14 | % is the frame labeled? 15 | l = 0; 16 | 17 | % ignore frames without a ground truth 18 | if ~gt_valid(b_gt) 19 | return; 20 | end 21 | l = 1; 22 | 23 | % did the b_gt accept the frame? 24 | if(~gt_occluded(b_gt)) 25 | g = 1; 26 | end 27 | 28 | % did the tracker accept the frame? 29 | n = ~gt_occluded(k_box); 30 | 31 | % was the acceptence correct? 32 | overlaps = rect_overlap(k_box,rectBtoK(b_gt)); 33 | c = ~gt_occluded(b_gt) & ~gt_occluded(k_box) & overlaps > thresh; 34 | end 35 | -------------------------------------------------------------------------------- /video/track_scorer.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-23 2 | % this is a class to simplify the scoring of tracks in MATLAB 3 | classdef track_scorer 4 | properties (SetAccess = private) 5 | % precision = correctly accepted / number accepted 6 | % recall = correctly accepted / gt accepted 7 | cAccept = 0; 8 | gAccept = 0; 9 | nAccept = 0; 10 | % displacement score info. 11 | agg_displacement = 0; 12 | N = 0; 13 | OR_OCC = 0; 14 | % simple accuracy 15 | total_counted = 0; 16 | total_correct = 0; 17 | end 18 | 19 | % ctor 20 | %function scorer = track_scorer() 21 | %end 22 | methods 23 | function scorer = put(scorer,k_gt,k_loc) 24 | if ~gt_valid(k_gt) 25 | return; 26 | end 27 | 28 | % update f1 29 | [l,c,g,n] = score_track_one(rectKtoB(k_gt),k_loc); 30 | scorer.cAccept = scorer.cAccept + c; 31 | scorer.gAccept = scorer.gAccept + g; 32 | scorer.nAccept = scorer.nAccept + n; 33 | 34 | % update displacement error (only meaning without occ) 35 | if ~gt_occluded(k_gt) && ~gt_occluded(k_loc) 36 | scorer.N = scorer.N + 1; 37 | cen_gt = rect_center(k_gt); 38 | cen_lc = rect_center(k_loc); 39 | newDist = pdist2(cen_gt,cen_lc); 40 | assert(~isnan(newDist)); 41 | scorer.agg_displacement = scorer.agg_displacement + ... 42 | newDist; 43 | else 44 | % something signals occlusion. 45 | scorer.OR_OCC = scorer.OR_OCC + 1; 46 | end 47 | 48 | % update total correct 49 | scorer.total_counted = scorer.total_counted + 1; 50 | if gt_occluded(k_gt) && gt_occluded(k_loc) 51 | scorer.total_correct = scorer.total_correct + 1; 52 | elseif ~gt_occluded(k_gt) && ~gt_occluded(k_loc) && ... 53 | rect_overlap(k_gt,k_loc) > cfg('correct_overlap') 54 | scorer.total_correct = scorer.total_correct + 1; 55 | end 56 | end 57 | 58 | function [f1,p,r,displacement,OR_OCC,acc] = score(scorer) 59 | p = scorer.cAccept/scorer.nAccept; 60 | r = scorer.cAccept/scorer.gAccept; 61 | f1 = f1score(p,r); 62 | displacement = scorer.agg_displacement ./ scorer.N; 63 | OR_OCC = scorer.OR_OCC; 64 | acc = scorer.total_correct./scorer.total_counted; 65 | end 66 | end 67 | end 68 | -------------------------------------------------------------------------------- /video/vidLen.m: -------------------------------------------------------------------------------- 1 | % JSS3 2012-5-18 2 | % Return the length of the named video 3 | function len = vidLen(vidName) 4 | gt = gt_load(vidName); 5 | len = size(gt,1); 6 | end 7 | --------------------------------------------------------------------------------