sustaining_gazes/matlab_version/face_detection/face_detection_zhu/face-release1.0-basic/detect.m

172 lines
5.0 KiB
Matlab

function boxes = detect(input, model, thresh)
% Keep track of detected boxes and features
BOXCACHESIZE = 100000;
cnt = 0;
boxes.s = 0;
boxes.c = 0;
boxes.xy = 0;
boxes.level = 0;
boxes(BOXCACHESIZE) = boxes;
% Compute the feature pyramid and prepare filters
pyra = featpyramid(input,model);
[components,filters,resp] = modelcomponents(model,pyra);
for c = randperm(length(components)),
minlevel = model.interval+1;
levels = minlevel:length(pyra.feat);
for rlevel = levels(randperm(length(levels))),
parts = components{c};
numparts = length(parts);
% Local part scores
for k = 1:numparts,
f = parts(k).filterid;
level = rlevel-parts(k).scale*model.interval;
if isempty(resp{level}),
resp{level} = fconv(pyra.feat{level},filters,1,length(filters));
end
parts(k).score = resp{level}{f};
parts(k).level = level;
end
% Walk from leaves to root of tree, passing message to parent
% Given a 2D array of filter scores 'child', shiftdt() does the following:
% (1) Apply distance transform
% (2) Shift by anchor position (child.startxy) of part wrt parent
% (3) Downsample by child.step
for k = numparts:-1:2,
child = parts(k);
par = child.parent;
[Ny,Nx,foo] = size(parts(par).score);
[msg,parts(k).Ix,parts(k).Iy] = shiftdt(child.score, child.w(1),child.w(2),child.w(3),child.w(4), ...
child.startx, child.starty, Nx, Ny, child.step);
parts(par).score = parts(par).score + msg;
end
% Add bias to root score
rscore = parts(1).score + parts(1).w;
[Y,X] = find(rscore >= thresh);
if ~isempty(X)
XY = backtrack( X, Y, parts, pyra);
end
% Walk back down tree following pointers
for i = 1:length(X)
x = X(i);
y = Y(i);
if cnt == BOXCACHESIZE
b0 = nms_face(boxes,0.3);
clear boxes;
boxes.s = 0;
boxes.c = 0;
boxes.xy = 0;
boxes.level = 0;
boxes(BOXCACHESIZE) = boxes;
cnt = length(b0);
boxes(1:cnt) = b0;
end
cnt = cnt + 1;
boxes(cnt).c = c;
boxes(cnt).s = rscore(y,x);
boxes(cnt).level = rlevel;
boxes(cnt).xy = XY(:,:,i);
end
end
end
boxes = boxes(1:cnt);
% Backtrack through dynamic programming messages to estimate part locations
% and the associated feature vector
function box = backtrack(x,y,parts,pyra)
numparts = length(parts);
ptr = zeros(numparts,2,length(x));
box = zeros(numparts,4,length(x));
k = 1;
p = parts(k);
ptr(k,1,:) = x;
ptr(k,2,:) = y;
% image coordinates of root
scale = pyra.scale(p.level);
padx = pyra.padx;
pady = pyra.pady;
box(k,1,:) = (x-1-padx)*scale + 1;
box(k,2,:) = (y-1-pady)*scale + 1;
box(k,3,:) = box(k,1,:) + p.sizx*scale - 1;
box(k,4,:) = box(k,2,:) + p.sizy*scale - 1;
for k = 2:numparts,
p = parts(k);
par = p.parent;
x = ptr(par,1,:);
y = ptr(par,2,:);
inds = sub2ind(size(p.Ix), y, x);
ptr(k,1,:) = p.Ix(inds);
ptr(k,2,:) = p.Iy(inds);
% image coordinates of part k
scale = pyra.scale(p.level);
box(k,1,:) = (ptr(k,1,:)-1-padx)*scale + 1;
box(k,2,:) = (ptr(k,2,:)-1-pady)*scale + 1;
box(k,3,:) = box(k,1,:) + p.sizx*scale - 1;
box(k,4,:) = box(k,2,:) + p.sizy*scale - 1;
end
% Cache various statistics from the model data structure for later use
function [components,filters,resp] = modelcomponents(model,pyra)
components = cell(length(model.components),1);
for c = 1:length(model.components),
for k = 1:length(model.components{c}),
p = model.components{c}(k);
x = model.filters(p.filterid);
[p.sizy p.sizx foo] = size(x.w);
p.filterI = x.i;
x = model.defs(p.defid);
p.defI = x.i;
p.w = x.w;
% store the scale of each part relative to the component root
par = p.parent;
assert(par < k);
ax = x.anchor(1);
ay = x.anchor(2);
ds = x.anchor(3);
if par > 0,
p.scale = ds + components{c}(par).scale;
else
assert(k == 1);
p.scale = 0;
end
% amount of (virtual) padding to hallucinate
step = 2^ds;
virtpady = (step-1)*pyra.pady;
virtpadx = (step-1)*pyra.padx;
% starting points (simulates additional padding at finer scales)
p.starty = ay-virtpady;
p.startx = ax-virtpadx;
p.step = step;
p.level = 0;
p.score = 0;
p.Ix = 0;
p.Iy = 0;
components{c}(k) = p;
end
end
resp = cell(length(pyra.feat),1);
filters = cell(length(model.filters),1);
for i = 1:length(filters),
filters{i} = model.filters(i).w;
end