convert to typescript

pull/70/head
Vladimir Mandic 2021-02-08 11:39:09 -05:00
parent ea9847927b
commit 6fb133b55e
69 changed files with 6640 additions and 6775 deletions

View File

@ -46,7 +46,7 @@ Compatible with *Browser*, *WebWorker* and *NodeJS* execution on both Windows an
<br>
*This is a pre-release project, see [issues](https://github.com/vladmandic/human/issues) for list of known limitations and planned enhancements*
*See [issues](https://github.com/vladmandic/human/issues?q=) and [discussions](https://github.com/vladmandic/human/discussions) for list of known limitations and planned enhancements*
*Suggestions are welcome!*

View File

@ -56,14 +56,19 @@ async function detect(input) {
}
async function test() {
// test with embedded face image
log.state('Processing embedded warmup image: face');
myConfig.warmup = 'face';
const resultFace = await human.warmup(myConfig);
log.data(resultFace);
log.data('Face: ', resultFace.face);
// test with embedded full body image
log.state('Processing embedded warmup image: full');
myConfig.warmup = 'full';
const resultFull = await human.warmup(myConfig);
log.data(resultFull);
log.data('Body:', resultFull.body);
log.data('Hand:', resultFull.hand);
log.data('Gesture:', resultFull.gesture);
}
async function main() {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{
"inputs": {
"dist/human.esm.js": {
"bytes": 1349003,
"bytes": 1343005,
"imports": []
},
"demo/draw.js": {
@ -43,14 +43,14 @@
"imports": [],
"exports": [],
"inputs": {},
"bytes": 2028101
"bytes": 2018414
},
"dist/demo-browser-index.js": {
"imports": [],
"exports": [],
"inputs": {
"dist/human.esm.js": {
"bytesInOutput": 1340450
"bytesInOutput": 1335513
},
"demo/draw.js": {
"bytesInOutput": 6204
@ -65,7 +65,7 @@
"bytesInOutput": 16815
}
},
"bytes": 1388309
"bytes": 1383372
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

526
dist/human.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

466
dist/human.esm.json vendored
View File

@ -1,18 +1,18 @@
{
"inputs": {
"src/log.js": {
"src/log.ts": {
"bytes": 401,
"imports": []
},
"dist/tfjs.esm.js": {
"bytes": 1071833,
"bytes": 1071825,
"imports": []
},
"src/tfjs/backend.js": {
"bytes": 2171,
"src/tfjs/backend.ts": {
"bytes": 2168,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -21,11 +21,11 @@
}
]
},
"src/blazeface/blazeface.js": {
"bytes": 7024,
"src/blazeface/blazeface.ts": {
"bytes": 6024,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -34,8 +34,8 @@
}
]
},
"src/blazeface/box.js": {
"bytes": 1935,
"src/blazeface/box.ts": {
"bytes": 1727,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -43,44 +43,40 @@
}
]
},
"src/blazeface/util.js": {
"bytes": 3087,
"src/blazeface/util.ts": {
"bytes": 2777,
"imports": []
},
"src/blazeface/coords.js": {
"bytes": 37915,
"src/blazeface/coords.ts": {
"bytes": 37783,
"imports": []
},
"src/blazeface/facepipeline.js": {
"bytes": 14275,
"src/blazeface/facepipeline.ts": {
"bytes": 14254,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/blazeface/box.js",
"path": "src/blazeface/box.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/util.js",
"path": "src/blazeface/util.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/coords.js",
"kind": "import-statement"
},
{
"path": "src/log.js",
"path": "src/blazeface/coords.ts",
"kind": "import-statement"
}
]
},
"src/blazeface/facemesh.js": {
"bytes": 2973,
"src/blazeface/facemesh.ts": {
"bytes": 2935,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -88,33 +84,33 @@
"kind": "import-statement"
},
{
"path": "src/blazeface/blazeface.js",
"path": "src/blazeface/blazeface.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/facepipeline.js",
"path": "src/blazeface/facepipeline.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/coords.js",
"path": "src/blazeface/coords.ts",
"kind": "import-statement"
}
]
},
"src/profile.js": {
"bytes": 1045,
"src/profile.ts": {
"bytes": 1004,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
}
]
},
"src/faceboxes/faceboxes.js": {
"bytes": 2612,
"src/faceboxes/faceboxes.ts": {
"bytes": 2852,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -122,16 +118,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/age/age.js": {
"bytes": 2037,
"src/age/age.ts": {
"bytes": 2064,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -139,16 +135,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/gender/gender.js": {
"bytes": 2906,
"src/gender/gender.ts": {
"bytes": 2904,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -156,16 +152,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/emotion/emotion.js": {
"bytes": 3056,
"src/emotion/emotion.ts": {
"bytes": 3033,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -173,16 +169,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/embedding/embedding.js": {
"bytes": 2063,
"src/embedding/embedding.ts": {
"bytes": 1992,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -190,13 +186,13 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/posenet/modelBase.js": {
"bytes": 1343,
"src/posenet/modelBase.ts": {
"bytes": 1333,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -204,93 +200,93 @@
}
]
},
"src/posenet/heapSort.js": {
"bytes": 1590,
"src/posenet/heapSort.ts": {
"bytes": 1645,
"imports": []
},
"src/posenet/buildParts.js": {
"bytes": 1775,
"src/posenet/buildParts.ts": {
"bytes": 1723,
"imports": [
{
"path": "src/posenet/heapSort.js",
"path": "src/posenet/heapSort.ts",
"kind": "import-statement"
}
]
},
"src/posenet/keypoints.js": {
"bytes": 2011,
"src/posenet/keypoints.ts": {
"bytes": 2025,
"imports": []
},
"src/posenet/vectors.js": {
"bytes": 1273,
"src/posenet/vectors.ts": {
"bytes": 1075,
"imports": [
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
}
]
},
"src/posenet/decoders.js": {
"bytes": 2083,
"src/posenet/decoders.ts": {
"bytes": 1943,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
}
]
},
"src/posenet/decodePose.js": {
"bytes": 5368,
"src/posenet/decodePose.ts": {
"bytes": 5152,
"imports": [
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/vectors.js",
"path": "src/posenet/vectors.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decoders.js",
"path": "src/posenet/decoders.ts",
"kind": "import-statement"
}
]
},
"src/posenet/decodeMultiple.js": {
"bytes": 2373,
"src/posenet/decodeMultiple.ts": {
"bytes": 2259,
"imports": [
{
"path": "src/posenet/buildParts.js",
"path": "src/posenet/buildParts.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decodePose.js",
"path": "src/posenet/decodePose.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/vectors.js",
"path": "src/posenet/vectors.ts",
"kind": "import-statement"
}
]
},
"src/posenet/util.js": {
"bytes": 2262,
"src/posenet/util.ts": {
"bytes": 2017,
"imports": [
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
}
]
},
"src/posenet/modelPoseNet.js": {
"bytes": 2519,
"src/posenet/posenet.ts": {
"bytes": 2376,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -298,42 +294,25 @@
"kind": "import-statement"
},
{
"path": "src/posenet/modelBase.js",
"path": "src/posenet/modelBase.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decodeMultiple.js",
"path": "src/posenet/decodeMultiple.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decodePose.js",
"path": "src/posenet/decodePose.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/util.js",
"path": "src/posenet/util.ts",
"kind": "import-statement"
}
]
},
"src/posenet/posenet.js": {
"bytes": 712,
"imports": [
{
"path": "src/posenet/modelPoseNet.js",
"kind": "import-statement"
},
{
"path": "src/posenet/keypoints.js",
"kind": "import-statement"
},
{
"path": "src/posenet/util.js",
"kind": "import-statement"
}
]
},
"src/handpose/box.js": {
"bytes": 2522,
"src/handpose/box.ts": {
"bytes": 2443,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -341,53 +320,49 @@
}
]
},
"src/handpose/handdetector.js": {
"bytes": 3548,
"src/handpose/handdetector.ts": {
"bytes": 3627,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/handpose/box.js",
"path": "src/handpose/box.ts",
"kind": "import-statement"
}
]
},
"src/handpose/util.js": {
"bytes": 2346,
"src/handpose/util.ts": {
"bytes": 2254,
"imports": []
},
"src/handpose/handpipeline.js": {
"bytes": 7246,
"src/handpose/handpipeline.ts": {
"bytes": 7344,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/handpose/box.js",
"path": "src/handpose/box.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/util.js",
"kind": "import-statement"
},
{
"path": "src/log.js",
"path": "src/handpose/util.ts",
"kind": "import-statement"
}
]
},
"src/handpose/anchors.js": {
"bytes": 224151,
"src/handpose/anchors.ts": {
"bytes": 224156,
"imports": []
},
"src/handpose/handpose.js": {
"bytes": 2578,
"src/handpose/handpose.ts": {
"bytes": 2529,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -395,32 +370,32 @@
"kind": "import-statement"
},
{
"path": "src/handpose/handdetector.js",
"path": "src/handpose/handdetector.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/handpipeline.js",
"path": "src/handpose/handpipeline.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/anchors.js",
"path": "src/handpose/anchors.ts",
"kind": "import-statement"
}
]
},
"src/gesture/gesture.js": {
"bytes": 4245,
"src/gesture/gesture.ts": {
"bytes": 4265,
"imports": []
},
"src/imagefx.js": {
"bytes": 19445,
"bytes": 19447,
"imports": []
},
"src/image.js": {
"bytes": 5871,
"src/image.ts": {
"bytes": 5851,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -437,19 +412,19 @@
"bytes": 9786,
"imports": []
},
"src/sample.js": {
"src/sample.ts": {
"bytes": 55382,
"imports": []
},
"package.json": {
"bytes": 2321,
"bytes": 2344,
"imports": []
},
"src/human.js": {
"bytes": 18962,
"src/human.ts": {
"bytes": 19393,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -457,51 +432,51 @@
"kind": "import-statement"
},
{
"path": "src/tfjs/backend.js",
"path": "src/tfjs/backend.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/facemesh.js",
"path": "src/blazeface/facemesh.ts",
"kind": "import-statement"
},
{
"path": "src/faceboxes/faceboxes.js",
"path": "src/faceboxes/faceboxes.ts",
"kind": "import-statement"
},
{
"path": "src/age/age.js",
"path": "src/age/age.ts",
"kind": "import-statement"
},
{
"path": "src/gender/gender.js",
"path": "src/gender/gender.ts",
"kind": "import-statement"
},
{
"path": "src/emotion/emotion.js",
"path": "src/emotion/emotion.ts",
"kind": "import-statement"
},
{
"path": "src/embedding/embedding.js",
"path": "src/embedding/embedding.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/posenet.js",
"path": "src/posenet/posenet.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/handpose.js",
"path": "src/handpose/handpose.ts",
"kind": "import-statement"
},
{
"path": "src/gesture/gesture.js",
"path": "src/gesture/gesture.ts",
"kind": "import-statement"
},
{
"path": "src/image.js",
"path": "src/image.ts",
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
},
{
@ -509,7 +484,7 @@
"kind": "import-statement"
},
{
"path": "src/sample.js",
"path": "src/sample.ts",
"kind": "import-statement"
},
{
@ -524,7 +499,7 @@
"imports": [],
"exports": [],
"inputs": {},
"bytes": 1932071
"bytes": 1923046
},
"dist/human.esm.js": {
"imports": [],
@ -532,125 +507,122 @@
"default"
],
"inputs": {
"src/blazeface/blazeface.js": {
"bytesInOutput": 2915
"src/blazeface/facemesh.ts": {
"bytesInOutput": 1445
},
"src/blazeface/box.js": {
"bytesInOutput": 987
},
"src/blazeface/util.js": {
"bytesInOutput": 1197
},
"src/blazeface/coords.js": {
"bytesInOutput": 30534
},
"src/blazeface/facepipeline.js": {
"bytesInOutput": 5578
},
"src/blazeface/facemesh.js": {
"bytesInOutput": 1518
},
"src/profile.js": {
"bytesInOutput": 637
},
"src/faceboxes/faceboxes.js": {
"bytesInOutput": 1387
},
"src/age/age.js": {
"bytesInOutput": 813
},
"src/gender/gender.js": {
"bytesInOutput": 1283
},
"src/emotion/emotion.js": {
"bytesInOutput": 1247
},
"src/embedding/embedding.js": {
"bytesInOutput": 870
},
"src/posenet/modelBase.js": {
"bytesInOutput": 679
},
"src/posenet/heapSort.js": {
"bytesInOutput": 1048
},
"src/posenet/buildParts.js": {
"bytesInOutput": 529
},
"src/posenet/keypoints.js": {
"bytesInOutput": 1638
},
"src/posenet/vectors.js": {
"bytesInOutput": 627
},
"src/posenet/decoders.js": {
"bytesInOutput": 875
},
"src/posenet/decodePose.js": {
"bytesInOutput": 1482
},
"src/posenet/decodeMultiple.js": {
"bytesInOutput": 704
},
"src/posenet/util.js": {
"bytesInOutput": 1065
},
"src/posenet/modelPoseNet.js": {
"bytesInOutput": 1167
},
"src/posenet/posenet.js": {
"bytesInOutput": 401
},
"src/handpose/handdetector.js": {
"bytesInOutput": 1704
},
"src/handpose/handpipeline.js": {
"bytesInOutput": 2485
},
"src/handpose/anchors.js": {
"bytesInOutput": 127006
},
"src/handpose/handpose.js": {
"bytesInOutput": 1331
},
"src/gesture/gesture.js": {
"bytesInOutput": 2424
"src/posenet/keypoints.ts": {
"bytesInOutput": 1690
},
"src/imagefx.js": {
"bytesInOutput": 11004
"bytesInOutput": 11016
},
"src/image.js": {
"bytesInOutput": 2480
},
"src/log.js": {
"src/log.ts": {
"bytesInOutput": 252
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1062888
"bytesInOutput": 1062782
},
"src/tfjs/backend.js": {
"src/tfjs/backend.ts": {
"bytesInOutput": 1205
},
"src/human.js": {
"bytesInOutput": 10537
"src/blazeface/blazeface.ts": {
"bytesInOutput": 2185
},
"src/handpose/box.js": {
"src/blazeface/box.ts": {
"bytesInOutput": 834
},
"src/blazeface/util.ts": {
"bytesInOutput": 858
},
"src/blazeface/coords.ts": {
"bytesInOutput": 28983
},
"src/blazeface/facepipeline.ts": {
"bytesInOutput": 5046
},
"src/human.ts": {
"bytesInOutput": 10223
},
"src/faceboxes/faceboxes.ts": {
"bytesInOutput": 1549
},
"src/profile.ts": {
"bytesInOutput": 606
},
"src/age/age.ts": {
"bytesInOutput": 826
},
"src/gender/gender.ts": {
"bytesInOutput": 1309
},
"src/emotion/emotion.ts": {
"bytesInOutput": 1243
},
"src/embedding/embedding.ts": {
"bytesInOutput": 802
},
"src/posenet/posenet.ts": {
"bytesInOutput": 1007
},
"src/posenet/modelBase.ts": {
"bytesInOutput": 646
},
"src/posenet/heapSort.ts": {
"bytesInOutput": 1017
},
"src/posenet/buildParts.ts": {
"bytesInOutput": 456
},
"src/posenet/decodePose.ts": {
"bytesInOutput": 1292
},
"src/posenet/vectors.ts": {
"bytesInOutput": 346
},
"src/posenet/decoders.ts": {
"bytesInOutput": 768
},
"src/posenet/decodeMultiple.ts": {
"bytesInOutput": 557
},
"src/posenet/util.ts": {
"bytesInOutput": 354
},
"src/handpose/handpose.ts": {
"bytesInOutput": 1263
},
"src/handpose/box.ts": {
"bytesInOutput": 938
},
"src/handpose/util.js": {
"src/handpose/handdetector.ts": {
"bytesInOutput": 1668
},
"src/handpose/util.ts": {
"bytesInOutput": 816
},
"src/handpose/handpipeline.ts": {
"bytesInOutput": 2449
},
"src/handpose/anchors.ts": {
"bytesInOutput": 126985
},
"src/gesture/gesture.ts": {
"bytesInOutput": 2391
},
"src/image.ts": {
"bytesInOutput": 2454
},
"config.js": {
"bytesInOutput": 1426
},
"src/sample.js": {
"src/sample.ts": {
"bytesInOutput": 55295
},
"package.json": {
"bytesInOutput": 16
}
},
"bytes": 1349003
"bytes": 1343005
}
}
}

4949
dist/human.js vendored

File diff suppressed because one or more lines are too long

7
dist/human.js.map vendored

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

16
dist/human.node.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

224
dist/human.node.json vendored
View File

@ -1,18 +1,18 @@
{
"inputs": {
"src/log.js": {
"src/log.ts": {
"bytes": 401,
"imports": []
},
"dist/tfjs.esm.js": {
"bytes": 681,
"bytes": 690,
"imports": []
},
"src/tfjs/backend.js": {
"bytes": 2171,
"src/tfjs/backend.ts": {
"bytes": 2168,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -22,10 +22,10 @@
]
},
"src/blazeface/blazeface.js": {
"bytes": 7024,
"bytes": 6983,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -52,7 +52,7 @@
"imports": []
},
"src/blazeface/facepipeline.js": {
"bytes": 14275,
"bytes": 14028,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -71,16 +71,16 @@
"kind": "import-statement"
},
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
}
]
},
"src/blazeface/facemesh.js": {
"bytes": 2973,
"bytes": 2898,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -101,20 +101,20 @@
}
]
},
"src/profile.js": {
"bytes": 1045,
"src/profile.ts": {
"bytes": 1004,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
}
]
},
"src/faceboxes/faceboxes.js": {
"bytes": 2612,
"src/faceboxes/faceboxes.ts": {
"bytes": 2852,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -122,16 +122,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/age/age.js": {
"bytes": 2037,
"src/age/age.ts": {
"bytes": 2064,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -139,16 +139,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/gender/gender.js": {
"bytes": 2906,
"src/gender/gender.ts": {
"bytes": 2904,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -156,16 +156,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/emotion/emotion.js": {
"bytes": 3056,
"src/emotion/emotion.ts": {
"bytes": 3033,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -173,16 +173,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/embedding/embedding.js": {
"bytes": 2063,
"src/embedding/embedding.ts": {
"bytes": 1992,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -190,7 +190,7 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
@ -244,7 +244,7 @@
]
},
"src/posenet/decodePose.js": {
"bytes": 5368,
"bytes": 5216,
"imports": [
{
"path": "src/posenet/keypoints.js",
@ -261,7 +261,7 @@
]
},
"src/posenet/decodeMultiple.js": {
"bytes": 2373,
"bytes": 2303,
"imports": [
{
"path": "src/posenet/buildParts.js",
@ -286,11 +286,11 @@
}
]
},
"src/posenet/modelPoseNet.js": {
"bytes": 2519,
"src/posenet/posenet.js": {
"bytes": 2406,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -315,23 +315,6 @@
}
]
},
"src/posenet/posenet.js": {
"bytes": 712,
"imports": [
{
"path": "src/posenet/modelPoseNet.js",
"kind": "import-statement"
},
{
"path": "src/posenet/keypoints.js",
"kind": "import-statement"
},
{
"path": "src/posenet/util.js",
"kind": "import-statement"
}
]
},
"src/handpose/box.js": {
"bytes": 2522,
"imports": [
@ -355,11 +338,11 @@
]
},
"src/handpose/util.js": {
"bytes": 2346,
"bytes": 2326,
"imports": []
},
"src/handpose/handpipeline.js": {
"bytes": 7246,
"bytes": 7243,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -374,7 +357,7 @@
"kind": "import-statement"
},
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
}
]
@ -384,10 +367,10 @@
"imports": []
},
"src/handpose/handpose.js": {
"bytes": 2578,
"bytes": 2536,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -408,19 +391,19 @@
}
]
},
"src/gesture/gesture.js": {
"bytes": 4245,
"src/gesture/gesture.ts": {
"bytes": 4265,
"imports": []
},
"src/imagefx.js": {
"bytes": 19445,
"bytes": 19311,
"imports": []
},
"src/image.js": {
"bytes": 5871,
"src/image.ts": {
"bytes": 5851,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -437,7 +420,7 @@
"bytes": 9786,
"imports": []
},
"src/sample.js": {
"src/sample.ts": {
"bytes": 55382,
"imports": []
},
@ -445,11 +428,11 @@
"bytes": 2321,
"imports": []
},
"src/human.js": {
"bytes": 18962,
"src/human.ts": {
"bytes": 19233,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -457,7 +440,7 @@
"kind": "import-statement"
},
{
"path": "src/tfjs/backend.js",
"path": "src/tfjs/backend.ts",
"kind": "import-statement"
},
{
@ -465,23 +448,23 @@
"kind": "import-statement"
},
{
"path": "src/faceboxes/faceboxes.js",
"path": "src/faceboxes/faceboxes.ts",
"kind": "import-statement"
},
{
"path": "src/age/age.js",
"path": "src/age/age.ts",
"kind": "import-statement"
},
{
"path": "src/gender/gender.js",
"path": "src/gender/gender.ts",
"kind": "import-statement"
},
{
"path": "src/emotion/emotion.js",
"path": "src/emotion/emotion.ts",
"kind": "import-statement"
},
{
"path": "src/embedding/embedding.js",
"path": "src/embedding/embedding.ts",
"kind": "import-statement"
},
{
@ -493,15 +476,15 @@
"kind": "import-statement"
},
{
"path": "src/gesture/gesture.js",
"path": "src/gesture/gesture.ts",
"kind": "import-statement"
},
{
"path": "src/image.js",
"path": "src/image.ts",
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
},
{
@ -509,7 +492,7 @@
"kind": "import-statement"
},
{
"path": "src/sample.js",
"path": "src/sample.ts",
"kind": "import-statement"
},
{
@ -524,14 +507,14 @@
"imports": [],
"exports": [],
"inputs": {},
"bytes": 714830
"bytes": 712944
},
"dist/human.node-gpu.js": {
"imports": [],
"exports": [],
"inputs": {
"dist/tfjs.esm.js": {
"bytesInOutput": 545
"bytesInOutput": 550
},
"src/blazeface/blazeface.js": {
"bytesInOutput": 3077
@ -549,25 +532,7 @@
"bytesInOutput": 5593
},
"src/blazeface/facemesh.js": {
"bytesInOutput": 1556
},
"src/profile.js": {
"bytesInOutput": 631
},
"src/faceboxes/faceboxes.js": {
"bytesInOutput": 1425
},
"src/age/age.js": {
"bytesInOutput": 852
},
"src/gender/gender.js": {
"bytesInOutput": 1348
},
"src/emotion/emotion.js": {
"bytesInOutput": 1306
},
"src/embedding/embedding.js": {
"bytesInOutput": 908
"bytesInOutput": 1574
},
"src/posenet/modelBase.js": {
"bytesInOutput": 688
@ -596,11 +561,8 @@
"src/posenet/util.js": {
"bytesInOutput": 1051
},
"src/posenet/modelPoseNet.js": {
"bytesInOutput": 1180
},
"src/posenet/posenet.js": {
"bytesInOutput": 385
"bytesInOutput": 1223
},
"src/handpose/handdetector.js": {
"bytesInOutput": 1844
@ -612,43 +574,61 @@
"bytesInOutput": 127005
},
"src/handpose/handpose.js": {
"bytesInOutput": 1363
"bytesInOutput": 1397
},
"src/gesture/gesture.js": {
"bytesInOutput": 2423
"src/human.ts": {
"bytesInOutput": 10355
},
"src/imagefx.js": {
"bytesInOutput": 10999
},
"src/image.js": {
"bytesInOutput": 2478
},
"src/human.js": {
"bytesInOutput": 10681
},
"src/log.js": {
"src/log.ts": {
"bytesInOutput": 251
},
"src/tfjs/backend.js": {
"src/tfjs/backend.ts": {
"bytesInOutput": 1304
},
"src/faceboxes/faceboxes.ts": {
"bytesInOutput": 1592
},
"src/profile.ts": {
"bytesInOutput": 604
},
"src/age/age.ts": {
"bytesInOutput": 828
},
"src/gender/gender.ts": {
"bytesInOutput": 1337
},
"src/emotion/emotion.ts": {
"bytesInOutput": 1265
},
"src/embedding/embedding.ts": {
"bytesInOutput": 851
},
"src/handpose/box.js": {
"bytesInOutput": 958
},
"src/handpose/util.js": {
"bytesInOutput": 812
},
"src/gesture/gesture.ts": {
"bytesInOutput": 2391
},
"src/image.ts": {
"bytesInOutput": 2434
},
"src/imagefx.js": {
"bytesInOutput": 11045
},
"config.js": {
"bytesInOutput": 1426
},
"src/sample.js": {
"src/sample.ts": {
"bytesInOutput": 55295
},
"package.json": {
"bytesInOutput": 16
}
},
"bytes": 280251
"bytes": 279609
}
}
}

4949
dist/human.ts vendored Normal file

File diff suppressed because one or more lines are too long

7
dist/human.ts.map vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,18 +1,18 @@
{
"inputs": {
"src/log.js": {
"src/log.ts": {
"bytes": 401,
"imports": []
},
"dist/tfjs.esm.js": {
"bytes": 1071833,
"bytes": 1071825,
"imports": []
},
"src/tfjs/backend.js": {
"bytes": 2171,
"src/tfjs/backend.ts": {
"bytes": 2168,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -21,11 +21,11 @@
}
]
},
"src/blazeface/blazeface.js": {
"bytes": 7024,
"src/blazeface/blazeface.ts": {
"bytes": 6024,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -34,8 +34,8 @@
}
]
},
"src/blazeface/box.js": {
"bytes": 1935,
"src/blazeface/box.ts": {
"bytes": 1727,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -43,44 +43,40 @@
}
]
},
"src/blazeface/util.js": {
"bytes": 3087,
"src/blazeface/util.ts": {
"bytes": 2777,
"imports": []
},
"src/blazeface/coords.js": {
"bytes": 37915,
"src/blazeface/coords.ts": {
"bytes": 37783,
"imports": []
},
"src/blazeface/facepipeline.js": {
"bytes": 14275,
"src/blazeface/facepipeline.ts": {
"bytes": 14254,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/blazeface/box.js",
"path": "src/blazeface/box.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/util.js",
"path": "src/blazeface/util.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/coords.js",
"kind": "import-statement"
},
{
"path": "src/log.js",
"path": "src/blazeface/coords.ts",
"kind": "import-statement"
}
]
},
"src/blazeface/facemesh.js": {
"bytes": 2973,
"src/blazeface/facemesh.ts": {
"bytes": 2935,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -88,33 +84,33 @@
"kind": "import-statement"
},
{
"path": "src/blazeface/blazeface.js",
"path": "src/blazeface/blazeface.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/facepipeline.js",
"path": "src/blazeface/facepipeline.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/coords.js",
"path": "src/blazeface/coords.ts",
"kind": "import-statement"
}
]
},
"src/profile.js": {
"bytes": 1045,
"src/profile.ts": {
"bytes": 1004,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
}
]
},
"src/faceboxes/faceboxes.js": {
"bytes": 2612,
"src/faceboxes/faceboxes.ts": {
"bytes": 2852,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -122,16 +118,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/age/age.js": {
"bytes": 2037,
"src/age/age.ts": {
"bytes": 2064,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -139,16 +135,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/gender/gender.js": {
"bytes": 2906,
"src/gender/gender.ts": {
"bytes": 2904,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -156,16 +152,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/emotion/emotion.js": {
"bytes": 3056,
"src/emotion/emotion.ts": {
"bytes": 3033,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -173,16 +169,16 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/embedding/embedding.js": {
"bytes": 2063,
"src/embedding/embedding.ts": {
"bytes": 1992,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -190,13 +186,13 @@
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
}
]
},
"src/posenet/modelBase.js": {
"bytes": 1343,
"src/posenet/modelBase.ts": {
"bytes": 1333,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -204,93 +200,93 @@
}
]
},
"src/posenet/heapSort.js": {
"bytes": 1590,
"src/posenet/heapSort.ts": {
"bytes": 1645,
"imports": []
},
"src/posenet/buildParts.js": {
"bytes": 1775,
"src/posenet/buildParts.ts": {
"bytes": 1723,
"imports": [
{
"path": "src/posenet/heapSort.js",
"path": "src/posenet/heapSort.ts",
"kind": "import-statement"
}
]
},
"src/posenet/keypoints.js": {
"bytes": 2011,
"src/posenet/keypoints.ts": {
"bytes": 2025,
"imports": []
},
"src/posenet/vectors.js": {
"bytes": 1273,
"src/posenet/vectors.ts": {
"bytes": 1075,
"imports": [
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
}
]
},
"src/posenet/decoders.js": {
"bytes": 2083,
"src/posenet/decoders.ts": {
"bytes": 1943,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
}
]
},
"src/posenet/decodePose.js": {
"bytes": 5368,
"src/posenet/decodePose.ts": {
"bytes": 5152,
"imports": [
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/vectors.js",
"path": "src/posenet/vectors.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decoders.js",
"path": "src/posenet/decoders.ts",
"kind": "import-statement"
}
]
},
"src/posenet/decodeMultiple.js": {
"bytes": 2373,
"src/posenet/decodeMultiple.ts": {
"bytes": 2259,
"imports": [
{
"path": "src/posenet/buildParts.js",
"path": "src/posenet/buildParts.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decodePose.js",
"path": "src/posenet/decodePose.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/vectors.js",
"path": "src/posenet/vectors.ts",
"kind": "import-statement"
}
]
},
"src/posenet/util.js": {
"bytes": 2262,
"src/posenet/util.ts": {
"bytes": 2017,
"imports": [
{
"path": "src/posenet/keypoints.js",
"path": "src/posenet/keypoints.ts",
"kind": "import-statement"
}
]
},
"src/posenet/modelPoseNet.js": {
"bytes": 2519,
"src/posenet/posenet.ts": {
"bytes": 2376,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -298,42 +294,25 @@
"kind": "import-statement"
},
{
"path": "src/posenet/modelBase.js",
"path": "src/posenet/modelBase.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decodeMultiple.js",
"path": "src/posenet/decodeMultiple.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/decodePose.js",
"path": "src/posenet/decodePose.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/util.js",
"path": "src/posenet/util.ts",
"kind": "import-statement"
}
]
},
"src/posenet/posenet.js": {
"bytes": 712,
"imports": [
{
"path": "src/posenet/modelPoseNet.js",
"kind": "import-statement"
},
{
"path": "src/posenet/keypoints.js",
"kind": "import-statement"
},
{
"path": "src/posenet/util.js",
"kind": "import-statement"
}
]
},
"src/handpose/box.js": {
"bytes": 2522,
"src/handpose/box.ts": {
"bytes": 2443,
"imports": [
{
"path": "dist/tfjs.esm.js",
@ -341,53 +320,49 @@
}
]
},
"src/handpose/handdetector.js": {
"bytes": 3548,
"src/handpose/handdetector.ts": {
"bytes": 3627,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/handpose/box.js",
"path": "src/handpose/box.ts",
"kind": "import-statement"
}
]
},
"src/handpose/util.js": {
"bytes": 2346,
"src/handpose/util.ts": {
"bytes": 2254,
"imports": []
},
"src/handpose/handpipeline.js": {
"bytes": 7246,
"src/handpose/handpipeline.ts": {
"bytes": 7344,
"imports": [
{
"path": "dist/tfjs.esm.js",
"kind": "import-statement"
},
{
"path": "src/handpose/box.js",
"path": "src/handpose/box.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/util.js",
"kind": "import-statement"
},
{
"path": "src/log.js",
"path": "src/handpose/util.ts",
"kind": "import-statement"
}
]
},
"src/handpose/anchors.js": {
"bytes": 224151,
"src/handpose/anchors.ts": {
"bytes": 224156,
"imports": []
},
"src/handpose/handpose.js": {
"bytes": 2578,
"src/handpose/handpose.ts": {
"bytes": 2529,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -395,32 +370,32 @@
"kind": "import-statement"
},
{
"path": "src/handpose/handdetector.js",
"path": "src/handpose/handdetector.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/handpipeline.js",
"path": "src/handpose/handpipeline.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/anchors.js",
"path": "src/handpose/anchors.ts",
"kind": "import-statement"
}
]
},
"src/gesture/gesture.js": {
"bytes": 4245,
"src/gesture/gesture.ts": {
"bytes": 4265,
"imports": []
},
"src/imagefx.js": {
"bytes": 19445,
"bytes": 19447,
"imports": []
},
"src/image.js": {
"bytes": 5871,
"src/image.ts": {
"bytes": 5851,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -437,19 +412,19 @@
"bytes": 9786,
"imports": []
},
"src/sample.js": {
"src/sample.ts": {
"bytes": 55382,
"imports": []
},
"package.json": {
"bytes": 2321,
"bytes": 2344,
"imports": []
},
"src/human.js": {
"bytes": 18962,
"src/human.ts": {
"bytes": 19393,
"imports": [
{
"path": "src/log.js",
"path": "src/log.ts",
"kind": "import-statement"
},
{
@ -457,51 +432,51 @@
"kind": "import-statement"
},
{
"path": "src/tfjs/backend.js",
"path": "src/tfjs/backend.ts",
"kind": "import-statement"
},
{
"path": "src/blazeface/facemesh.js",
"path": "src/blazeface/facemesh.ts",
"kind": "import-statement"
},
{
"path": "src/faceboxes/faceboxes.js",
"path": "src/faceboxes/faceboxes.ts",
"kind": "import-statement"
},
{
"path": "src/age/age.js",
"path": "src/age/age.ts",
"kind": "import-statement"
},
{
"path": "src/gender/gender.js",
"path": "src/gender/gender.ts",
"kind": "import-statement"
},
{
"path": "src/emotion/emotion.js",
"path": "src/emotion/emotion.ts",
"kind": "import-statement"
},
{
"path": "src/embedding/embedding.js",
"path": "src/embedding/embedding.ts",
"kind": "import-statement"
},
{
"path": "src/posenet/posenet.js",
"path": "src/posenet/posenet.ts",
"kind": "import-statement"
},
{
"path": "src/handpose/handpose.js",
"path": "src/handpose/handpose.ts",
"kind": "import-statement"
},
{
"path": "src/gesture/gesture.js",
"path": "src/gesture/gesture.ts",
"kind": "import-statement"
},
{
"path": "src/image.js",
"path": "src/image.ts",
"kind": "import-statement"
},
{
"path": "src/profile.js",
"path": "src/profile.ts",
"kind": "import-statement"
},
{
@ -509,7 +484,7 @@
"kind": "import-statement"
},
{
"path": "src/sample.js",
"path": "src/sample.ts",
"kind": "import-statement"
},
{
@ -520,135 +495,132 @@
}
},
"outputs": {
"dist/human.js.map": {
"dist/human.ts.map": {
"imports": [],
"exports": [],
"inputs": {},
"bytes": 1932088
"bytes": 1923057
},
"dist/human.js": {
"dist/human.ts": {
"imports": [],
"exports": [],
"inputs": {
"src/blazeface/blazeface.js": {
"bytesInOutput": 2915
"src/blazeface/facemesh.ts": {
"bytesInOutput": 1445
},
"src/blazeface/box.js": {
"bytesInOutput": 987
},
"src/blazeface/util.js": {
"bytesInOutput": 1197
},
"src/blazeface/coords.js": {
"bytesInOutput": 30534
},
"src/blazeface/facepipeline.js": {
"bytesInOutput": 5578
},
"src/blazeface/facemesh.js": {
"bytesInOutput": 1518
},
"src/profile.js": {
"bytesInOutput": 637
},
"src/faceboxes/faceboxes.js": {
"bytesInOutput": 1387
},
"src/age/age.js": {
"bytesInOutput": 813
},
"src/gender/gender.js": {
"bytesInOutput": 1283
},
"src/emotion/emotion.js": {
"bytesInOutput": 1247
},
"src/embedding/embedding.js": {
"bytesInOutput": 870
},
"src/posenet/modelBase.js": {
"bytesInOutput": 679
},
"src/posenet/heapSort.js": {
"bytesInOutput": 1048
},
"src/posenet/buildParts.js": {
"bytesInOutput": 529
},
"src/posenet/keypoints.js": {
"bytesInOutput": 1638
},
"src/posenet/vectors.js": {
"bytesInOutput": 627
},
"src/posenet/decoders.js": {
"bytesInOutput": 875
},
"src/posenet/decodePose.js": {
"bytesInOutput": 1482
},
"src/posenet/decodeMultiple.js": {
"bytesInOutput": 704
},
"src/posenet/util.js": {
"bytesInOutput": 1065
},
"src/posenet/modelPoseNet.js": {
"bytesInOutput": 1167
},
"src/posenet/posenet.js": {
"bytesInOutput": 401
},
"src/handpose/handdetector.js": {
"bytesInOutput": 1704
},
"src/handpose/handpipeline.js": {
"bytesInOutput": 2485
},
"src/handpose/anchors.js": {
"bytesInOutput": 127006
},
"src/handpose/handpose.js": {
"bytesInOutput": 1331
},
"src/gesture/gesture.js": {
"bytesInOutput": 2424
"src/posenet/keypoints.ts": {
"bytesInOutput": 1690
},
"src/imagefx.js": {
"bytesInOutput": 11004
"bytesInOutput": 11016
},
"src/image.js": {
"bytesInOutput": 2480
"src/human.ts": {
"bytesInOutput": 10259
},
"src/human.js": {
"bytesInOutput": 10573
},
"src/log.js": {
"src/log.ts": {
"bytesInOutput": 252
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1062888
"bytesInOutput": 1062782
},
"src/tfjs/backend.js": {
"src/tfjs/backend.ts": {
"bytesInOutput": 1205
},
"src/handpose/box.js": {
"src/blazeface/blazeface.ts": {
"bytesInOutput": 2185
},
"src/blazeface/box.ts": {
"bytesInOutput": 834
},
"src/blazeface/util.ts": {
"bytesInOutput": 858
},
"src/blazeface/coords.ts": {
"bytesInOutput": 28983
},
"src/blazeface/facepipeline.ts": {
"bytesInOutput": 5046
},
"src/faceboxes/faceboxes.ts": {
"bytesInOutput": 1549
},
"src/profile.ts": {
"bytesInOutput": 606
},
"src/age/age.ts": {
"bytesInOutput": 826
},
"src/gender/gender.ts": {
"bytesInOutput": 1309
},
"src/emotion/emotion.ts": {
"bytesInOutput": 1243
},
"src/embedding/embedding.ts": {
"bytesInOutput": 802
},
"src/posenet/posenet.ts": {
"bytesInOutput": 1007
},
"src/posenet/modelBase.ts": {
"bytesInOutput": 646
},
"src/posenet/heapSort.ts": {
"bytesInOutput": 1017
},
"src/posenet/buildParts.ts": {
"bytesInOutput": 456
},
"src/posenet/decodePose.ts": {
"bytesInOutput": 1292
},
"src/posenet/vectors.ts": {
"bytesInOutput": 346
},
"src/posenet/decoders.ts": {
"bytesInOutput": 768
},
"src/posenet/decodeMultiple.ts": {
"bytesInOutput": 557
},
"src/posenet/util.ts": {
"bytesInOutput": 354
},
"src/handpose/handpose.ts": {
"bytesInOutput": 1263
},
"src/handpose/box.ts": {
"bytesInOutput": 938
},
"src/handpose/util.js": {
"src/handpose/handdetector.ts": {
"bytesInOutput": 1668
},
"src/handpose/util.ts": {
"bytesInOutput": 816
},
"src/handpose/handpipeline.ts": {
"bytesInOutput": 2449
},
"src/handpose/anchors.ts": {
"bytesInOutput": 126985
},
"src/gesture/gesture.ts": {
"bytesInOutput": 2391
},
"src/image.ts": {
"bytesInOutput": 2454
},
"config.js": {
"bytesInOutput": 1426
},
"src/sample.js": {
"src/sample.ts": {
"bytesInOutput": 55295
},
"package.json": {
"bytesInOutput": 16
}
},
"bytes": 1349045
"bytes": 1343047
}
}
}

234
dist/tfjs.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
dist/tfjs.esm.json vendored
View File

@ -25407,7 +25407,7 @@
}
]
},
"src/tfjs/tf-browser.js": {
"src/tfjs/tf-browser.ts": {
"bytes": 1784,
"imports": [
{
@ -28613,7 +28613,7 @@
"node_modules/@tensorflow/tfjs-backend-wasm/dist/index.js": {
"bytesInOutput": 0
},
"src/tfjs/tf-browser.js": {
"src/tfjs/tf-browser.ts": {
"bytesInOutput": 154
},
"node_modules/@tensorflow/tfjs-core/dist/public/chained_ops/abs.js": {
@ -29739,7 +29739,7 @@
"bytesInOutput": 15
}
},
"bytes": 1071833
"bytes": 1071825
}
}
}

24
package-lock.json generated
View File

@ -821,9 +821,9 @@
}
},
"esbuild": {
"version": "0.8.42",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.42.tgz",
"integrity": "sha512-zUtj5RMqROCCCH0vV/a7cd8YQg8I0GWBhV3A3PklWRT+oM/YwVbnrtFnITzE1otGdnXplWHWdZ4OcYiV0PN+JQ==",
"version": "0.8.43",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.43.tgz",
"integrity": "sha512-ZVE2CpootS4jtnfV0bbtJdgRsHEXcMP0P7ZXGfTmNzzhBr2e5ag7Vp3ry0jmw8zduJz4iHzxg4m5jtPxWERz1w==",
"dev": true
},
"escalade": {
@ -2285,9 +2285,9 @@
"dev": true
},
"simple-git": {
"version": "2.32.0",
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.32.0.tgz",
"integrity": "sha512-swz7avV2JADYgTmvs+j/eDBt+gPx3SAyh2MxlDVvxqHzHLkKr6kLr4N62qZCv5LBxc9Wx8TIXVeJKmTTY8UdSQ==",
"version": "2.34.2",
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.34.2.tgz",
"integrity": "sha512-/EX4FtcpAj5L/Bs5zgaBGYDrnkrKflFVNppNLH9VXpIjZBLHx5cZ6/mOYJCoKXKlLRuk3iTvzrIsHo7v42zWHg==",
"dev": true,
"requires": {
"@kwsites/file-exists": "^1.1.1",
@ -2505,6 +2505,12 @@
"strip-bom": "^3.0.0"
}
},
"tslib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz",
"integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==",
"dev": true
},
"type-check": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz",
@ -2520,6 +2526,12 @@
"integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true
},
"typescript": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz",
"integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==",
"dev": true
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",

View File

@ -35,7 +35,7 @@
"@vladmandic/pilogger": "^0.2.14",
"chokidar": "^3.5.1",
"dayjs": "^1.10.4",
"esbuild": "^0.8.42",
"esbuild": "^0.8.43",
"eslint": "^7.19.0",
"eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.22.1",
@ -44,7 +44,9 @@
"eslint-plugin-promise": "^4.2.1",
"rimraf": "^3.0.2",
"seedrandom": "^3.0.5",
"simple-git": "^2.32.0"
"simple-git": "^2.34.2",
"tslib": "^2.1.0",
"typescript": "^4.1.3"
},
"scripts": {
"start": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",

View File

@ -6,6 +6,7 @@ const log = require('@vladmandic/pilogger');
// keeps esbuild service instance cached
let es;
let busy = false;
const banner = `
/*
Human library
@ -33,7 +34,7 @@ const targets = {
platform: 'node',
format: 'cjs',
metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-node.js'],
entryPoints: ['src/tfjs/tf-node.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'],
},
@ -41,7 +42,7 @@ const targets = {
platform: 'node',
format: 'cjs',
metafile: 'dist/human.node.json',
entryPoints: ['src/human.js'],
entryPoints: ['src/human.ts'],
outfile: 'dist/human.node.js',
external: ['@tensorflow'],
},
@ -51,7 +52,7 @@ const targets = {
platform: 'node',
format: 'cjs',
metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-node-gpu.js'],
entryPoints: ['src/tfjs/tf-node-gpu.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'],
},
@ -59,7 +60,7 @@ const targets = {
platform: 'node',
format: 'cjs',
metafile: 'dist/human.node.json',
entryPoints: ['src/human.js'],
entryPoints: ['src/human.ts'],
outfile: 'dist/human.node-gpu.js',
external: ['@tensorflow'],
},
@ -69,7 +70,7 @@ const targets = {
platform: 'browser',
format: 'esm',
metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-browser.js'],
entryPoints: ['src/tfjs/tf-browser.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['fs', 'buffer', 'util', '@tensorflow'],
},
@ -77,7 +78,7 @@ const targets = {
platform: 'browser',
format: 'esm',
metafile: 'dist/human.esm.json',
entryPoints: ['src/human.js'],
entryPoints: ['src/human.ts'],
outfile: 'dist/human.esm-nobundle.js',
external: ['fs', 'buffer', 'util', '@tensorflow'],
},
@ -87,7 +88,7 @@ const targets = {
platform: 'browser',
format: 'esm',
metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-browser.js'],
entryPoints: ['src/tfjs/tf-browser.ts'],
outfile: 'dist/tfjs.esm.js',
external: ['fs', 'buffer', 'util'],
},
@ -95,16 +96,16 @@ const targets = {
platform: 'browser',
format: 'iife',
globalName: 'Human',
metafile: 'dist/human.json',
entryPoints: ['src/human.js'],
outfile: 'dist/human.js',
metafile: 'dist/human.tson',
entryPoints: ['src/human.ts'],
outfile: 'dist/human.ts',
external: ['fs', 'buffer', 'util'],
},
esm: {
platform: 'browser',
format: 'esm',
metafile: 'dist/human.esm.json',
entryPoints: ['src/human.js'],
entryPoints: ['src/human.ts'],
outfile: 'dist/human.esm.js',
external: ['fs', 'buffer', 'util'],
},
@ -148,6 +149,12 @@ async function getStats(metafile) {
// rebuild on file change
async function build(f, msg) {
if (busy) {
log.state('Build: busy...');
setTimeout(() => build(f, msg), 500);
return;
}
busy = true;
log.info('Build: file', msg, f, 'target:', common.target);
if (!es) es = await esbuild.startService();
// common build options
@ -168,6 +175,7 @@ async function build(f, msg) {
log.error('Build error', JSON.stringify(err.errors || err, null, 2));
if (require.main === module) process.exit(1);
}
busy = false;
}
if (require.main === module) {

View File

@ -21,9 +21,9 @@ Repository: **<${app.repository.url}>**
`;
async function update(f) {
const all = await git.log();
const gitLog = await git.log();
// @ts-ignore
const log = all.all.sort((a, b) => (new Date(b.date).getTime() - new Date(a.date).getTime()));
const log = gitLog.all.sort((a, b) => (new Date(b.date).getTime() - new Date(a.date).getTime()));
let previous = '';
for (const l of log) {

View File

@ -52,6 +52,14 @@ const mime = {
'.wasm': 'application/wasm',
};
let last = Date.now();
async function buildAll(evt, msg) {
const now = Date.now();
if ((now - last) > 2) build.build(evt, msg);
else log.state('Build: merge event file', msg, evt);
last = now;
}
// watch filesystem for any changes and notify build when needed
async function watch() {
const watcher = chokidar.watch(options.monitor, {
@ -66,9 +74,9 @@ async function watch() {
});
// single event handler for file add/change/delete
watcher
.on('add', (evt) => build.build(evt, 'add'))
.on('change', (evt) => build.build(evt, 'modify'))
.on('unlink', (evt) => build.build(evt, 'remove'))
.on('add', (evt) => buildAll(evt, 'add'))
.on('change', (evt) => buildAll(evt, 'modify'))
.on('unlink', (evt) => buildAll(evt, 'remove'))
.on('error', (err) => log.error(`Client watcher error: ${err}`))
.on('ready', () => log.state('Monitoring:', options.monitor));
}

View File

@ -1,12 +1,12 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js';
const models = {};
const models = { age: null };
let last = { age: 0 };
let skipped = Number.MAX_SAFE_INTEGER;
async function load(config) {
export async function load(config) {
if (!models.age) {
models.age = await tf.loadGraphModel(config.face.age.modelPath);
log(`load model: ${config.face.age.modelPath.match(/\/(.*)\./)[1]}`);
@ -14,7 +14,7 @@ async function load(config) {
return models.age;
}
async function predict(image, config) {
export async function predict(image, config) {
if (!models.age) return null;
if ((skipped < config.face.age.skipFrames) && config.videoOptimized && last.age && (last.age > 0)) {
skipped++;
@ -38,29 +38,27 @@ async function predict(image, config) {
tf.dispose(resize);
let ageT;
const obj = {};
const obj = { age: undefined };
if (!config.profile) {
if (config.face.age.enabled) ageT = await models.age.predict(enhance);
} else {
const profileAge = config.face.age.enabled ? await tf.profile(() => models.age.predict(enhance)) : {};
ageT = profileAge.result.clone();
profileAge.result.dispose();
// @ts-ignore
profile.run('age', profileAge);
if (models.age) {
if (!config.profile) {
if (config.face.age.enabled) ageT = await models.age.predict(enhance);
} else {
const profileAge = config.face.age.enabled ? await tf.profile(() => models.age.predict(enhance)) : {};
ageT = profileAge.result.clone();
profileAge.result.dispose();
profile.run('age', profileAge);
}
enhance.dispose();
if (ageT) {
const data = ageT.dataSync();
obj.age = Math.trunc(10 * data[0]) / 10;
}
ageT.dispose();
last = obj;
}
enhance.dispose();
if (ageT) {
const data = ageT.dataSync();
obj.age = Math.trunc(10 * data[0]) / 10;
}
ageT.dispose();
last = obj;
resolve(obj);
});
}
exports.predict = predict;
exports.load = load;

View File

@ -1,4 +1,4 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
const NUM_LANDMARKS = 6;
@ -24,7 +24,7 @@ function generateAnchors(inputSize) {
return anchors;
}
const disposeBox = (box) => {
export const disposeBox = (box) => {
box.startEndTensor.dispose();
box.startPoint.dispose();
box.endPoint.dispose();
@ -65,7 +65,16 @@ function scaleBoxFromPrediction(face, scaleFactor) {
});
}
class BlazeFaceModel {
export class BlazeFaceModel {
blazeFaceModel: any;
width: number;
height: number;
anchorsData: any;
anchors: any;
inputSize: number;
config: any;
scaleFaces: number;
constructor(model, config) {
this.blazeFaceModel = model;
this.width = config.face.detector.inputSize;
@ -132,47 +141,11 @@ class BlazeFaceModel {
scaleFactor: [inputImage.shape[2] / this.width, inputImage.shape[1] / this.height],
};
}
async estimateFaces(input) {
// @ts-ignore
const { boxes, scaleFactor } = await this.getBoundingBoxes(input);
const faces = [];
for (const face of boxes) {
const landmarkData = face.landmarks.arraySync();
const scaledBox = scaleBoxFromPrediction(face, scaleFactor);
// @ts-ignore
const boxData = scaleBox.arraySync();
const probabilityData = face.probability.arraySync();
const anchor = face.anchor;
const [scaleFactorX, scaleFactorY] = scaleFactor;
const scaledLandmarks = landmarkData
.map((landmark) => ([
(landmark[0] + anchor[0]) * scaleFactorX,
(landmark[1] + anchor[1]) * scaleFactorY,
]));
const normalizedFace = {
topLeft: boxData.slice(0, 2),
bottomRight: boxData.slice(2),
landmarks: scaledLandmarks,
probability: probabilityData,
};
disposeBox(face.box);
face.landmarks.dispose();
face.probability.dispose();
scaledBox.dispose();
faces.push(normalizedFace);
}
return faces;
}
}
async function load(config) {
export async function load(config) {
const blazeface = await tf.loadGraphModel(config.face.detector.modelPath, { fromTFHub: config.face.detector.modelPath.includes('tfhub.dev') });
const model = new BlazeFaceModel(blazeface, config);
log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`);
return model;
}
exports.load = load;
exports.BlazeFaceModel = BlazeFaceModel;
exports.disposeBox = disposeBox;

View File

@ -1,29 +1,26 @@
import * as tf from '../../dist/tfjs.esm.js';
function scaleBoxCoordinates(box, factor) {
export function scaleBoxCoordinates(box, factor) {
const startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];
const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];
return { startPoint, endPoint };
}
exports.scaleBoxCoordinates = scaleBoxCoordinates;
function getBoxSize(box) {
export function getBoxSize(box) {
return [
Math.abs(box.endPoint[0] - box.startPoint[0]),
Math.abs(box.endPoint[1] - box.startPoint[1]),
];
}
exports.getBoxSize = getBoxSize;
function getBoxCenter(box) {
export function getBoxCenter(box) {
return [
box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,
box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 2,
];
}
exports.getBoxCenter = getBoxCenter;
function cutBoxFromImageAndResize(box, image, cropSize) {
export function cutBoxFromImageAndResize(box, image, cropSize) {
const h = image.shape[1];
const w = image.shape[2];
const boxes = [[
@ -32,9 +29,8 @@ function cutBoxFromImageAndResize(box, image, cropSize) {
]];
return tf.image.cropAndResize(image, boxes, [0], cropSize);
}
exports.cutBoxFromImageAndResize = cutBoxFromImageAndResize;
function enlargeBox(box, factor = 1.5) {
export function enlargeBox(box, factor = 1.5) {
const center = getBoxCenter(box);
const size = getBoxSize(box);
const newHalfSize = [factor * size[0] / 2, factor * size[1] / 2];
@ -42,9 +38,8 @@ function enlargeBox(box, factor = 1.5) {
const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];
return { startPoint, endPoint, landmarks: box.landmarks };
}
exports.enlargeBox = enlargeBox;
function squarifyBox(box) {
export function squarifyBox(box) {
const centers = getBoxCenter(box);
const size = getBoxSize(box);
const maxEdge = Math.max(...size);
@ -53,4 +48,3 @@ function squarifyBox(box) {
const endPoint = [centers[0] + halfSize, centers[1] + halfSize];
return { startPoint, endPoint, landmarks: box.landmarks };
}
exports.squarifyBox = squarifyBox;

View File

@ -1,4 +1,4 @@
const MESH_ANNOTATIONS = {
export const MESH_ANNOTATIONS = {
silhouette: [
10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288,
397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136,
@ -37,7 +37,7 @@ const MESH_ANNOTATIONS = {
leftCheek: [425],
};
const MESH_TO_IRIS_INDICES_MAP = [ // A mapping from facemesh model keypoints to iris model keypoints.
export const MESH_TO_IRIS_INDICES_MAP = [ // A mapping from facemesh model keypoints to iris model keypoints.
{ key: 'EyeUpper0', indices: [9, 10, 11, 12, 13, 14, 15] },
{ key: 'EyeUpper1', indices: [25, 26, 27, 28, 29, 30, 31] },
{ key: 'EyeUpper2', indices: [41, 42, 43, 44, 45, 46, 47] },
@ -49,7 +49,7 @@ const MESH_TO_IRIS_INDICES_MAP = [ // A mapping from facemesh model keypoints to
// { key: 'EyebrowLower', indices: [48, 49, 50, 51, 52, 53] },
];
const UV468 = [
export const UV468 = [
[0.499976992607117, 0.652534008026123],
[0.500025987625122, 0.547487020492554],
[0.499974012374878, 0.602371990680695],
@ -520,7 +520,7 @@ const UV468 = [
[0.723330020904541, 0.363372981548309],
];
const TRI468 = [
export const TRI468 = [
127, 34, 139, 11, 0, 37, 232, 231, 120, 72, 37, 39, 128, 121, 47, 232, 121, 128, 104, 69, 67, 175, 171, 148, 157, 154, 155, 118, 50, 101, 73, 39, 40, 9,
151, 108, 48, 115, 131, 194, 204, 211, 74, 40, 185, 80, 42, 183, 40, 92, 186, 230, 229, 118, 202, 212, 214, 83, 18, 17, 76, 61, 146, 160, 29, 30, 56,
157, 173, 106, 204, 194, 135, 214, 192, 203, 165, 98, 21, 71, 68, 51, 45, 4, 144, 24, 23, 77, 146, 91, 205, 50, 187, 201, 200, 18, 91, 106, 182, 90, 91,
@ -606,7 +606,7 @@ const TRI468 = [
259, 443, 259, 260, 444, 260, 467, 445, 309, 459, 250, 305, 289, 290, 305, 290, 460, 401, 376, 435, 309, 250, 392, 376, 411, 433, 453, 341, 464, 357,
453, 465, 343, 357, 412, 437, 343, 399, 344, 360, 440, 420, 437, 456, 360, 420, 363, 361, 401, 288, 265, 372, 353, 390, 339, 249, 339, 448, 255];
const TRI68 = [0, 1, 36, 0, 36, 17, 1, 2, 41, 1, 41, 36, 2, 3, 31, 2, 31, 41, 3, 4, 48, 3, 48, 31, 4, 5, 48, 5, 6, 48, 6, 7, 59, 6, 59, 48, 7, 8, 58, 7, 58, 59,
export const TRI68 = [0, 1, 36, 0, 36, 17, 1, 2, 41, 1, 41, 36, 2, 3, 31, 2, 31, 41, 3, 4, 48, 3, 48, 31, 4, 5, 48, 5, 6, 48, 6, 7, 59, 6, 59, 48, 7, 8, 58, 7, 58, 59,
8, 9, 56, 8, 56, 57, 8, 57, 58, 9, 10, 55, 9, 55, 56, 10, 11, 54, 10, 54, 55, 11, 12, 54, 12, 13, 54, 13, 14, 35, 13, 35, 54, 14, 15, 46, 14, 46, 35, 15, 16,
45, 15, 45, 46, 16, 26, 45, 17, 36, 18, 18, 37, 19, 18, 36, 37, 19, 38, 20, 19, 37, 38, 20, 39, 21, 20, 38, 39, 21, 39, 27, 22, 42, 23, 22, 27, 42, 23, 43, 24,
23, 42, 43, 24, 44, 25, 24, 43, 44, 25, 45, 26, 25, 44, 45, 27, 39, 28, 27, 28, 42, 28, 39, 29, 28, 29, 42, 29, 31, 30, 29, 30, 35, 29, 40, 31, 29, 35, 47, 29,
@ -614,7 +614,8 @@ const TRI68 = [0, 1, 36, 0, 36, 17, 1, 2, 41, 1, 41, 36, 2, 3, 31, 2, 31, 41, 3,
35, 34, 51, 52, 35, 46, 47, 35, 52, 53, 35, 53, 54, 36, 41, 37, 37, 40, 38, 37, 41, 40, 38, 40, 39, 42, 47, 43, 43, 47, 44, 44, 46, 45, 44, 47, 46, 48, 60, 49,
48, 59, 60, 49, 61, 50, 49, 60, 61, 50, 62, 51, 50, 61, 62, 51, 62, 52, 52, 63, 53, 52, 62, 63, 53, 64, 54, 53, 63, 64, 54, 64, 55, 55, 65, 56, 55, 64, 65, 56,
66, 57, 56, 65, 66, 57, 66, 58, 58, 67, 59, 58, 66, 67, 59, 67, 60, 60, 67, 61, 61, 66, 62, 61, 67, 66, 62, 66, 63, 63, 65, 64, 63, 66, 65, 21, 27, 22];
const TRI33 = [
export const TRI33 = [
/* eyes */ 0, 8, 7, 7, 8, 1, 2, 10, 9, 9, 10, 3,
/* brows */ 17, 0, 18, 18, 0, 7, 18, 7, 19, 19, 7, 1, 19, 1, 11, 19, 11, 20, 21, 3, 22, 21, 9, 3, 20, 9, 21, 20, 2, 9, 20, 11, 2,
/* 4head */ 23, 17, 18, 25, 21, 22, 24, 19, 20, 24, 18, 19, 24, 20, 21, 24, 23, 18, 24, 21, 25,
@ -624,9 +625,10 @@ const TRI33 = [
/* chin */ 5, 32, 16, 16, 32, 6, 5, 30, 32, 6, 32, 31,
/* cont */ 26, 30, 5, 27, 6, 31, 0, 28, 26, 3, 27, 29, 17, 28, 0, 3, 29, 22, 23, 28, 17, 22, 29, 25, 28, 30, 26, 27, 31, 29,
];
const TRI7 = [0, 4, 1, 2, 4, 3, 4, 5, 6];
const VTX68 = [
export const TRI7 = [0, 4, 1, 2, 4, 3, 4, 5, 6];
export const VTX68 = [
/* cont */ 127, 234, 132, 58, 172, 150, 149, 148, 152, 377, 378, 379, 397, 288, 361, 454, 356,
/* brows */ 70, 63, 105, 66, 107, 336, 296, 334, 293, 300,
/* nose */ 168, 6, 195, 4, 98, 97, 2, 326, 327,
@ -634,18 +636,13 @@ const VTX68 = [
/* lip */ 57, 40, 37, 0, 267, 270, 287, 321, 314, 17, 84, 91,
/* mouth */ 78, 81, 13, 311, 308, 402, 14, 178,
];
const VTX33 = [33, 133, 362, 263, 1, 62, 308, 159, 145, 386, 374, 6, 102, 331, 2, 13, 14, 70, 105, 107, 336, 334, 300, 54, 10, 284, 50, 280, 234, 454, 58, 288, 152];
const VTX7 = [33, 133, 362, 263, 1, 78, 308];
exports.MESH_ANNOTATIONS = MESH_ANNOTATIONS;
exports.MESH_TO_IRIS_INDICES_MAP = MESH_TO_IRIS_INDICES_MAP;
export const VTX33 = [33, 133, 362, 263, 1, 62, 308, 159, 145, 386, 374, 6, 102, 331, 2, 13, 14, 70, 105, 107, 336, 334, 300, 54, 10, 284, 50, 280, 234, 454, 58, 288, 152];
exports.TRI468 = TRI468;
exports.TRI68 = TRI68;
exports.TRI33 = TRI33;
exports.TRI7 = TRI7;
export const VTX7 = [33, 133, 362, 263, 1, 78, 308];
exports.UV468 = UV468;
exports.UV68 = VTX68.map((x) => UV468[x]);
exports.UV33 = VTX33.map((x) => UV468[x]);
exports.UV7 = VTX7.map((x) => UV468[x]);
export const UV68 = VTX68.map((x) => UV468[x]);
export const UV33 = VTX33.map((x) => UV468[x]);
export const UV7 = VTX7.map((x) => UV468[x]);

View File

@ -1,12 +1,14 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as blazeface from './blazeface.js';
import * as facepipeline from './facepipeline.js';
import * as coords from './coords.js';
class MediaPipeFaceMesh {
export class MediaPipeFaceMesh {
facePipeline: any;
config: any;
constructor(blazeFace, blazeMeshModel, irisModel, config) {
// @ts-ignore
this.facePipeline = new facepipeline.Pipeline(blazeFace, blazeMeshModel, irisModel, config);
this.config = config;
}
@ -48,7 +50,7 @@ class MediaPipeFaceMesh {
}
let faceModels = [null, null, null];
async function load(config) {
export async function load(config) {
faceModels = await Promise.all([
(!faceModels[0] && config.face.enabled) ? blazeface.load(config) : null,
(!faceModels[1] && config.face.mesh.enabled) ? tf.loadGraphModel(config.face.mesh.modelPath, { fromTFHub: config.face.mesh.modelPath.includes('tfhub.dev') }) : null,
@ -60,6 +62,4 @@ async function load(config) {
return faceMesh;
}
exports.load = load;
exports.MediaPipeFaceMesh = MediaPipeFaceMesh;
exports.triangulation = coords.TRI468;

View File

@ -4,7 +4,7 @@ import * as bounding from './box';
import * as util from './util';
import * as coords from './coords.js';
// eslint-disable-next-line no-unused-vars
import { log } from '../log.js';
import { log } from '../log';
const LANDMARKS_COUNT = 468;
const MESH_MOUTH_INDEX = 13;
@ -22,11 +22,11 @@ const IRIS_IRIS_INDEX = 71;
const IRIS_NUM_COORDINATES = 76;
// Replace the raw coordinates returned by facemesh with refined iris model coordinates. Update the z coordinate to be an average of the original and the new. This produces the best visual effect.
function replaceRawCoordinates(rawCoords, newCoords, prefix, keys) {
function replaceRawCoordinates(rawCoords, newCoords, prefix, keys = null) {
for (let i = 0; i < coords.MESH_TO_IRIS_INDICES_MAP.length; i++) {
const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i];
const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`];
const shouldReplaceAllKeys = keys == null;
const shouldReplaceAllKeys = keys === null;
if (shouldReplaceAllKeys || keys.includes(key)) {
for (let j = 0; j < indices.length; j++) {
const index = indices[j];
@ -39,7 +39,19 @@ function replaceRawCoordinates(rawCoords, newCoords, prefix, keys) {
}
}
// The Pipeline coordinates between the bounding box and skeleton models.
class Pipeline {
export class Pipeline {
storedBoxes: any;
runsWithoutFaceDetector: number;
boundingBoxDetector: any;
meshDetector: any;
irisModel: any;
meshWidth: number;
meshHeight: number;
irisSize: number;
irisEnlarge: number;
skipped: number;
detectedFaces: number;
constructor(boundingBoxDetector, meshDetector, irisModel, config) {
// An array of facial bounding boxes.
this.storedBoxes = [];
@ -56,7 +68,6 @@ class Pipeline {
}
transformRawCoords(rawCoords, box, angle, rotationMatrix) {
// @ts-ignore
const boxSize = bounding.getBoxSize({ startPoint: box.startPoint, endPoint: box.endPoint });
const scaleFactor = [boxSize[0] / this.meshWidth, boxSize[1] / this.meshHeight];
const coordsScaled = rawCoords.map((coord) => ([
@ -66,7 +77,6 @@ class Pipeline {
const coordsRotationMatrix = (angle !== 0) ? util.buildRotationMatrix(angle, [0, 0]) : util.IDENTITY_MATRIX;
const coordsRotated = (angle !== 0) ? coordsScaled.map((coord) => ([...util.rotatePoint(coord, coordsRotationMatrix), coord[2]])) : coordsScaled;
const inverseRotationMatrix = (angle !== 0) ? util.invertTransformMatrix(rotationMatrix) : util.IDENTITY_MATRIX;
// @ts-ignore
const boxCenter = [...bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint }), 1];
return coordsRotated.map((coord) => ([
coord[0] + util.dot(boxCenter, inverseRotationMatrix[0]),
@ -83,9 +93,7 @@ class Pipeline {
// Returns a box describing a cropped region around the eye fit for passing to the iris model.
getEyeBox(rawCoords, face, eyeInnerCornerIndex, eyeOuterCornerIndex, flip = false) {
// @ts-ignore
const box = bounding.squarifyBox(bounding.enlargeBox(this.calculateLandmarksBoundingBox([rawCoords[eyeInnerCornerIndex], rawCoords[eyeOuterCornerIndex]]), this.irisEnlarge));
// @ts-ignore
const boxSize = bounding.getBoxSize(box);
let crop = tf.image.cropAndResize(face, [[
box.startPoint[1] / this.meshHeight,
@ -159,11 +167,8 @@ class Pipeline {
return null;
}
for (let i = 0; i < this.storedBoxes.length; i++) {
// @ts-ignore
const scaledBox = bounding.scaleBoxCoordinates({ startPoint: this.storedBoxes[i].startPoint, endPoint: this.storedBoxes[i].endPoint }, detector.scaleFactor);
// @ts-ignore
const enlargedBox = bounding.enlargeBox(scaledBox);
// @ts-ignore
const squarifiedBox = bounding.squarifyBox(enlargedBox);
const landmarks = this.storedBoxes[i].landmarks.arraySync();
const confidence = this.storedBoxes[i].confidence;
@ -188,17 +193,14 @@ class Pipeline {
if (config.face.detector.rotation) {
const [indexOfMouth, indexOfForehead] = (box.landmarks.length >= LANDMARKS_COUNT) ? MESH_KEYPOINTS_LINE_OF_SYMMETRY_INDICES : BLAZEFACE_KEYPOINTS_LINE_OF_SYMMETRY_INDICES;
angle = util.computeRotation(box.landmarks[indexOfMouth], box.landmarks[indexOfForehead]);
// @ts-ignore
const faceCenter = bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint });
const faceCenterNormalized = [faceCenter[0] / input.shape[2], faceCenter[1] / input.shape[1]];
const rotatedImage = tf.image.rotateWithOffset(input, angle, 0, faceCenterNormalized);
rotationMatrix = util.buildRotationMatrix(-angle, faceCenter);
// @ts-ignore
face = bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotatedImage, [this.meshHeight, this.meshWidth]).div(255);
} else {
rotationMatrix = util.IDENTITY_MATRIX;
const cloned = input.clone();
// @ts-ignore
face = bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, cloned, [this.meshHeight, this.meshWidth]).div(255);
}
@ -215,8 +217,8 @@ class Pipeline {
}
const [, confidence, contourCoords] = this.meshDetector.predict(face); // The first returned tensor represents facial contours, which are included in the coordinates.
const confidenceVal = confidence.dataSync()[0];
if (confidenceVal < config.face.detector.minConfidence) return null; // if below confidence just exit
const faceConfidence = confidence.dataSync()[0];
if (faceConfidence < config.face.detector.minConfidence) return null; // if below confidence just exit
const coordsReshaped = tf.reshape(contourCoords, [-1, 3]);
let rawCoords = coordsReshaped.arraySync();
@ -245,20 +247,19 @@ class Pipeline {
}
const transformedCoordsData = this.transformRawCoords(rawCoords, box, angle, rotationMatrix);
// @ts-ignore
const landmarksBox = bounding.enlargeBox(this.calculateLandmarksBoundingBox(transformedCoordsData));
// @ts-ignore
const squarifiedLandmarksBox = bounding.squarifyBox(landmarksBox);
const transformedCoords = tf.tensor2d(transformedCoordsData);
const prediction = {
coords: transformedCoords,
box: landmarksBox,
faceConfidence: confidenceVal,
faceConfidence,
confidence: box.confidence,
image: face,
rawCoords,
};
if (config.face.mesh.returnRawData) prediction.rawCoords = rawCoords;
this.storedBoxes[i] = { ...squarifiedLandmarksBox, landmarks: transformedCoords.arraySync(), confidence: box.confidence, faceConfidence: confidenceVal };
if (!config.face.mesh.returnRawData) delete prediction.rawCoords;
this.storedBoxes[i] = { ...squarifiedLandmarksBox, landmarks: transformedCoords.arraySync(), confidence: box.confidence, faceConfidence };
return prediction;
}));
@ -275,4 +276,3 @@ class Pipeline {
return { startPoint, endPoint, landmarks };
}
}
exports.Pipeline = Pipeline;

View File

@ -1,52 +1,47 @@
exports.IDENTITY_MATRIX = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
export const IDENTITY_MATRIX = [[1, 0, 0], [0, 1, 0], [0, 0, 1]];
/**
* Normalizes the provided angle to the range -pi to pi.
* @param angle The angle in radians to be normalized.
*/
function normalizeRadians(angle) {
export function normalizeRadians(angle) {
return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));
}
exports.normalizeRadians = normalizeRadians;
/**
* Computes the angle of rotation between two anchor points.
* @param point1 First anchor point
* @param point2 Second anchor point
*/
function computeRotation(point1, point2) {
export function computeRotation(point1, point2) {
const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);
return normalizeRadians(radians);
}
exports.computeRotation = computeRotation;
function radToDegrees(rad) {
export function radToDegrees(rad) {
return rad * 180 / Math.PI;
}
exports.radToDegrees = radToDegrees;
function buildTranslationMatrix(x, y) {
export function buildTranslationMatrix(x, y) {
return [[1, 0, x], [0, 1, y], [0, 0, 1]];
}
function dot(v1, v2) {
export function dot(v1, v2) {
let product = 0;
for (let i = 0; i < v1.length; i++) {
product += v1[i] * v2[i];
}
return product;
}
exports.dot = dot;
function getColumnFrom2DArr(arr, columnIndex) {
export function getColumnFrom2DArr(arr, columnIndex) {
const column = [];
for (let i = 0; i < arr.length; i++) {
column.push(arr[i][columnIndex]);
}
return column;
}
exports.getColumnFrom2DArr = getColumnFrom2DArr;
function multiplyTransformMatrices(mat1, mat2) {
export function multiplyTransformMatrices(mat1, mat2) {
const product = [];
const size = mat1.length;
for (let row = 0; row < size; row++) {
@ -57,7 +52,8 @@ function multiplyTransformMatrices(mat1, mat2) {
}
return product;
}
function buildRotationMatrix(rotation, center) {
export function buildRotationMatrix(rotation, center) {
const cosA = Math.cos(rotation);
const sinA = Math.sin(rotation);
const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]];
@ -66,9 +62,8 @@ function buildRotationMatrix(rotation, center) {
const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);
return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix);
}
exports.buildRotationMatrix = buildRotationMatrix;
function invertTransformMatrix(matrix) {
export function invertTransformMatrix(matrix) {
const rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];
const translationComponent = [matrix[0][2], matrix[1][2]];
const invertedTranslation = [
@ -81,17 +76,14 @@ function invertTransformMatrix(matrix) {
[0, 0, 1],
];
}
exports.invertTransformMatrix = invertTransformMatrix;
function rotatePoint(homogeneousCoordinate, rotationMatrix) {
export function rotatePoint(homogeneousCoordinate, rotationMatrix) {
return [
dot(homogeneousCoordinate, rotationMatrix[0]),
dot(homogeneousCoordinate, rotationMatrix[1]),
];
}
exports.rotatePoint = rotatePoint;
function xyDistanceBetweenPoints(a, b) {
export function xyDistanceBetweenPoints(a, b) {
return Math.sqrt(((a[0] - b[0]) ** 2) + ((a[1] - b[1]) ** 2));
}
exports.xyDistanceBetweenPoints = xyDistanceBetweenPoints;

View File

@ -1,13 +1,13 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js';
// based on https://github.com/sirius-ai/MobileFaceNet_TF
// model converted from https://github.com/sirius-ai/MobileFaceNet_TF/files/3551493/FaceMobileNet192_train_false.zip
const models = {};
const models = { embedding: null };
async function load(config) {
export async function load(config) {
if (!models.embedding) {
models.embedding = await tf.loadGraphModel(config.face.embedding.modelPath);
log(`load model: ${config.face.embedding.modelPath.match(/\/(.*)\./)[1]}`);
@ -15,7 +15,7 @@ async function load(config) {
return models.embedding;
}
function simmilarity(embedding1, embedding2) {
export function simmilarity(embedding1, embedding2) {
if (embedding1?.length !== embedding2?.length) return 0;
// general minkowski distance
// euclidean distance is limited case where order is 2
@ -24,7 +24,7 @@ function simmilarity(embedding1, embedding2) {
return (Math.trunc(1000 * (1 - distance)) / 1000);
}
async function predict(image, config) {
export async function predict(image, config) {
if (!models.embedding) return null;
return new Promise(async (resolve) => {
const resize = tf.image.resizeBilinear(image, [config.face.embedding.inputSize, config.face.embedding.inputSize], false);
@ -39,7 +39,6 @@ async function predict(image, config) {
const profileData = await tf.profile(() => models.embedding.predict({ img_inputs: resize }));
data = [...profileData.result.dataSync()];
profileData.result.dispose();
// @ts-ignore
profile.run('emotion', profileData);
}
}
@ -48,7 +47,3 @@ async function predict(image, config) {
resolve(data);
});
}
exports.predict = predict;
exports.simmilarity = simmilarity;
exports.load = load;

View File

@ -1,9 +1,9 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js';
const annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];
const models = {};
const models = { emotion: null };
let last = [];
let skipped = Number.MAX_SAFE_INTEGER;
@ -11,7 +11,7 @@ let skipped = Number.MAX_SAFE_INTEGER;
const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale
const scale = 1; // score multiplication factor
async function load(config) {
export async function load(config) {
if (!models.emotion) {
models.emotion = await tf.loadGraphModel(config.face.emotion.modelPath);
log(`load model: ${config.face.emotion.modelPath.match(/\/(.*)\./)[1]}`);
@ -19,7 +19,7 @@ async function load(config) {
return models.emotion;
}
async function predict(image, config) {
export async function predict(image, config) {
if (!models.emotion) return null;
if ((skipped < config.face.emotion.skipFrames) && config.videoOptimized && (last.length > 0)) {
skipped++;
@ -77,6 +77,3 @@ async function predict(image, config) {
resolve(obj);
});
}
exports.predict = predict;
exports.load = load;

View File

@ -1,9 +1,14 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js';
class FaceBoxes {
export class FaceBoxes {
enlarge: number;
model: any;
config: any;
constructor(model, config) {
this.enlarge = 1.1;
this.model = model;
this.config = config;
}
@ -36,15 +41,20 @@ class FaceBoxes {
resizeT.dispose();
for (const i in boxes) {
if (scores[i] && scores[i] > this.config.face.detector.minConfidence) {
const enlarge = 1.05;
const crop = [boxes[i][0] / enlarge, boxes[i][1] / enlarge, boxes[i][2] * enlarge, boxes[i][3] * enlarge];
const crop = [boxes[i][0] / this.enlarge, boxes[i][1] / this.enlarge, boxes[i][2] * this.enlarge, boxes[i][3] * this.enlarge];
const boxRaw = [crop[1], crop[0], (crop[3]) - (crop[1]), (crop[2]) - (crop[0])];
const box = [parseInt(boxRaw[0] * input.shape[2]), parseInt(boxRaw[1] * input.shape[1]), parseInt(boxRaw[2] * input.shape[2]), parseInt(boxRaw[3] * input.shape[1])];
const image = tf.image.cropAndResize(input, [crop], [0], [this.config.face.detector.inputSize, this.config.face.detector.inputSize]);
const box = [
parseInt((boxRaw[0] * input.shape[2]).toString()),
parseInt((boxRaw[1] * input.shape[1]).toString()),
parseInt((boxRaw[2] * input.shape[2]).toString()),
parseInt((boxRaw[3] * input.shape[1]).toString())];
const resized = tf.image.cropAndResize(input, [crop], [0], [this.config.face.detector.inputSize, this.config.face.detector.inputSize]);
const image = resized.div([255]);
resized.dispose();
results.push({
confidence: scores[i],
box,
boxRaw,
boxRaw: this.config.face.mesh.returnRawData ? boxRaw : null,
image,
// mesh,
// meshRaw,
@ -56,7 +66,7 @@ class FaceBoxes {
}
}
async function load(config) {
export async function load(config) {
const model = await tf.loadGraphModel(config.face.detector.modelPath);
log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`);
const faceboxes = new FaceBoxes(model, config);
@ -64,6 +74,3 @@ async function load(config) {
if (config.face.iris.enabled) log(`load model: ${config.face.iris.modelPath.match(/\/(.*)\./)[1]}`);
return faceboxes;
}
exports.load = load;
exports.FaceBoxes = FaceBoxes;

View File

@ -1,8 +1,8 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js';
const models = {};
const models = { gender: null };
let last = { gender: '' };
let skipped = Number.MAX_SAFE_INTEGER;
let alternative = false;
@ -10,7 +10,7 @@ let alternative = false;
// tuning values
const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale
async function load(config) {
export async function load(config) {
if (!models.gender) {
models.gender = await tf.loadGraphModel(config.face.gender.modelPath);
alternative = models.gender.inputs[0].shape[3] === 1;
@ -19,7 +19,7 @@ async function load(config) {
return models.gender;
}
async function predict(image, config) {
export async function predict(image, config) {
if (!models.gender) return null;
if ((skipped < config.face.gender.skipFrames) && config.videoOptimized && last.gender !== '') {
skipped++;
@ -45,7 +45,7 @@ async function predict(image, config) {
tf.dispose(resize);
let genderT;
const obj = {};
const obj = { gender: undefined, confidence: undefined };
if (!config.profile) {
if (config.face.gender.enabled) genderT = await models.gender.predict(enhance);
@ -53,7 +53,6 @@ async function predict(image, config) {
const profileGender = config.face.gender.enabled ? await tf.profile(() => models.gender.predict(enhance)) : {};
genderT = profileGender.result.clone();
profileGender.result.dispose();
// @ts-ignore
profile.run('gender', profileGender);
}
enhance.dispose();
@ -82,6 +81,3 @@ async function predict(image, config) {
resolve(obj);
});
}
exports.predict = predict;
exports.load = load;

View File

@ -1,4 +1,4 @@
exports.body = (res) => {
export const body = (res) => {
if (!res) return [];
const gestures = [];
for (let i = 0; i < res.length; i++) {
@ -18,7 +18,7 @@ exports.body = (res) => {
return gestures;
};
exports.face = (res) => {
export const face = (res) => {
if (!res) return [];
const gestures = [];
for (let i = 0; i < res.length; i++) {
@ -39,7 +39,7 @@ exports.face = (res) => {
return gestures;
};
exports.iris = (res) => {
export const iris = (res) => {
if (!res) return [];
const gestures = [];
for (let i = 0; i < res.length; i++) {
@ -58,7 +58,7 @@ exports.iris = (res) => {
return gestures;
};
exports.hand = (res) => {
export const hand = (res) => {
if (!res) return [];
const gestures = [];
for (let i = 0; i < res.length; i++) {

View File

@ -1,4 +1,4 @@
exports.anchors = [
export const anchors = [
{
w: 1,
h: 1,

View File

@ -1,18 +1,20 @@
import * as tf from '../../dist/tfjs.esm.js';
function getBoxSize(box) {
export function getBoxSize(box) {
return [
Math.abs(box.endPoint[0] - box.startPoint[0]),
Math.abs(box.endPoint[1] - box.startPoint[1]),
];
}
function getBoxCenter(box) {
export function getBoxCenter(box) {
return [
box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,
box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 2,
];
}
function cutBoxFromImageAndResize(box, image, cropSize) {
export function cutBoxFromImageAndResize(box, image, cropSize) {
const h = image.shape[1];
const w = image.shape[2];
const boxes = [[
@ -23,7 +25,8 @@ function cutBoxFromImageAndResize(box, image, cropSize) {
]];
return tf.image.cropAndResize(image, boxes, [0], cropSize);
}
function scaleBoxCoordinates(box, factor) {
export function scaleBoxCoordinates(box, factor) {
const startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];
const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];
const palmLandmarks = box.palmLandmarks.map((coord) => {
@ -32,7 +35,8 @@ function scaleBoxCoordinates(box, factor) {
});
return { startPoint, endPoint, palmLandmarks, confidence: box.confidence };
}
function enlargeBox(box, factor = 1.5) {
export function enlargeBox(box, factor = 1.5) {
const center = getBoxCenter(box);
const size = getBoxSize(box);
const newHalfSize = [factor * size[0] / 2, factor * size[1] / 2];
@ -40,7 +44,8 @@ function enlargeBox(box, factor = 1.5) {
const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];
return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };
}
function squarifyBox(box) {
export function squarifyBox(box) {
const centers = getBoxCenter(box);
const size = getBoxSize(box);
const maxEdge = Math.max(...size);
@ -49,7 +54,8 @@ function squarifyBox(box) {
const endPoint = [centers[0] + halfSize, centers[1] + halfSize];
return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };
}
function shiftBox(box, shiftFactor) {
export function shiftBox(box, shiftFactor) {
const boxSize = [
box.endPoint[0] - box.startPoint[0],
box.endPoint[1] - box.startPoint[1],
@ -59,12 +65,3 @@ function shiftBox(box, shiftFactor) {
const endPoint = [box.endPoint[0] + shiftVector[0], box.endPoint[1] + shiftVector[1]];
return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };
}
export {
cutBoxFromImageAndResize,
enlargeBox,
getBoxCenter,
getBoxSize,
scaleBoxCoordinates,
shiftBox,
squarifyBox,
};

View File

@ -1,7 +1,13 @@
import * as tf from '../../dist/tfjs.esm.js';
import * as box from './box';
class HandDetector {
export class HandDetector {
model: any;
anchors: any;
anchorsTensor: any;
inputSizeTensor: any;
doubleInputSizeTensor: any;
constructor(model, inputSize, anchorsAnnotated) {
this.model = model;
this.anchors = anchorsAnnotated.map((anchor) => [anchor.x_center, anchor.y_center]);
@ -78,4 +84,3 @@ class HandDetector {
return hands;
}
}
exports.HandDetector = HandDetector;

View File

@ -2,7 +2,7 @@ import * as tf from '../../dist/tfjs.esm.js';
import * as box from './box';
import * as util from './util';
// eslint-disable-next-line no-unused-vars
import { log } from '../log.js';
import { log } from '../log';
// const PALM_BOX_SHIFT_VECTOR = [0, -0.4];
const PALM_BOX_ENLARGE_FACTOR = 5; // default 3
@ -12,7 +12,14 @@ const PALM_LANDMARK_IDS = [0, 5, 9, 13, 17, 1, 2];
const PALM_LANDMARKS_INDEX_OF_PALM_BASE = 0;
const PALM_LANDMARKS_INDEX_OF_MIDDLE_FINGER_BASE = 2;
class HandPipeline {
export class HandPipeline {
handDetector: any;
landmarkDetector: any;
inputSize: number;
storedBoxes: any;
skipped: number;
detectedHands: number;
constructor(handDetector, landmarkDetector, inputSize) {
this.handDetector = handDetector;
this.landmarkDetector = landmarkDetector;
@ -154,5 +161,3 @@ class HandPipeline {
return { startPoint, endPoint };
}
}
exports.HandPipeline = HandPipeline;

View File

@ -1,6 +1,6 @@
// https://storage.googleapis.com/tfjs-models/demos/handpose/index.html
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as handdetector from './handdetector';
import * as handpipeline from './handpipeline';
@ -15,7 +15,9 @@ const MESH_ANNOTATIONS = {
palmBase: [0],
};
class HandPose {
export class HandPose {
handPipeline: any;
constructor(handPipeline) {
this.handPipeline = handPipeline;
}
@ -51,20 +53,16 @@ class HandPose {
return hands;
}
}
exports.HandPose = HandPose;
async function load(config) {
export async function load(config) {
const [handDetectorModel, handPoseModel] = await Promise.all([
config.hand.enabled ? tf.loadGraphModel(config.hand.detector.modelPath, { fromTFHub: config.hand.detector.modelPath.includes('tfhub.dev') }) : null,
config.hand.landmarks ? tf.loadGraphModel(config.hand.skeleton.modelPath, { fromTFHub: config.hand.skeleton.modelPath.includes('tfhub.dev') }) : null,
]);
// @ts-ignore
const handDetector = new handdetector.HandDetector(handDetectorModel, config.hand.inputSize, anchors.anchors);
// @ts-ignore
const handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel, config.hand.inputSize);
const handPose = new HandPose(handPipeline);
if (config.hand.enabled) log(`load model: ${config.hand.detector.modelPath.match(/\/(.*)\./)[1]}`);
if (config.hand.landmarks) log(`load model: ${config.hand.skeleton.modelPath.match(/\/(.*)\./)[1]}`);
return handPose;
}
exports.load = load;

View File

@ -1,38 +1,43 @@
function normalizeRadians(angle) {
export function normalizeRadians(angle) {
return angle - 2 * Math.PI * Math.floor((angle + Math.PI) / (2 * Math.PI));
}
function computeRotation(point1, point2) {
export function computeRotation(point1, point2) {
const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);
return normalizeRadians(radians);
}
const buildTranslationMatrix = (x, y) => [[1, 0, x], [0, 1, y], [0, 0, 1]];
function dot(v1, v2) {
export const buildTranslationMatrix = (x, y) => [[1, 0, x], [0, 1, y], [0, 0, 1]];
export function dot(v1, v2) {
let product = 0;
for (let i = 0; i < v1.length; i++) {
product += v1[i] * v2[i];
}
return product;
}
function getColumnFrom2DArr(arr, columnIndex) {
export function getColumnFrom2DArr(arr, columnIndex) {
const column = [];
for (let i = 0; i < arr.length; i++) {
column.push(arr[i][columnIndex]);
}
return column;
}
function multiplyTransformMatrices(mat1, mat2) {
export function multiplyTransformMatrices(mat1, mat2) {
const product = [];
const size = mat1.length;
for (let row = 0; row < size; row++) {
product.push([]);
for (let col = 0; col < size; col++) {
// @ts-ignore
product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col)));
}
}
return product;
}
function buildRotationMatrix(rotation, center) {
export function buildRotationMatrix(rotation, center) {
const cosA = Math.cos(rotation);
const sinA = Math.sin(rotation);
const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]];
@ -41,7 +46,8 @@ function buildRotationMatrix(rotation, center) {
const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);
return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix);
}
function invertTransformMatrix(matrix) {
export function invertTransformMatrix(matrix) {
const rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];
const translationComponent = [matrix[0][2], matrix[1][2]];
const invertedTranslation = [
@ -54,18 +60,10 @@ function invertTransformMatrix(matrix) {
[0, 0, 1],
];
}
function rotatePoint(homogeneousCoordinate, rotationMatrix) {
export function rotatePoint(homogeneousCoordinate, rotationMatrix) {
return [
dot(homogeneousCoordinate, rotationMatrix[0]),
dot(homogeneousCoordinate, rotationMatrix[1]),
];
}
export {
buildRotationMatrix,
computeRotation,
dot,
getColumnFrom2DArr,
invertTransformMatrix,
normalizeRadians,
rotatePoint,
};

View File

@ -1,25 +1,26 @@
import { log } from './log.js';
import { log } from './log';
import * as tf from '../dist/tfjs.esm.js';
import * as backend from './tfjs/backend.js';
import * as facemesh from './blazeface/facemesh.js';
import * as faceboxes from './faceboxes/faceboxes.js';
import * as age from './age/age.js';
import * as gender from './gender/gender.js';
import * as emotion from './emotion/emotion.js';
import * as embedding from './embedding/embedding.js';
import * as posenet from './posenet/posenet.js';
import * as handpose from './handpose/handpose.js';
import * as gesture from './gesture/gesture.js';
import * as image from './image.js';
import * as profile from './profile.js';
import * as config from '../config.js';
import * as sample from './sample.js';
import * as backend from './tfjs/backend';
import * as facemesh from './blazeface/facemesh';
import * as faceboxes from './faceboxes/faceboxes';
import * as age from './age/age';
import * as gender from './gender/gender';
import * as emotion from './emotion/emotion';
import * as embedding from './embedding/embedding';
import * as posenet from './posenet/posenet';
import * as handpose from './handpose/handpose';
import * as gesture from './gesture/gesture';
import * as image from './image';
import * as profile from './profile';
import * as config from '../config';
import * as sample from './sample';
import * as app from '../package.json';
import { NodeFileSystem } from '@tensorflow/tfjs-node/dist/io/file_system';
// helper function: gets elapsed time on both browser and nodejs
const now = () => {
if (typeof performance !== 'undefined') return performance.now();
return parseInt(Number(process.hrtime.bigint()) / 1000 / 1000);
return parseInt((Number(process.hrtime.bigint()) / 1000 / 1000).toString());
};
// helper function: perform deep merge of multiple objects so it allows full inheriance with overrides
@ -42,6 +43,25 @@ function mergeDeep(...objects) {
}
class Human {
tf: any;
version: string;
config: any;
fx: any;
state: string;
numTensors: number;
analyzeMemoryLeaks: boolean;
checkSanity: boolean;
firstRun: boolean;
perf: any;
models: any;
// models
facemesh: any;
age: any;
gender: any;
emotion: any;
body: any;
hand: any;
constructor(userConfig = {}) {
this.tf = tf;
this.version = app.version;
@ -108,7 +128,7 @@ class Human {
}
// preload models, not explicitly required as it's done automatically on first use
async load(userConfig) {
async load(userConfig = null) {
this.state = 'load';
const timeStamp = now();
if (userConfig) this.config = mergeDeep(this.config, userConfig);
@ -160,7 +180,7 @@ class Human {
}
// check if backend needs initialization if it changed
async checkBackend(force) {
async checkBackend(force = false) {
if (this.config.backend && (this.config.backend !== '') && force || (tf.getBackend() !== this.config.backend)) {
const timeStamp = now();
this.state = 'backend';
@ -308,7 +328,7 @@ class Human {
emotion: emotionRes,
embedding: embeddingRes,
iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0,
image: face.image.toInt().squeeze(),
// image: face.image.toInt().squeeze(),
});
// dont need face anymore
@ -487,7 +507,8 @@ class Human {
async warmupNode() {
const atob = (str) => Buffer.from(str, 'base64');
const img = this.config.warmup === 'face' ? atob(sample.face) : atob(sample.body);
const data = tf.node.decodeJpeg(img);
// @ts-ignore
const data = tf.node.decodeJpeg(img); // tf.node is only defined when compiling for nodejs
const expanded = data.expandDims(0);
tf.dispose(data);
// log('Input:', expanded);

View File

@ -1,6 +1,6 @@
import { log } from './log.js';
import { log } from './log';
import * as tf from '../dist/tfjs.esm.js';
import * as fxImage from './imagefx.js';
import * as fxImage from './imagefx';
// internal temp canvases
let inCanvas = null;
@ -9,7 +9,7 @@ let outCanvas = null;
// process input image and return tensor
// input can be tensor, imagedata, htmlimageelement, htmlvideoelement
// input is resized and run through imagefx filter
function process(input, config) {
export function process(input, config) {
let tensor;
if (input instanceof tf.Tensor) {
tensor = tf.clone(input);
@ -39,7 +39,7 @@ function process(input, config) {
outCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(inCanvas.width, inCanvas.height) : document.createElement('canvas');
if (outCanvas.width !== inCanvas.width) outCanvas.width = inCanvas.width;
if (outCanvas.height !== inCanvas.height) outCanvas.height = inCanvas.height;
this.fx = tf.ENV.flags.IS_BROWSER ? new fxImage.Canvas({ canvas: outCanvas }) : null; // && (typeof document !== 'undefined')
this.fx = tf.ENV.flags.IS_BROWSER ? new fxImage.GLImageFilter({ canvas: outCanvas }) : null; // && (typeof document !== 'undefined')
}
if (!this.fx) return inCanvas;
this.fx.reset();
@ -106,5 +106,3 @@ function process(input, config) {
}
return { tensor, canvas: config.filter.return ? outCanvas : null };
}
exports.process = process;

View File

@ -5,7 +5,7 @@ WebGLImageFilter - MIT Licensed
<https://github.com/phoboslab/WebGLImageFilter>
*/
const WebGLProgram = function (gl, vertexSource, fragmentSource) {
const GLProgram = function (gl, vertexSource, fragmentSource) {
const _collect = function (source, prefix, collection) {
const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig');
source.replace(r, (match, name) => {
@ -58,7 +58,7 @@ const WebGLProgram = function (gl, vertexSource, fragmentSource) {
}
};
const WebGLImageFilter = function (params) {
const GLImageFilter = function (params) {
if (!params) params = { };
let _drawCount = 0;
let _sourceTexture = null;
@ -180,7 +180,7 @@ const WebGLImageFilter = function (params) {
return { fbo, texture };
};
const _draw = function (flags) {
const _draw = function (flags = null) {
let source = null;
let target = null;
let flipY = false;
@ -225,7 +225,7 @@ const WebGLImageFilter = function (params) {
}
// Compile shaders
_currentProgram = new WebGLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
const floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize;
@ -606,4 +606,4 @@ const WebGLImageFilter = function (params) {
].join('\n');
};
exports.Canvas = WebGLImageFilter;
exports.GLImageFilter = GLImageFilter;

View File

@ -1,6 +1,6 @@
const console = require('console');
const tf = require('@tensorflow/tfjs-node');
const Human = require('..').default; // this resolves to project root which is '@vladmandic/human'
const Human = require('../dist/human.node').default; // this resolves to project root which is '@vladmandic/human'
const logger = new console.Console({
stdout: process.stdout,

View File

@ -19,7 +19,7 @@ function scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, loca
return localMaximum;
}
function buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores) {
export function buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores) {
const [height, width, numKeypoints] = scores.shape;
const queue = new heapSort.MaxHeap(height * width * numKeypoints, ({ score }) => score);
for (let heatmapY = 0; heatmapY < height; ++heatmapY) {
@ -37,4 +37,3 @@ function buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores) {
}
return queue;
}
exports.buildPartWithScoreQueue = buildPartWithScoreQueue;

View File

@ -7,7 +7,6 @@ const kLocalMaximumRadius = 1;
function withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, { x, y }, keypointId) {
return poses.some(({ keypoints }) => {
const correspondingKeypoint = keypoints[keypointId].position;
// @ts-ignore
return vectors.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius;
});
}
@ -20,9 +19,8 @@ function getInstanceScore(existingPoses, squaredNmsRadius, instanceKeypoints) {
return notOverlappedKeypointScores / instanceKeypoints.length;
}
function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config) {
export function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config) {
const poses = [];
// @ts-ignore
const queue = buildParts.buildPartWithScoreQueue(config.body.scoreThreshold, kLocalMaximumRadius, scoresBuffer);
const squaredNmsRadius = config.body.nmsRadius ^ 2;
// Generate at most maxDetections object instances per image in decreasing root part score order.
@ -30,15 +28,12 @@ function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer
// The top element in the queue is the next root candidate.
const root = queue.dequeue();
// Part-based non-maximum suppression: We reject a root candidate if it is within a disk of `nmsRadius` pixels from the corresponding part of a previously detected instance.
// @ts-ignore
const rootImageCoords = vectors.getImageCoords(root.part, config.body.outputStride, offsetsBuffer);
if (withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, rootImageCoords, root.part.id)) continue;
// Else start a new detection instance at the position of the root.
// @ts-ignore
const keypoints = decodePose.decodePose(root, scoresBuffer, offsetsBuffer, config.body.outputStride, displacementsFwdBuffer, displacementsBwdBuffer);
const score = getInstanceScore(poses, squaredNmsRadius, keypoints);
if (score > config.body.scoreThreshold) poses.push({ keypoints, score });
}
return poses;
}
exports.decodeMultiplePoses = decodeMultiplePoses;

View File

@ -14,9 +14,7 @@ function getDisplacement(edgeId, point, displacements) {
}
function getStridedIndexNearPoint(point, outputStride, height, width) {
return {
// @ts-ignore
y: vectors.clamp(Math.round(point.y / outputStride), 0, height - 1),
// @ts-ignore
x: vectors.clamp(Math.round(point.x / outputStride), 0, width - 1),
};
}
@ -26,14 +24,11 @@ function traverseToTargetKeypoint(edgeId, sourceKeypoint, targetKeypointId, scor
// Nearest neighbor interpolation for the source->target displacements.
const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width);
const displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements);
// @ts-ignore
const displacedPoint = vectors.addVectors(sourceKeypoint.position, displacement);
let targetKeypoint = displacedPoint;
for (let i = 0; i < offsetRefineStep; i++) {
const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
// @ts-ignore
const offsetPoint = vectors.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
// @ts-ignore
targetKeypoint = vectors.addVectors({
x: targetKeypointIndices.x * outputStride,
y: targetKeypointIndices.y * outputStride,
@ -44,13 +39,12 @@ function traverseToTargetKeypoint(edgeId, sourceKeypoint, targetKeypointId, scor
return { position: targetKeypoint, part: keypoints.partNames[targetKeypointId], score };
}
function decodePose(root, scores, offsets, outputStride, displacementsFwd, displacementsBwd) {
export function decodePose(root, scores, offsets, outputStride, displacementsFwd, displacementsBwd) {
const numParts = scores.shape[2];
const numEdges = parentToChildEdges.length;
const instanceKeypoints = new Array(numParts);
// Start a new detection instance at the position of the root.
const { part: rootPart, score: rootScore } = root;
// @ts-ignore
const rootPoint = vectors.getImageCoords(rootPart, outputStride, offsets);
instanceKeypoints[rootPart.id] = {
score: rootScore,
@ -75,20 +69,16 @@ function decodePose(root, scores, offsets, outputStride, displacementsFwd, displ
}
return instanceKeypoints;
}
exports.decodePose = decodePose;
async function decodeSinglePose(heatmapScores, offsets, config) {
export async function decodeSinglePose(heatmapScores, offsets, config) {
let totalScore = 0.0;
// @ts-ignore
const heatmapValues = decoders.argmax2d(heatmapScores);
const allTensorBuffers = await Promise.all([heatmapScores.buffer(), offsets.buffer(), heatmapValues.buffer()]);
const scoresBuffer = allTensorBuffers[0];
const offsetsBuffer = allTensorBuffers[1];
const heatmapValuesBuffer = allTensorBuffers[2];
// @ts-ignore
const offsetPoints = decoders.getOffsetPoints(heatmapValuesBuffer, config.body.outputStride, offsetsBuffer);
const offsetPointsBuffer = await offsetPoints.buffer();
// @ts-ignore
const keypointConfidence = Array.from(decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer));
const instanceKeypoints = keypointConfidence.map((score, i) => {
totalScore += score;
@ -106,4 +96,3 @@ async function decodeSinglePose(heatmapScores, offsets, config) {
offsetPoints.dispose();
return { keypoints: filteredKeypoints, score: totalScore / instanceKeypoints.length };
}
exports.decodeSinglePose = decodeSinglePose;

View File

@ -1,7 +1,7 @@
import * as tf from '../../dist/tfjs.esm.js';
import * as kpt from './keypoints';
function getPointsConfidence(heatmapScores, heatMapCoords) {
export function getPointsConfidence(heatmapScores, heatMapCoords) {
const numKeypoints = heatMapCoords.shape[0];
const result = new Float32Array(numKeypoints);
for (let keypoint = 0; keypoint < numKeypoints; keypoint++) {
@ -11,7 +11,6 @@ function getPointsConfidence(heatmapScores, heatMapCoords) {
}
return result;
}
exports.getPointsConfidence = getPointsConfidence;
function getOffsetPoint(y, x, keypoint, offsetsBuffer) {
return {
@ -20,7 +19,7 @@ function getOffsetPoint(y, x, keypoint, offsetsBuffer) {
};
}
function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) {
export function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) {
const result = [];
for (let keypoint = 0; keypoint < kpt.NUM_KEYPOINTS; keypoint++) {
const heatmapY = heatMapCoordsBuffer.get(keypoint, 0).valueOf();
@ -31,12 +30,10 @@ function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) {
}
return tf.tensor2d(result, [kpt.NUM_KEYPOINTS, 2]);
}
exports.getOffsetVectors = getOffsetVectors;
function getOffsetPoints(heatMapCoordsBuffer, outputStride, offsetsBuffer) {
export function getOffsetPoints(heatMapCoordsBuffer, outputStride, offsetsBuffer) {
return tf.tidy(() => heatMapCoordsBuffer.toTensor().mul(tf.scalar(outputStride, 'int32')).toFloat().add(getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer)));
}
exports.getOffsetPoints = getOffsetPoints;
function mod(a, b) {
return tf.tidy(() => {
@ -45,7 +42,7 @@ function mod(a, b) {
});
}
function argmax2d(inputs) {
export function argmax2d(inputs) {
const [height, width, depth] = inputs.shape;
return tf.tidy(() => {
const reshaped = inputs.reshape([height * width, depth]);
@ -55,4 +52,3 @@ function argmax2d(inputs) {
return tf.concat([yCoords, xCoords], 1);
});
}
exports.argmax2d = argmax2d;

View File

@ -2,7 +2,11 @@
function half(k) {
return Math.floor(k / 2);
}
class MaxHeap {
export class MaxHeap {
priorityQueue: any;
numberOfElements: number;
getElementValue: any;
constructor(maxSize, getElementValue) {
this.priorityQueue = new Array(maxSize);
this.numberOfElements = -1;
@ -69,4 +73,3 @@ class MaxHeap {
this.priorityQueue[j] = t;
}
}
exports.MaxHeap = MaxHeap;

View File

@ -1,12 +1,12 @@
exports.partNames = [
export const partNames = [
'nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder',
'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist',
'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle',
];
exports.NUM_KEYPOINTS = exports.partNames.length;
export const NUM_KEYPOINTS = exports.partNames.length;
exports.partIds = exports.partNames.reduce((result, jointName, i) => {
export const partIds = exports.partNames.reduce((result, jointName, i) => {
result[jointName] = i;
return result;
}, {});
@ -19,9 +19,9 @@ const connectedPartNames = [
['rightHip', 'rightKnee'], ['rightKnee', 'rightAnkle'],
['leftShoulder', 'rightShoulder'], ['leftHip', 'rightHip'],
];
exports.connectedPartIndices = connectedPartNames.map(([jointNameA, jointNameB]) => ([exports.partIds[jointNameA], exports.partIds[jointNameB]]));
export const connectedPartIndices = connectedPartNames.map(([jointNameA, jointNameB]) => ([partIds[jointNameA], partIds[jointNameB]]));
exports.poseChain = [
export const poseChain = [
['nose', 'leftEye'], ['leftEye', 'leftEar'], ['nose', 'rightEye'],
['rightEye', 'rightEar'], ['nose', 'leftShoulder'],
['leftShoulder', 'leftElbow'], ['leftElbow', 'leftWrist'],
@ -32,7 +32,7 @@ exports.poseChain = [
['rightKnee', 'rightAnkle'],
];
exports.partChannels = [
export const partChannels = [
'left_face',
'right_face',
'right_upper_leg_front',

View File

@ -12,7 +12,8 @@ function nameOutputResultsResNet(results) {
return { offsets, heatmap, displacementFwd, displacementBwd };
}
class BaseModel {
export class BaseModel {
model: any;
constructor(model) {
this.model = model;
}
@ -37,4 +38,3 @@ class BaseModel {
this.model.dispose();
}
}
exports.BaseModel = BaseModel;

View File

@ -1,4 +1,5 @@
class ModelWeights {
export class ModelWeights {
variables: any;
constructor(variables) {
this.variables = variables;
}
@ -23,4 +24,3 @@ class ModelWeights {
for (let i = 0; i < this.variables.length; i++) this.variables[i].dispose();
}
}
exports.ModelWeights = ModelWeights;

View File

@ -1,23 +0,0 @@
import * as modelPoseNet from './modelPoseNet';
import * as keypoints from './keypoints';
import * as util from './util';
// @ts-ignore
exports.load = modelPoseNet.load;
// @ts-ignore
exports.PoseNet = modelPoseNet.PoseNet;
exports.partChannels = keypoints.partChannels;
exports.partIds = keypoints.partIds;
exports.partNames = keypoints.partNames;
exports.poseChain = keypoints.poseChain;
// @ts-ignore
exports.getAdjacentKeyPoints = util.getAdjacentKeyPoints;
// @ts-ignore
exports.getBoundingBox = util.getBoundingBox;
// @ts-ignore
exports.getBoundingBoxPoints = util.getBoundingBoxPoints;
// @ts-ignore
exports.scaleAndFlipPoses = util.scaleAndFlipPoses;
// @ts-ignore
exports.scalePose = util.scalePose;

View File

@ -1,4 +1,4 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
import * as modelBase from './modelBase';
import * as decodeMultiple from './decodeMultiple';
@ -9,15 +9,12 @@ async function estimateMultiple(input, res, config) {
return new Promise(async (resolve) => {
const height = input.shape[1];
const width = input.shape[2];
// @ts-ignore
const allTensorBuffers = await util.toTensorBuffers3D([res.heatmapScores, res.offsets, res.displacementFwd, res.displacementBwd]);
const scoresBuffer = allTensorBuffers[0];
const offsetsBuffer = allTensorBuffers[1];
const displacementsFwdBuffer = allTensorBuffers[2];
const displacementsBwdBuffer = allTensorBuffers[3];
// @ts-ignore
const poses = await decodeMultiple.decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config);
// @ts-ignore
const scaled = util.scaleAndFlipPoses(poses, [height, width], [config.body.inputSize, config.body.inputSize]);
resolve(scaled);
});
@ -27,22 +24,20 @@ async function estimateSingle(input, res, config) {
return new Promise(async (resolve) => {
const height = input.shape[1];
const width = input.shape[2];
// @ts-ignore
const pose = await decodePose.decodeSinglePose(res.heatmapScores, res.offsets, config);
const poses = [pose];
// @ts-ignore
const scaled = util.scaleAndFlipPoses(poses, [height, width], [config.body.inputSize, config.body.inputSize]);
resolve(scaled);
});
}
class PoseNet {
export class PoseNet {
baseModel: any;
constructor(model) {
this.baseModel = model;
}
async estimatePoses(input, config) {
// @ts-ignore
const resized = util.resizeTo(input, [config.body.inputSize, config.body.inputSize]);
const res = this.baseModel.predict(resized, config);
@ -61,13 +56,10 @@ class PoseNet {
this.baseModel.dispose();
}
}
exports.PoseNet = PoseNet;
async function load(config) {
export async function load(config) {
const model = await tf.loadGraphModel(config.body.modelPath);
// @ts-ignore
const mobilenet = new modelBase.BaseModel(model);
log(`load model: ${config.body.modelPath.match(/\/(.*)\./)[1]}`);
return new PoseNet(mobilenet);
}
exports.load = load;

View File

@ -1,10 +1,10 @@
import * as kpt from './keypoints';
function eitherPointDoesntMeetConfidence(a, b, minConfidence) {
export function eitherPointDoesntMeetConfidence(a, b, minConfidence) {
return (a < minConfidence || b < minConfidence);
}
function getAdjacentKeyPoints(keypoints, minConfidence) {
export function getAdjacentKeyPoints(keypoints, minConfidence) {
return kpt.connectedPartIndices.reduce((result, [leftJoint, rightJoint]) => {
if (eitherPointDoesntMeetConfidence(keypoints[leftJoint].score, keypoints[rightJoint].score, minConfidence)) {
return result;
@ -13,10 +13,9 @@ function getAdjacentKeyPoints(keypoints, minConfidence) {
return result;
}, []);
}
exports.getAdjacentKeyPoints = getAdjacentKeyPoints;
const { NEGATIVE_INFINITY, POSITIVE_INFINITY } = Number;
function getBoundingBox(keypoints) {
export function getBoundingBox(keypoints) {
return keypoints.reduce(({ maxX, maxY, minX, minY }, { position: { x, y } }) => ({
maxX: Math.max(maxX, x),
maxY: Math.max(maxY, y),
@ -29,20 +28,17 @@ function getBoundingBox(keypoints) {
minY: POSITIVE_INFINITY,
});
}
exports.getBoundingBox = getBoundingBox;
function getBoundingBoxPoints(keypoints) {
export function getBoundingBoxPoints(keypoints) {
const { minX, minY, maxX, maxY } = getBoundingBox(keypoints);
return [{ x: minX, y: minY }, { x: maxX, y: minY }, { x: maxX, y: maxY }, { x: minX, y: maxY }];
}
exports.getBoundingBoxPoints = getBoundingBoxPoints;
async function toTensorBuffers3D(tensors) {
export async function toTensorBuffers3D(tensors) {
return Promise.all(tensors.map((tensor) => tensor.buffer()));
}
exports.toTensorBuffers3D = toTensorBuffers3D;
function scalePose(pose, scaleY, scaleX) {
export function scalePose(pose, scaleY, scaleX) {
return {
score: pose.score,
keypoints: pose.keypoints.map(({ score, part, position }) => ({
@ -52,18 +48,15 @@ function scalePose(pose, scaleY, scaleX) {
})),
};
}
exports.scalePose = scalePose;
function resizeTo(image, [targetH, targetW]) {
export function resizeTo(image, [targetH, targetW]) {
const input = image.squeeze(0);
const resized = input.resizeBilinear([targetH, targetW]);
input.dispose();
return resized;
}
exports.resizeTo = resizeTo;
function scaleAndFlipPoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth]) {
export function scaleAndFlipPoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth]) {
const scaledPoses = poses.map((pose) => scalePose(pose, height / inputResolutionHeight, width / inputResolutionWidth));
return scaledPoses;
}
exports.scaleAndFlipPoses = scaleAndFlipPoses;

View File

@ -1,14 +1,13 @@
import * as kpt from './keypoints';
function getOffsetPoint(y, x, keypoint, offsets) {
export function getOffsetPoint(y, x, keypoint, offsets) {
return {
y: offsets.get(y, x, keypoint),
x: offsets.get(y, x, keypoint + kpt.NUM_KEYPOINTS),
};
}
exports.getOffsetPoint = getOffsetPoint;
function getImageCoords(part, outputStride, offsets) {
export function getImageCoords(part, outputStride, offsets) {
const { heatmapY, heatmapX, id: keypoint } = part;
const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);
return {
@ -16,37 +15,31 @@ function getImageCoords(part, outputStride, offsets) {
y: part.heatmapY * outputStride + y,
};
}
exports.getImageCoords = getImageCoords;
function fillArray(element, size) {
export function fillArray(element, size) {
const result = new Array(size);
for (let i = 0; i < size; i++) {
result[i] = element;
}
return result;
}
exports.fillArray = fillArray;
function clamp(a, min, max) {
export function clamp(a, min, max) {
if (a < min) return min;
if (a > max) return max;
return a;
}
exports.clamp = clamp;
function squaredDistance(y1, x1, y2, x2) {
export function squaredDistance(y1, x1, y2, x2) {
const dy = y2 - y1;
const dx = x2 - x1;
return dy * dy + dx * dx;
}
exports.squaredDistance = squaredDistance;
function addVectors(a, b) {
export function addVectors(a, b) {
return { x: a.x + b.x, y: a.y + b.y };
}
exports.addVectors = addVectors;
function clampVector(a, min, max) {
export function clampVector(a, min, max) {
return { y: clamp(a.y, min, max), x: clamp(a.x, min, max) };
}
exports.clampVector = clampVector;

View File

@ -1,26 +1,24 @@
import { log } from './log.js';
import { log } from './log';
const profileData = {};
export const data = {};
function profile(name, data) {
if (!data || !data.kernels) return;
export function run(name, raw) {
if (!raw || !raw.kernels) return;
const maxResults = 5;
const time = data.kernels
const time = raw.kernels
.filter((a) => a.kernelTimeMs > 0)
.reduce((a, b) => a += b.kernelTimeMs, 0);
const slowest = data.kernels
const slowest = raw.kernels
.map((a, i) => { a.id = i; return a; })
.filter((a) => a.kernelTimeMs > 0)
.sort((a, b) => b.kernelTimeMs - a.kernelTimeMs);
const largest = data.kernels
const largest = raw.kernels
.map((a, i) => { a.id = i; return a; })
.filter((a) => a.totalBytesSnapshot > 0)
.sort((a, b) => b.totalBytesSnapshot - a.totalBytesSnapshot);
if (slowest.length > maxResults) slowest.length = maxResults;
if (largest.length > maxResults) largest.length = maxResults;
const res = { newBytes: data.newBytes, newTensors: data.newTensors, peakBytes: data.peakBytes, numKernelOps: data.kernels.length, timeKernelOps: time, slowestKernelOps: slowest, largestKernelOps: largest };
profileData[name] = res;
const res = { newBytes: raw.newBytes, newTensors: raw.newTensors, peakBytes: raw.peakBytes, numKernelOps: raw.kernels.length, timeKernelOps: time, slowestKernelOps: slowest, largestKernelOps: largest };
data[name] = res;
log('Human profiler', name, res);
}
exports.run = profile;

View File

@ -1,4 +1,4 @@
import { log } from '../log.js';
import { log } from '../log';
import * as tf from '../../dist/tfjs.esm.js';
export const config = {