Skip to content

Commit

Permalink
hand-pick: #83
Browse files Browse the repository at this point in the history
  • Loading branch information
yofreke committed Sep 12, 2016
1 parent fcb8d39 commit 37e56b3
Show file tree
Hide file tree
Showing 3 changed files with 158 additions and 71 deletions.
111 changes: 69 additions & 42 deletions js/clm.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ var clm = {
var relaxation = 0.1;

var first = true;
var gettingPosition = false;

var convergenceLimit = 0.01;

Expand Down Expand Up @@ -307,11 +308,16 @@ var clm = {
cancelRequestAnimFrame(runnerTimeout);
}

this.recheck = function () {
console.log('RECHECKING');
first = true;
}

/*
* element : canvas or video element
* TODO: should be able to take img element as well
*/
this.track = function(element, box) {
this.track = function(element, box, gi) {
var evt = document.createEvent("Event");
evt.initEvent("clmtrackrBeforeTrack", true, true);
document.dispatchEvent(evt)
Expand All @@ -320,23 +326,35 @@ var clm = {
var croppedPatches = [];
var ptch, px, py;

if (first) {
// do viola-jones on canvas to get initial guess, if we don't have any points
var gi = getInitialPosition(element, box);
if (!gi) {
// send an event on no face found
var evt = document.createEvent("Event");
evt.initEvent("clmtrackrNotFound", true, true);
document.dispatchEvent(evt)

return false;
}
if (gi) {
scaling = gi[0];
rotation = gi[1];
translateX = gi[2];
translateY = gi[3];

first = false;
gettingPosition = false;
} else if (first) {
// do viola-jones on canvas to get initial guess, if we don't have any points
if (!gettingPosition) {
gettingPosition = true;
getInitialPosition(element, box, function (gi) {
gettingPosition = false;
if (!gi) {
// send an event on no face found
var evt = document.createEvent("Event");
evt.initEvent("clmtrackrNotFound", true, true);
document.dispatchEvent(evt);
first = true;

return false;
} else {
this.track(element, box, gi);
}

}.bind(this));
}
return;
} else {
facecheck_count += 1;

Expand Down Expand Up @@ -390,7 +408,7 @@ var clm = {
// send event to signal that tracking was lost
var evt = document.createEvent("Event");
evt.initEvent("clmtrackrLost", true, true);
document.dispatchEvent(evt)
document.dispatchEvent(evt);

return false;
}
Expand Down Expand Up @@ -793,12 +811,13 @@ var clm = {

var runnerFunction = function() {
runnerTimeout = requestAnimFrame(runnerFunction);
// schedule as many iterations as we can during each request
var startTime = (new Date()).getTime();
while (((new Date()).getTime() - startTime) < 16) {
var tracking = this.track(runnerElement, runnerBox);
if (!tracking) continue;
}
// // schedule as many iterations as we can during each request
// var startTime = (new Date()).getTime();
// while (((new Date()).getTime() - startTime) < 16) {
// var tracking = this.track(runnerElement, runnerBox);
// if (!tracking) continue;
// }
this.track(runnerElement, runnerBox);
}.bind(this);

var getWebGLResponsesType = function(type, patches) {
Expand Down Expand Up @@ -906,25 +925,12 @@ var clm = {
return positions;
}

// detect position of face on canvas/video element
var detectPosition = function(el) {
var canvas = document.createElement('canvas');
canvas.width = el.width;
canvas.height = el.height;
var cc = canvas.getContext('2d');
cc.drawImage(el, 0, 0, el.width, el.height);

// do viola-jones on canvas to get initial guess, if we don't have any points
/*var comp = ccv.detect_objects(
ccv.grayscale(canvas), ccv.cascade, 5, 1
);*/

var jf = new jsfeat_face(canvas);
var comp = jf.findFace();

if (comp.length > 0) {
var faceDetected = function (e, callback) {
var comp = e.data.comp;
if (comp && comp.length > 0) {
candidate = comp[0];
} else {
callback(false);
return false;
}

Expand All @@ -934,7 +940,22 @@ var clm = {
}
}

return candidate;
// return candidate;
callback(candidate);
}

// detect position of face on canvas/video element
var detectPosition = function(el, callback) {
var canvas = document.createElement('canvas');
canvas.width = el.width;
canvas.height = el.height;
var cc = canvas.getContext('2d');
cc.drawImage(el, 0, 0, el.width, el.height);

var jf = new jsfeat_face(canvas);
jf.faceDetected = faceDetected;
//TODO Allow option that limit simultaneous trigger of WebWorkers
var comp = jf.findFace(callback);
}

// part one of meanshift calculation
Expand Down Expand Up @@ -1041,15 +1062,21 @@ var clm = {
}

// get initial starting point for model
var getInitialPosition = function(element, box) {
var getInitialPosition = function(element, box, callback, det) {
var translateX, translateY, scaling, rotation;
if (box) {
candidate = {x : box[0], y : box[1], width : box[2], height : box[3]};
} else {
var det = detectPosition(element);
if (!det) {
// if no face found, stop.
return false;
detectPosition(element, function (det) {
if (!det) {
// if no face found, stop.
callback(false);
} else {
getInitialPosition(element, box, callback, det);
}
});
return;
}
}

Expand Down Expand Up @@ -1171,7 +1198,7 @@ var clm = {

currentPositions = calculatePositions(currentParameters, true);

return [scaling, rotation, translateX, translateY];
callback([scaling, rotation, translateX, translateY]);
}

// draw a parametrized line on a canvas
Expand Down
58 changes: 29 additions & 29 deletions js/jsfeat_detect.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
// simple wrapper for jsfeat face detector
var jsfeat = require('jsfeat');
var findFaceWorker = require('./jsfeat_detect_worker');

// Curtousy of stackoverflow this function
Worker.createURL = function(func_or_string){
var str = (typeof func_or_string === 'function')?func_or_string.toString():func_or_string;
var blob = new Blob(['\'use strict\';\nself.onmessage ='+str], { type: 'text/javascript' });
return window.URL.createObjectURL(blob);
};

Worker.create = function(func_or_string){
return new Worker(Worker.createURL(func_or_string));
};


/**
* this cascade is derived from https://github.com/mtschirs/js-objectdetect implementation
* @author Martin Tschirsich / http://www.tu-darmstadt.de/~m_t
Expand All @@ -22,44 +36,30 @@ var jsfeat_face = function(image) {
work_ctx = image.getContext('2d');
}

img_u8 = new jsfeat.matrix_t(w, h, jsfeat.U8_t | jsfeat.C1_t);
ii_sum = new Int32Array((w+1)*(h+1));
ii_sqsum = new Int32Array((w+1)*(h+1));
ii_tilted = new Int32Array((w+1)*(h+1));
// img_u8 = new jsfeat.matrix_t(w, h, jsfeat.U8_t | jsfeat.C1_t);
// ii_sum = new Int32Array((w+1)*(h+1));
// ii_sqsum = new Int32Array((w+1)*(h+1));
// ii_tilted = new Int32Array((w+1)*(h+1));

var classifier = frontalface;
// var classifier = frontalface;

this.findFace = function () {
this.findFace = function (callback) {
if (image.tagName == 'VIDEO' || image.tagName == 'IMG') {
work_ctx.drawImage(image, 0, 0);
}
var imageData = work_ctx.getImageData(0, 0, w, h);

jsfeat.imgproc.grayscale(imageData.data, w, h, img_u8);

jsfeat.imgproc.equalize_histogram(img_u8, img_u8);
var worker = Worker.create(findFaceWorker);

jsfeat.imgproc.compute_integral_image(img_u8, ii_sum, ii_sqsum, null);
worker.addEventListener('message', function (e) {
this.faceDetected(e, callback);
}.bind(this), false);

var rects = jsfeat.haar.detect_multi_scale(ii_sum, ii_sqsum, ii_tilted, null, img_u8.cols, img_u8.rows, classifier, 1.15, 2);

rects = jsfeat.haar.group_rectangles(rects, 1);

var rl = rects.length;

if (rl > 0) {
var best = rects[0];
for (var i = 1;i < rl;i++) {
if (rects[i].neighbors > best.neighbors) {
best = rects[i]
} else if (rects[i].neighbors == best.neighbors) {
if (rects[i].confidence > best.confidence) best = rects[i];
}
}
return [best];
} else {
return false;
}
worker.postMessage({
w: w,
h: h,
imageData:imageData
});
}

}
Expand Down
60 changes: 60 additions & 0 deletions js/jsfeat_detect_worker.js

Large diffs are not rendered by default.

0 comments on commit 37e56b3

Please sign in to comment.