Skip to content

Instantly share code, notes, and snippets.

@bobbigmac
Created August 10, 2017 11:21
Show Gist options
  • Save bobbigmac/08b6f341385fc4445fe545a80aa3d15f to your computer and use it in GitHub Desktop.
Save bobbigmac/08b6f341385fc4445fe545a80aa3d15f to your computer and use it in GitHub Desktop.
Maps a clmtrackr 2d facial-points array to estimate of 3d X, Y and Z rotations
var
jawLeft = 0,
jawRight = 14,
leftBrowTop = 21,
rightBrowTop = 17,
leftChin = 6,
chinTip = 7,
rightChin = 8,
noseTop = 33
;
mapEventTo3dTransforms = function (event, outerWidth, outerHeight) {
var x = 0, y = 1, precision = 2;
var avg = ((a,b) => (a+b) / 2);
var left = avg(event[jawLeft][x], event[jawLeft + 1][x]);
var right = avg(event[jawRight - 1][x], event[jawRight][x]);
var top = avg(event[leftBrowTop][y], event[rightBrowTop][y]);
var bottom = avg(event[leftChin][y], event[rightChin][y]);
var width = right - left;
var center = left + (width / 2);
var height = bottom - top;
var middle = bottom + (height / 2);
var out = {
left, right, top, bottom, width, height, center, middle
}
// console.log(out.middle, out.center);
var pctEvent = event.map(function(ev) {
return [
(ev[x]-center) / width,
(ev[y]-middle) / height
];
});
var outer = pctEvent.slice(0, 15).concat(pctEvent.slice(15, 23));
var inner = pctEvent.slice(23);
// Get strength of offset between face and head placements
var innerMiddle = inner.reduce(function(pre,ev) {
pre[0] += ev[0];
pre[1] += ev[1];
return pre;
}, [0,0]);
innerMiddle = [innerMiddle[0] / inner.length, innerMiddle[1] / inner.length];
var outerMiddle = outer.reduce(function(pre,ev) {
pre[0] += ev[0];
pre[1] += ev[1];
return pre;
}, [0,0]);
outerMiddle = [outerMiddle[0] / outer.length, outerMiddle[1] / outer.length];
out.pctY = (innerMiddle[0] - outerMiddle[0]) / 2;
out.pctX = (innerMiddle[1] - outerMiddle[1]);
// Get turn and lean
var rotX = (out.pctX / 2) * 360;
// 0.9 compensates for model's inner/outer offset
var rotY = (out.pctY + 0.02) * 360;
// Get tilt
var p2 = event[noseTop], p1 = event[chinTip];
var rotZ = (-90 - (Math.atan2(p2[y] - p1[y], p2[x] - p1[x]) * 180 / Math.PI));
var dx = event[jawRight][x] - event[jawLeft][x];
var dy = event[jawRight][y] - event[jawLeft][y];
var hyp = Math.sqrt((dx * dx) + (dy * dy));
return {
x: rotX,
y: rotY,
z: rotZ,
hyp: hyp,
stats: out
}
}
@msj121
Copy link

msj121 commented Nov 16, 2017

Are outerWidth or outerHeight supposed to be used? Or are they placeholders for possible future consideration?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment