xxxxxxxxxx
332
// p5.js + BRFv4 face tracker (via handsfree.js)
//
// We're using a specific version of handsfree.js
// that has the (commercial, trial) BRFv4 tracker baked in:
// https://unpkg.com/handsfree@4.0.3/dist/handsfree.js
// more information about the BRFv4 tracker is at:
// https://github.com/Tastenkunst/brfv4_javascript_examples
//to do
//one tear per blink +
//closed eyes and open mouth - lots of tears
//smile - no tears, sunny background +
//rotate cheek
var tears = [];
var myHandsfree;
var videoInput;
var rx;
var ry;
var rz;
var x;
var y;
var col = 0;
var colD = 1;
var oldBlink = false;
var smileOn = false;
//---------------------------------------------
function setup() {
// createCanvas(800, 480);
createCanvas(640, 480);
var myConfig = {
hideCursor: true
};
myHandsfree = new Handsfree(myConfig);
myHandsfree.start();
videoInput = createCapture(VIDEO);
videoInput.size(width, height);
videoInput.hide();
}
//---------------------------------------------
function draw() {
background(250);
// image(videoInput, -90, 0, width + 10, height);
// image(videoInput, -95, 0, width * 1.3, height);
if (myHandsfree.isTracking) {
if (myHandsfree.pose.length > 0) {
var face0 = myHandsfree.pose[0].face;
var nPoints = face0.vertices.length;
//facePoints 0 - 52
//eyepoints 72-82 , 84-94
//lip 94-120, 120-134
//nose 54-60, 62-70
var smileDiff = dist(face0.vertices[108], face0.vertices[109], face0.vertices[96], face0.vertices[97]);
var eyeDiff = dist(face0.vertices[78], face0.vertices[79], face0.vertices[72], face0.vertices[73]);
if (smileDiff > 2.5 * eyeDiff) smile(face0);
else smileOn = false;
lineFace(face0);
// var blinkDiff = 2 * dist(face0.vertices[82], face0.vertices[83], face0.vertices[76], face0.vertices[77]);
// var blinkRatio = blinkDiff / eyeDiff;
// print(blinkRatio);
// if (!smileOn) {
// if (blinkRatio > 5) {
// if (!oldBlink) {
// print("blink");
// if (col >= 255) colD = -1;
// if (col <= 0) colD = 1;
// col += colD * 5;
// oldBlink = true;
// var tearX = [84, 92, 90];
// var newTearX = tearX[int(random(0, 3))];
// var tearW = face0.vertices[90] - face0.vertices[84];
// tears.push(makeTear(face0.vertices[newTearX], face0.vertices[newTearX + 1], tearW));
// } else oldBlink = true;
// } else oldBlink = false;
var v = face0.vertices;
if (_oldFaceShapeVertices.length === 0) storeFaceShapeVertices(v);
var k, l, yLE, yRE;
// Left eye movement (y)
for (k = 36, l = 41, yLE = 0; k <= l; k++) {
yLE += v[k * 2 + 1] - _oldFaceShapeVertices[k * 2 + 1];
}
yLE /= 6;
// Right eye movement (y)
for (k = 42, l = 47, yRE = 0; k <= l; k++) {
yRE += v[k * 2 + 1] - _oldFaceShapeVertices[k * 2 + 1];
}
yRE /= 6;
var yN = 0;
// Compare to overall movement (nose y)
yN += v[27 * 2 + 1] - _oldFaceShapeVertices[27 * 2 + 1];
yN += v[28 * 2 + 1] - _oldFaceShapeVertices[28 * 2 + 1];
yN += v[29 * 2 + 1] - _oldFaceShapeVertices[29 * 2 + 1];
yN += v[30 * 2 + 1] - _oldFaceShapeVertices[30 * 2 + 1];
yN /= 4;
var blinkRatio = Math.abs((yLE + yRE) / yN);
if ((blinkRatio > 12 && (yLE > 0.4 || yRE > 0.4))) {
console.log("blink " + blinkRatio.toFixed(2) + " " + yLE.toFixed(2) + " " +
yRE.toFixed(2) + " " + yN.toFixed(2));
blink();
var tearX = [84, 92, 90];
var newTearX = tearX[int(random(0, 3))];
var tearW = face0.vertices[90] - face0.vertices[84];
tears.push(makeTear(face0.vertices[newTearX], face0.vertices[newTearX + 1], tearW));
}
for (var t = 0; t < tears.length; t++) {
tears[t].render();
tears[t].update();
}
fill(255);
stroke(1);
for (var w = 0; w < nPoints; w += 2) {
var xw = face0.vertices[w + 0];
var yw = face0.vertices[w + 1];
// ellipse(xw, yw, 9, 9);
// text(w, xw, yw);
}
// Rotations of the head, in radians
rx = face0.rotationX; // pitch
ry = face0.rotationY; // yaw
rz = face0.rotationZ; // roll
storeFaceShapeVertices(v);
}
}
}
function blink() {
_blinked = true;
if (_timeOut > -1) {
clearTimeout(_timeOut);
}
_timeOut = setTimeout(resetBlink, 150);
}
function resetBlink() {
_blinked = false;
}
function storeFaceShapeVertices(vertices) {
for (var i = 0, l = vertices.length; i < l; i++) {
_oldFaceShapeVertices[i] = vertices[i];
}
}
var _oldFaceShapeVertices = [];
var _blinked = false;
var _timeOut = -1;
function smile(face) {
smileOn = true;
var x = face.vertices[56];
var y = face.vertices[57];
var w = (face.vertices[17] - y);
stroke(255);
fill(255, 255, 0, 100);
ellipse(x, y, w * 2, w * 2);
for (var i = 0; i < 20; i++) {
var a = map(i, 0, 20, 0, TWO_PI);
var lineX1 = x + w * cos(a);
var lineY1 = y + w * sin(a);
var lineX2 = x + w * 1.1 * cos(a);
var lineY2 = y + w * 1.1 * sin(a);
line(lineX1, lineY1, lineX2, lineY2);
}
// beginShape();
// for (var j1 = 14; j1 < 34; j1 += 2) { // right side of face
// x = face0.vertices[j1 + 0];
// y = face0.vertices[j1 + 1];
// curveVertex(x, y);
// }
}
function makeTear(x, y, w) {
var tears = {
x: x,
y: y,
w: w / 4,
update: updateTear,
render: renderTear
};
return tears;
}
function updateTear() {
this.y *= 1.005;
}
function renderTear() {
fill(0, 0, 255, 100);
beginShape();
curveVertex(this.x, this.y);
curveVertex(this.x + this.w, this.y + this.w * 2.5);
curveVertex(this.x, this.y + this.w * 3.5);
curveVertex(this.x - this.w, this.y + this.w * 2.5);
endShape(CLOSE);
}
function lineFace(face0) {
if (!smileOn) fill(255 - col, 0, col, 80);
stroke(255);
strokeWeight(3);
beginShape();
for (var j0 = 34; j0 < 46; j0 += 2) { // left eyebrow
x = face0.vertices[j0 + 0];
y = face0.vertices[j0 + 1];
curveVertex(x, y);
}
endShape();
beginShape();
for (var j1 = 14; j1 < 34; j1 += 2) { // right side of face
x = face0.vertices[j1 + 0];
y = face0.vertices[j1 + 1];
curveVertex(x, y);
}
curveVertex(face0.vertices[52], face0.vertices[53]);
for (var j2 = 52; j2 > 42; j2 -= 2) { // right eyebrow
x = face0.vertices[j2 + 0];
y = face0.vertices[j2 + 1];
curveVertex(x, y);
}
for (var j3 = 54; j3 < 62; j3 += 2) { // nose
x = face0.vertices[j3 + 0];
y = face0.vertices[j3 + 1];
curveVertex(x, y);
}
for (var j4 = 70; j4 > 66; j4 -= 2) { // bottom of nose
x = face0.vertices[j4 + 0];
y = face0.vertices[j4 + 1];
curveVertex(x, y);
}
for (var j5 = 102; j5 < 116; j5 += 2) { // around mouth
x = face0.vertices[j5 + 0];
y = face0.vertices[j5 + 1];
curveVertex(x, y);
}
vertex(face0.vertices[16], face0.vertices[17]);
endShape(CLOSE);
//EYES
fill(0, 0, 0, 50);
beginShape();
for (var j6 = 78; j6 > 70; j6 -= 2) { //top left eye
x = face0.vertices[j6 + 0];
y = face0.vertices[j6 + 1];
curveVertex(x, y);
}
for (var j7 = 82; j7 > 78; j7 -= 2) { // bottom left eye
x = face0.vertices[j7 + 0];
y = face0.vertices[j7 + 1];
curveVertex(x, y);
}
curveVertex(face0.vertices[54], face0.vertices[77]);
for (var j8 = 84; j8 < 94; j8 += 2) { // right eye
x = face0.vertices[j8 + 0];
y = face0.vertices[j8 + 1];
curveVertex(x, y);
}
curveVertex(face0.vertices[84], face0.vertices[85]);
curveVertex(face0.vertices[54], face0.vertices[77]);
endShape(CLOSE);
//MOUTH
fill(255 - col, 255 - col, 0, 100);
beginShape();
for (var m = 120; m < 136; m += 2) {
x = face0.vertices[m + 0];
y = face0.vertices[m + 1];
curveVertex(x, y);
}
endShape(CLOSE);
// beginShape(); // cheeks
// var cheekY = (face0.vertices[59] - face0.vertices[57]) / 2 + face0.vertices[57];
// fill(col, 0, 255 - col, 100);
// curveVertex(face0.vertices[72], face0.vertices[59]);
// curveVertex(face0.vertices[74], cheekY)
// curveVertex(face0.vertices[78], face0.vertices[59]);
// curveVertex(face0.vertices[74], face0.vertices[65]);
// endShape(CLOSE);
}