mirror of https://github.com/vladmandic/human
implement multi-person gestures
parent
c688254269
commit
f336b7772f
|
@ -4,9 +4,11 @@ async function drawGesture(result, canvas, ui) {
|
||||||
ctx.font = ui.baseFont;
|
ctx.font = ui.baseFont;
|
||||||
ctx.fillStyle = ui.baseLabel;
|
ctx.fillStyle = ui.baseLabel;
|
||||||
let i = 1;
|
let i = 1;
|
||||||
for (const [key, val] of Object.entries(result)) {
|
for (const gesture in result) {
|
||||||
if (val.length > 0) {
|
const [where, what] = Object.entries(result[gesture]);
|
||||||
const label = `${key}: ${val.join(', ')}`;
|
if ((what.length > 1) && (what[1].length > 0)) {
|
||||||
|
const person = where[1] > 0 ? `#${where[1]}` : '';
|
||||||
|
const label = `${where[0]} ${person}: ${what[1]}`;
|
||||||
ctx.fillStyle = 'black';
|
ctx.fillStyle = 'black';
|
||||||
ctx.fillText(label, 8, 2 + (i * ui.baseLineHeight));
|
ctx.fillText(label, 8, 2 + (i * ui.baseLineHeight));
|
||||||
ctx.fillStyle = ui.baseLabel;
|
ctx.fillStyle = ui.baseLabel;
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -18,7 +18,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"demo/draw.js": {
|
"demo/draw.js": {
|
||||||
"bytes": 10436,
|
"bytes": 10568,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"demo/gl-bench.js": {
|
"demo/gl-bench.js": {
|
||||||
|
@ -30,7 +30,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"dist/human.esm.js": {
|
"dist/human.esm.js": {
|
||||||
"bytes": 1784266,
|
"bytes": 1784464,
|
||||||
"imports": []
|
"imports": []
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -38,17 +38,17 @@
|
||||||
"dist/demo-browser-index.js.map": {
|
"dist/demo-browser-index.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 2678448
|
"bytes": 2679237
|
||||||
},
|
},
|
||||||
"dist/demo-browser-index.js": {
|
"dist/demo-browser-index.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"exports": [],
|
"exports": [],
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"dist/human.esm.js": {
|
"dist/human.esm.js": {
|
||||||
"bytesInOutput": 1777021
|
"bytesInOutput": 1777219
|
||||||
},
|
},
|
||||||
"demo/draw.js": {
|
"demo/draw.js": {
|
||||||
"bytesInOutput": 7668
|
"bytesInOutput": 7773
|
||||||
},
|
},
|
||||||
"demo/menu.js": {
|
"demo/menu.js": {
|
||||||
"bytesInOutput": 11838
|
"bytesInOutput": 11838
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
"bytesInOutput": 19407
|
"bytesInOutput": 19407
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 1830756
|
"bytes": 1831059
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -228,7 +228,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytes": 2981,
|
"bytes": 3260,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/hand/anchors.js": {
|
||||||
|
@ -290,7 +290,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 16057,
|
"bytes": 16046,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
"dist/human.esm.js.map": {
|
"dist/human.esm.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 2583057
|
"bytes": 2583632
|
||||||
},
|
},
|
||||||
"dist/human.esm.js": {
|
"dist/human.esm.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -444,7 +444,7 @@
|
||||||
"bytesInOutput": 1929
|
"bytesInOutput": 1929
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytesInOutput": 2255
|
"bytesInOutput": 2459
|
||||||
},
|
},
|
||||||
"src/imagefx.js": {
|
"src/imagefx.js": {
|
||||||
"bytesInOutput": 13638
|
"bytesInOutput": 13638
|
||||||
|
@ -456,7 +456,7 @@
|
||||||
"bytesInOutput": 1529574
|
"bytesInOutput": 1529574
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 10604
|
"bytesInOutput": 10598
|
||||||
},
|
},
|
||||||
"src/hand/box.js": {
|
"src/hand/box.js": {
|
||||||
"bytesInOutput": 1880
|
"bytesInOutput": 1880
|
||||||
|
@ -471,7 +471,7 @@
|
||||||
"bytesInOutput": 22
|
"bytesInOutput": 22
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 1784266
|
"bytes": 1784464
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -228,7 +228,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytes": 2981,
|
"bytes": 3260,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/hand/anchors.js": {
|
||||||
|
@ -290,7 +290,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 16057,
|
"bytes": 16046,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
"dist/human.js.map": {
|
"dist/human.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 2550003
|
"bytes": 2550600
|
||||||
},
|
},
|
||||||
"dist/human.js": {
|
"dist/human.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -442,7 +442,7 @@
|
||||||
"bytesInOutput": 1910
|
"bytesInOutput": 1910
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytesInOutput": 2235
|
"bytesInOutput": 2459
|
||||||
},
|
},
|
||||||
"src/imagefx.js": {
|
"src/imagefx.js": {
|
||||||
"bytesInOutput": 13638
|
"bytesInOutput": 13638
|
||||||
|
@ -451,7 +451,7 @@
|
||||||
"bytesInOutput": 4044
|
"bytesInOutput": 4044
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 10668
|
"bytesInOutput": 10662
|
||||||
},
|
},
|
||||||
"dist/tfjs.esm.js": {
|
"dist/tfjs.esm.js": {
|
||||||
"bytesInOutput": 1529065
|
"bytesInOutput": 1529065
|
||||||
|
@ -469,7 +469,7 @@
|
||||||
"bytesInOutput": 22
|
"bytesInOutput": 22
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 1783568
|
"bytes": 1783786
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -228,7 +228,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytes": 2981,
|
"bytes": 3260,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/hand/anchors.js": {
|
||||||
|
@ -290,7 +290,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 16057,
|
"bytes": 16046,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
"dist/human.node-gpu.js.map": {
|
"dist/human.node-gpu.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 686025
|
"bytes": 686589
|
||||||
},
|
},
|
||||||
"dist/human.node-gpu.js": {
|
"dist/human.node-gpu.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -445,7 +445,7 @@
|
||||||
"bytesInOutput": 1973
|
"bytesInOutput": 1973
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytesInOutput": 2259
|
"bytesInOutput": 2463
|
||||||
},
|
},
|
||||||
"src/imagefx.js": {
|
"src/imagefx.js": {
|
||||||
"bytesInOutput": 13620
|
"bytesInOutput": 13620
|
||||||
|
@ -454,7 +454,7 @@
|
||||||
"bytesInOutput": 4107
|
"bytesInOutput": 4107
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 10692
|
"bytesInOutput": 10686
|
||||||
},
|
},
|
||||||
"src/hand/box.js": {
|
"src/hand/box.js": {
|
||||||
"bytesInOutput": 1917
|
"bytesInOutput": 1917
|
||||||
|
@ -469,7 +469,7 @@
|
||||||
"bytesInOutput": 21
|
"bytesInOutput": 21
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 250245
|
"bytes": 250443
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
exports.body = (res) => {
|
exports.body = (res) => {
|
||||||
if (!res) return [];
|
if (!res) return [];
|
||||||
const gestures = [];
|
const gestures = [];
|
||||||
for (const pose of res) {
|
for (const i in res) {
|
||||||
// raising hands
|
// raising hands
|
||||||
const leftWrist = pose.keypoints.find((a) => (a.part === 'leftWrist'));
|
const leftWrist = res[i].keypoints.find((a) => (a.part === 'leftWrist'));
|
||||||
const rightWrist = pose.keypoints.find((a) => (a.part === 'rightWrist'));
|
const rightWrist = res[i].keypoints.find((a) => (a.part === 'rightWrist'));
|
||||||
const nose = pose.keypoints.find((a) => (a.part === 'nose'));
|
const nose = res[i].keypoints.find((a) => (a.part === 'nose'));
|
||||||
if (nose && leftWrist && rightWrist && (leftWrist.position.y < nose.position.y) && (rightWrist.position.y < nose.position.y)) gestures.push('i give up');
|
if (nose && leftWrist && rightWrist && (leftWrist.position.y < nose.position.y) && (rightWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'i give up' });
|
||||||
else if (nose && leftWrist && (leftWrist.position.y < nose.position.y)) gestures.push('raise left hand');
|
else if (nose && leftWrist && (leftWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'raise left hand' });
|
||||||
else if (nose && rightWrist && (rightWrist.position.y < nose.position.y)) gestures.push('raise right hand');
|
else if (nose && rightWrist && (rightWrist.position.y < nose.position.y)) gestures.push({ body: i, gesture: 'raise right hand' });
|
||||||
|
|
||||||
// leaning
|
// leaning
|
||||||
const leftShoulder = pose.keypoints.find((a) => (a.part === 'leftShoulder'));
|
const leftShoulder = res[i].keypoints.find((a) => (a.part === 'leftShoulder'));
|
||||||
const rightShoulder = pose.keypoints.find((a) => (a.part === 'rightShoulder'));
|
const rightShoulder = res[i].keypoints.find((a) => (a.part === 'rightShoulder'));
|
||||||
if (leftShoulder && rightShoulder) gestures.push(`leaning ${(leftShoulder.position.y > rightShoulder.position.y) ? 'left' : 'right'}`);
|
if (leftShoulder && rightShoulder) gestures.push({ body: i, gesture: `leaning ${(leftShoulder.position.y > rightShoulder.position.y) ? 'left' : 'right'}` });
|
||||||
}
|
}
|
||||||
return gestures;
|
return gestures;
|
||||||
};
|
};
|
||||||
|
@ -21,19 +21,19 @@ exports.body = (res) => {
|
||||||
exports.face = (res) => {
|
exports.face = (res) => {
|
||||||
if (!res) return [];
|
if (!res) return [];
|
||||||
const gestures = [];
|
const gestures = [];
|
||||||
for (const face of res) {
|
for (const i in res) {
|
||||||
if (face.mesh && face.mesh.length > 0) {
|
if (res[i].mesh && res[i].mesh.length > 0) {
|
||||||
const eyeFacing = face.mesh[35][2] - face.mesh[263][2];
|
const eyeFacing = res[i].mesh[35][2] - res[i].mesh[263][2];
|
||||||
if (Math.abs(eyeFacing) < 10) gestures.push('facing camera');
|
if (Math.abs(eyeFacing) < 10) gestures.push({ face: i, gesture: 'facing camera' });
|
||||||
else gestures.push(`facing ${eyeFacing < 0 ? 'right' : 'left'}`);
|
else gestures.push({ face: i, gesture: `facing ${eyeFacing < 0 ? 'right' : 'left'}` });
|
||||||
const openLeft = Math.abs(face.mesh[374][1] - face.mesh[386][1]) / Math.abs(face.mesh[443][1] - face.mesh[450][1]); // center of eye inner lid y coord div center of wider eye border y coord
|
const openLeft = Math.abs(res[i].mesh[374][1] - res[i].mesh[386][1]) / Math.abs(res[i].mesh[443][1] - res[i].mesh[450][1]); // center of eye inner lid y coord div center of wider eye border y coord
|
||||||
if (openLeft < 0.2) gestures.push('blink left eye');
|
if (openLeft < 0.2) gestures.push({ face: i, gesture: 'blink left eye' });
|
||||||
const openRight = Math.abs(face.mesh[145][1] - face.mesh[159][1]) / Math.abs(face.mesh[223][1] - face.mesh[230][1]); // center of eye inner lid y coord div center of wider eye border y coord
|
const openRight = Math.abs(res[i].mesh[145][1] - res[i].mesh[159][1]) / Math.abs(res[i].mesh[223][1] - res[i].mesh[230][1]); // center of eye inner lid y coord div center of wider eye border y coord
|
||||||
if (openRight < 0.2) gestures.push('blink right eye');
|
if (openRight < 0.2) gestures.push({ face: i, gesture: 'blink right eye' });
|
||||||
const mouthOpen = Math.min(100, 500 * Math.abs(face.mesh[13][1] - face.mesh[14][1]) / Math.abs(face.mesh[10][1] - face.mesh[152][1]));
|
const mouthOpen = Math.min(100, 500 * Math.abs(res[i].mesh[13][1] - res[i].mesh[14][1]) / Math.abs(res[i].mesh[10][1] - res[i].mesh[152][1]));
|
||||||
if (mouthOpen > 10) gestures.push(`mouth ${Math.trunc(mouthOpen)}% open`);
|
if (mouthOpen > 10) gestures.push({ face: i, gesture: `mouth ${Math.trunc(mouthOpen)}% open` });
|
||||||
const chinDepth = face.mesh[152][2];
|
const chinDepth = res[i].mesh[152][2];
|
||||||
if (Math.abs(chinDepth) > 10) gestures.push(`head ${chinDepth < 0 ? 'up' : 'down'}`);
|
if (Math.abs(chinDepth) > 10) gestures.push({ face: i, gesture: `head ${chinDepth < 0 ? 'up' : 'down'}` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gestures;
|
return gestures;
|
||||||
|
@ -42,15 +42,15 @@ exports.face = (res) => {
|
||||||
exports.hand = (res) => {
|
exports.hand = (res) => {
|
||||||
if (!res) return [];
|
if (!res) return [];
|
||||||
const gestures = [];
|
const gestures = [];
|
||||||
for (const hand of res) {
|
for (const i in res) {
|
||||||
const fingers = [];
|
const fingers = [];
|
||||||
for (const [finger, pos] of Object.entries(hand['annotations'])) {
|
for (const [finger, pos] of Object.entries(res[i]['annotations'])) {
|
||||||
if (finger !== 'palmBase') fingers.push({ name: finger.toLowerCase(), position: pos[0] }); // get tip of each finger
|
if (finger !== 'palmBase') fingers.push({ name: finger.toLowerCase(), position: pos[0] }); // get tip of each finger
|
||||||
}
|
}
|
||||||
if (fingers && fingers.length > 0) {
|
if (fingers && fingers.length > 0) {
|
||||||
const closest = fingers.reduce((best, a) => (best.position[2] < a.position[2] ? best : a));
|
const closest = fingers.reduce((best, a) => (best.position[2] < a.position[2] ? best : a));
|
||||||
const highest = fingers.reduce((best, a) => (best.position[1] < a.position[1] ? best : a));
|
const highest = fingers.reduce((best, a) => (best.position[1] < a.position[1] ? best : a));
|
||||||
gestures.push(`${closest.name} forward ${highest.name} up`);
|
gestures.push({ hand: i, gesture: `${closest.name} forward ${highest.name} up` });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return gestures;
|
return gestures;
|
||||||
|
|
|
@ -408,7 +408,7 @@ class Human {
|
||||||
let gestureRes = [];
|
let gestureRes = [];
|
||||||
if (this.config.gesture.enabled) {
|
if (this.config.gesture.enabled) {
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
gestureRes = { face: gesture.face(faceRes), body: gesture.body(poseRes), hand: gesture.hand(handRes) };
|
gestureRes = [...gesture.face(faceRes), ...gesture.body(poseRes), ...gesture.hand(handRes)];
|
||||||
if (!this.config.async) this.perf.gesture = Math.trunc(now() - timeStamp);
|
if (!this.config.async) this.perf.gesture = Math.trunc(now() - timeStamp);
|
||||||
else if (this.perf.gesture) delete this.perf.gesture;
|
else if (this.perf.gesture) delete this.perf.gesture;
|
||||||
}
|
}
|
||||||
|
|
2
wiki
2
wiki
|
@ -1 +1 @@
|
||||||
Subproject commit 333457d935d89f2559342b31907d04d091520604
|
Subproject commit bcac4981f7df29e367259caf6b3b73e5ecde6519
|
Loading…
Reference in New Issue