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> <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!* *Suggestions are welcome!*

View File

@ -56,14 +56,19 @@ async function detect(input) {
} }
async function test() { async function test() {
// test with embedded face image
log.state('Processing embedded warmup image: face'); log.state('Processing embedded warmup image: face');
myConfig.warmup = 'face'; myConfig.warmup = 'face';
const resultFace = await human.warmup(myConfig); 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'); log.state('Processing embedded warmup image: full');
myConfig.warmup = 'full'; myConfig.warmup = 'full';
const resultFull = await human.warmup(myConfig); 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() { 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": { "inputs": {
"dist/human.esm.js": { "dist/human.esm.js": {
"bytes": 1349003, "bytes": 1343005,
"imports": [] "imports": []
}, },
"demo/draw.js": { "demo/draw.js": {
@ -43,14 +43,14 @@
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": {}, "inputs": {},
"bytes": 2028101 "bytes": 2018414
}, },
"dist/demo-browser-index.js": { "dist/demo-browser-index.js": {
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": { "inputs": {
"dist/human.esm.js": { "dist/human.esm.js": {
"bytesInOutput": 1340450 "bytesInOutput": 1335513
}, },
"demo/draw.js": { "demo/draw.js": {
"bytesInOutput": 6204 "bytesInOutput": 6204
@ -65,7 +65,7 @@
"bytesInOutput": 16815 "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": { "inputs": {
"src/log.js": { "src/log.ts": {
"bytes": 401, "bytes": 401,
"imports": [] "imports": []
}, },
"dist/tfjs.esm.js": { "dist/tfjs.esm.js": {
"bytes": 1071833, "bytes": 1071825,
"imports": [] "imports": []
}, },
"src/tfjs/backend.js": { "src/tfjs/backend.ts": {
"bytes": 2171, "bytes": 2168,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -21,11 +21,11 @@
} }
] ]
}, },
"src/blazeface/blazeface.js": { "src/blazeface/blazeface.ts": {
"bytes": 7024, "bytes": 6024,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -34,8 +34,8 @@
} }
] ]
}, },
"src/blazeface/box.js": { "src/blazeface/box.ts": {
"bytes": 1935, "bytes": 1727,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -43,44 +43,40 @@
} }
] ]
}, },
"src/blazeface/util.js": { "src/blazeface/util.ts": {
"bytes": 3087, "bytes": 2777,
"imports": [] "imports": []
}, },
"src/blazeface/coords.js": { "src/blazeface/coords.ts": {
"bytes": 37915, "bytes": 37783,
"imports": [] "imports": []
}, },
"src/blazeface/facepipeline.js": { "src/blazeface/facepipeline.ts": {
"bytes": 14275, "bytes": 14254,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/box.js", "path": "src/blazeface/box.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/util.js", "path": "src/blazeface/util.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/coords.js", "path": "src/blazeface/coords.ts",
"kind": "import-statement"
},
{
"path": "src/log.js",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/blazeface/facemesh.js": { "src/blazeface/facemesh.ts": {
"bytes": 2973, "bytes": 2935,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -88,33 +84,33 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/blazeface.js", "path": "src/blazeface/blazeface.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/facepipeline.js", "path": "src/blazeface/facepipeline.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/coords.js", "path": "src/blazeface/coords.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/profile.js": { "src/profile.ts": {
"bytes": 1045, "bytes": 1004,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/faceboxes/faceboxes.js": { "src/faceboxes/faceboxes.ts": {
"bytes": 2612, "bytes": 2852,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -122,16 +118,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/age/age.js": { "src/age/age.ts": {
"bytes": 2037, "bytes": 2064,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -139,16 +135,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/gender/gender.js": { "src/gender/gender.ts": {
"bytes": 2906, "bytes": 2904,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -156,16 +152,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/emotion/emotion.js": { "src/emotion/emotion.ts": {
"bytes": 3056, "bytes": 3033,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -173,16 +169,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/embedding/embedding.js": { "src/embedding/embedding.ts": {
"bytes": 2063, "bytes": 1992,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -190,13 +186,13 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/modelBase.js": { "src/posenet/modelBase.ts": {
"bytes": 1343, "bytes": 1333,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -204,93 +200,93 @@
} }
] ]
}, },
"src/posenet/heapSort.js": { "src/posenet/heapSort.ts": {
"bytes": 1590, "bytes": 1645,
"imports": [] "imports": []
}, },
"src/posenet/buildParts.js": { "src/posenet/buildParts.ts": {
"bytes": 1775, "bytes": 1723,
"imports": [ "imports": [
{ {
"path": "src/posenet/heapSort.js", "path": "src/posenet/heapSort.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/keypoints.js": { "src/posenet/keypoints.ts": {
"bytes": 2011, "bytes": 2025,
"imports": [] "imports": []
}, },
"src/posenet/vectors.js": { "src/posenet/vectors.ts": {
"bytes": 1273, "bytes": 1075,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/decoders.js": { "src/posenet/decoders.ts": {
"bytes": 2083, "bytes": 1943,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/decodePose.js": { "src/posenet/decodePose.ts": {
"bytes": 5368, "bytes": 5152,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/vectors.js", "path": "src/posenet/vectors.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decoders.js", "path": "src/posenet/decoders.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/decodeMultiple.js": { "src/posenet/decodeMultiple.ts": {
"bytes": 2373, "bytes": 2259,
"imports": [ "imports": [
{ {
"path": "src/posenet/buildParts.js", "path": "src/posenet/buildParts.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decodePose.js", "path": "src/posenet/decodePose.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/vectors.js", "path": "src/posenet/vectors.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/util.js": { "src/posenet/util.ts": {
"bytes": 2262, "bytes": 2017,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/modelPoseNet.js": { "src/posenet/posenet.ts": {
"bytes": 2519, "bytes": 2376,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -298,42 +294,25 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/modelBase.js", "path": "src/posenet/modelBase.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decodeMultiple.js", "path": "src/posenet/decodeMultiple.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decodePose.js", "path": "src/posenet/decodePose.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/util.js", "path": "src/posenet/util.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/posenet.js": { "src/handpose/box.ts": {
"bytes": 712, "bytes": 2443,
"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": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -341,53 +320,49 @@
} }
] ]
}, },
"src/handpose/handdetector.js": { "src/handpose/handdetector.ts": {
"bytes": 3548, "bytes": 3627,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/box.js", "path": "src/handpose/box.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/handpose/util.js": { "src/handpose/util.ts": {
"bytes": 2346, "bytes": 2254,
"imports": [] "imports": []
}, },
"src/handpose/handpipeline.js": { "src/handpose/handpipeline.ts": {
"bytes": 7246, "bytes": 7344,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/box.js", "path": "src/handpose/box.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/util.js", "path": "src/handpose/util.ts",
"kind": "import-statement"
},
{
"path": "src/log.js",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/handpose/anchors.js": { "src/handpose/anchors.ts": {
"bytes": 224151, "bytes": 224156,
"imports": [] "imports": []
}, },
"src/handpose/handpose.js": { "src/handpose/handpose.ts": {
"bytes": 2578, "bytes": 2529,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -395,32 +370,32 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/handdetector.js", "path": "src/handpose/handdetector.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/handpipeline.js", "path": "src/handpose/handpipeline.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/anchors.js", "path": "src/handpose/anchors.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/gesture/gesture.js": { "src/gesture/gesture.ts": {
"bytes": 4245, "bytes": 4265,
"imports": [] "imports": []
}, },
"src/imagefx.js": { "src/imagefx.js": {
"bytes": 19445, "bytes": 19447,
"imports": [] "imports": []
}, },
"src/image.js": { "src/image.ts": {
"bytes": 5871, "bytes": 5851,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -437,19 +412,19 @@
"bytes": 9786, "bytes": 9786,
"imports": [] "imports": []
}, },
"src/sample.js": { "src/sample.ts": {
"bytes": 55382, "bytes": 55382,
"imports": [] "imports": []
}, },
"package.json": { "package.json": {
"bytes": 2321, "bytes": 2344,
"imports": [] "imports": []
}, },
"src/human.js": { "src/human.ts": {
"bytes": 18962, "bytes": 19393,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -457,51 +432,51 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/tfjs/backend.js", "path": "src/tfjs/backend.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/facemesh.js", "path": "src/blazeface/facemesh.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/faceboxes/faceboxes.js", "path": "src/faceboxes/faceboxes.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/age/age.js", "path": "src/age/age.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/gender/gender.js", "path": "src/gender/gender.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/emotion/emotion.js", "path": "src/emotion/emotion.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/embedding/embedding.js", "path": "src/embedding/embedding.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/posenet.js", "path": "src/posenet/posenet.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/handpose.js", "path": "src/handpose/handpose.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/gesture/gesture.js", "path": "src/gesture/gesture.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/image.js", "path": "src/image.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -509,7 +484,7 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/sample.js", "path": "src/sample.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -524,7 +499,7 @@
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": {}, "inputs": {},
"bytes": 1932071 "bytes": 1923046
}, },
"dist/human.esm.js": { "dist/human.esm.js": {
"imports": [], "imports": [],
@ -532,125 +507,122 @@
"default" "default"
], ],
"inputs": { "inputs": {
"src/blazeface/blazeface.js": { "src/blazeface/facemesh.ts": {
"bytesInOutput": 2915 "bytesInOutput": 1445
}, },
"src/blazeface/box.js": { "src/posenet/keypoints.ts": {
"bytesInOutput": 987 "bytesInOutput": 1690
},
"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/imagefx.js": { "src/imagefx.js": {
"bytesInOutput": 11004 "bytesInOutput": 11016
}, },
"src/image.js": { "src/log.ts": {
"bytesInOutput": 2480
},
"src/log.js": {
"bytesInOutput": 252 "bytesInOutput": 252
}, },
"dist/tfjs.esm.js": { "dist/tfjs.esm.js": {
"bytesInOutput": 1062888 "bytesInOutput": 1062782
}, },
"src/tfjs/backend.js": { "src/tfjs/backend.ts": {
"bytesInOutput": 1205 "bytesInOutput": 1205
}, },
"src/human.js": { "src/blazeface/blazeface.ts": {
"bytesInOutput": 10537 "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 "bytesInOutput": 938
}, },
"src/handpose/util.js": { "src/handpose/handdetector.ts": {
"bytesInOutput": 1668
},
"src/handpose/util.ts": {
"bytesInOutput": 816 "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": { "config.js": {
"bytesInOutput": 1426 "bytesInOutput": 1426
}, },
"src/sample.js": { "src/sample.ts": {
"bytesInOutput": 55295 "bytesInOutput": 55295
}, },
"package.json": { "package.json": {
"bytesInOutput": 16 "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": { "inputs": {
"src/log.js": { "src/log.ts": {
"bytes": 401, "bytes": 401,
"imports": [] "imports": []
}, },
"dist/tfjs.esm.js": { "dist/tfjs.esm.js": {
"bytes": 681, "bytes": 690,
"imports": [] "imports": []
}, },
"src/tfjs/backend.js": { "src/tfjs/backend.ts": {
"bytes": 2171, "bytes": 2168,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -22,10 +22,10 @@
] ]
}, },
"src/blazeface/blazeface.js": { "src/blazeface/blazeface.js": {
"bytes": 7024, "bytes": 6983,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -52,7 +52,7 @@
"imports": [] "imports": []
}, },
"src/blazeface/facepipeline.js": { "src/blazeface/facepipeline.js": {
"bytes": 14275, "bytes": 14028,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -71,16 +71,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/blazeface/facemesh.js": { "src/blazeface/facemesh.js": {
"bytes": 2973, "bytes": 2898,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -101,20 +101,20 @@
} }
] ]
}, },
"src/profile.js": { "src/profile.ts": {
"bytes": 1045, "bytes": 1004,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/faceboxes/faceboxes.js": { "src/faceboxes/faceboxes.ts": {
"bytes": 2612, "bytes": 2852,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -122,16 +122,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/age/age.js": { "src/age/age.ts": {
"bytes": 2037, "bytes": 2064,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -139,16 +139,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/gender/gender.js": { "src/gender/gender.ts": {
"bytes": 2906, "bytes": 2904,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -156,16 +156,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/emotion/emotion.js": { "src/emotion/emotion.ts": {
"bytes": 3056, "bytes": 3033,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -173,16 +173,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/embedding/embedding.js": { "src/embedding/embedding.ts": {
"bytes": 2063, "bytes": 1992,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -190,7 +190,7 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
@ -244,7 +244,7 @@
] ]
}, },
"src/posenet/decodePose.js": { "src/posenet/decodePose.js": {
"bytes": 5368, "bytes": 5216,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.js",
@ -261,7 +261,7 @@
] ]
}, },
"src/posenet/decodeMultiple.js": { "src/posenet/decodeMultiple.js": {
"bytes": 2373, "bytes": 2303,
"imports": [ "imports": [
{ {
"path": "src/posenet/buildParts.js", "path": "src/posenet/buildParts.js",
@ -286,11 +286,11 @@
} }
] ]
}, },
"src/posenet/modelPoseNet.js": { "src/posenet/posenet.js": {
"bytes": 2519, "bytes": 2406,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "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": { "src/handpose/box.js": {
"bytes": 2522, "bytes": 2522,
"imports": [ "imports": [
@ -355,11 +338,11 @@
] ]
}, },
"src/handpose/util.js": { "src/handpose/util.js": {
"bytes": 2346, "bytes": 2326,
"imports": [] "imports": []
}, },
"src/handpose/handpipeline.js": { "src/handpose/handpipeline.js": {
"bytes": 7246, "bytes": 7243,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -374,7 +357,7 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
@ -384,10 +367,10 @@
"imports": [] "imports": []
}, },
"src/handpose/handpose.js": { "src/handpose/handpose.js": {
"bytes": 2578, "bytes": 2536,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -408,19 +391,19 @@
} }
] ]
}, },
"src/gesture/gesture.js": { "src/gesture/gesture.ts": {
"bytes": 4245, "bytes": 4265,
"imports": [] "imports": []
}, },
"src/imagefx.js": { "src/imagefx.js": {
"bytes": 19445, "bytes": 19311,
"imports": [] "imports": []
}, },
"src/image.js": { "src/image.ts": {
"bytes": 5871, "bytes": 5851,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -437,7 +420,7 @@
"bytes": 9786, "bytes": 9786,
"imports": [] "imports": []
}, },
"src/sample.js": { "src/sample.ts": {
"bytes": 55382, "bytes": 55382,
"imports": [] "imports": []
}, },
@ -445,11 +428,11 @@
"bytes": 2321, "bytes": 2321,
"imports": [] "imports": []
}, },
"src/human.js": { "src/human.ts": {
"bytes": 18962, "bytes": 19233,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -457,7 +440,7 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/tfjs/backend.js", "path": "src/tfjs/backend.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -465,23 +448,23 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/faceboxes/faceboxes.js", "path": "src/faceboxes/faceboxes.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/age/age.js", "path": "src/age/age.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/gender/gender.js", "path": "src/gender/gender.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/emotion/emotion.js", "path": "src/emotion/emotion.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/embedding/embedding.js", "path": "src/embedding/embedding.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -493,15 +476,15 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/gesture/gesture.js", "path": "src/gesture/gesture.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/image.js", "path": "src/image.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -509,7 +492,7 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/sample.js", "path": "src/sample.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -524,14 +507,14 @@
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": {}, "inputs": {},
"bytes": 714830 "bytes": 712944
}, },
"dist/human.node-gpu.js": { "dist/human.node-gpu.js": {
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": { "inputs": {
"dist/tfjs.esm.js": { "dist/tfjs.esm.js": {
"bytesInOutput": 545 "bytesInOutput": 550
}, },
"src/blazeface/blazeface.js": { "src/blazeface/blazeface.js": {
"bytesInOutput": 3077 "bytesInOutput": 3077
@ -549,25 +532,7 @@
"bytesInOutput": 5593 "bytesInOutput": 5593
}, },
"src/blazeface/facemesh.js": { "src/blazeface/facemesh.js": {
"bytesInOutput": 1556 "bytesInOutput": 1574
},
"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
}, },
"src/posenet/modelBase.js": { "src/posenet/modelBase.js": {
"bytesInOutput": 688 "bytesInOutput": 688
@ -596,11 +561,8 @@
"src/posenet/util.js": { "src/posenet/util.js": {
"bytesInOutput": 1051 "bytesInOutput": 1051
}, },
"src/posenet/modelPoseNet.js": {
"bytesInOutput": 1180
},
"src/posenet/posenet.js": { "src/posenet/posenet.js": {
"bytesInOutput": 385 "bytesInOutput": 1223
}, },
"src/handpose/handdetector.js": { "src/handpose/handdetector.js": {
"bytesInOutput": 1844 "bytesInOutput": 1844
@ -612,43 +574,61 @@
"bytesInOutput": 127005 "bytesInOutput": 127005
}, },
"src/handpose/handpose.js": { "src/handpose/handpose.js": {
"bytesInOutput": 1363 "bytesInOutput": 1397
}, },
"src/gesture/gesture.js": { "src/human.ts": {
"bytesInOutput": 2423 "bytesInOutput": 10355
}, },
"src/imagefx.js": { "src/log.ts": {
"bytesInOutput": 10999
},
"src/image.js": {
"bytesInOutput": 2478
},
"src/human.js": {
"bytesInOutput": 10681
},
"src/log.js": {
"bytesInOutput": 251 "bytesInOutput": 251
}, },
"src/tfjs/backend.js": { "src/tfjs/backend.ts": {
"bytesInOutput": 1304 "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": { "src/handpose/box.js": {
"bytesInOutput": 958 "bytesInOutput": 958
}, },
"src/handpose/util.js": { "src/handpose/util.js": {
"bytesInOutput": 812 "bytesInOutput": 812
}, },
"src/gesture/gesture.ts": {
"bytesInOutput": 2391
},
"src/image.ts": {
"bytesInOutput": 2434
},
"src/imagefx.js": {
"bytesInOutput": 11045
},
"config.js": { "config.js": {
"bytesInOutput": 1426 "bytesInOutput": 1426
}, },
"src/sample.js": { "src/sample.ts": {
"bytesInOutput": 55295 "bytesInOutput": 55295
}, },
"package.json": { "package.json": {
"bytesInOutput": 16 "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": { "inputs": {
"src/log.js": { "src/log.ts": {
"bytes": 401, "bytes": 401,
"imports": [] "imports": []
}, },
"dist/tfjs.esm.js": { "dist/tfjs.esm.js": {
"bytes": 1071833, "bytes": 1071825,
"imports": [] "imports": []
}, },
"src/tfjs/backend.js": { "src/tfjs/backend.ts": {
"bytes": 2171, "bytes": 2168,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -21,11 +21,11 @@
} }
] ]
}, },
"src/blazeface/blazeface.js": { "src/blazeface/blazeface.ts": {
"bytes": 7024, "bytes": 6024,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -34,8 +34,8 @@
} }
] ]
}, },
"src/blazeface/box.js": { "src/blazeface/box.ts": {
"bytes": 1935, "bytes": 1727,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -43,44 +43,40 @@
} }
] ]
}, },
"src/blazeface/util.js": { "src/blazeface/util.ts": {
"bytes": 3087, "bytes": 2777,
"imports": [] "imports": []
}, },
"src/blazeface/coords.js": { "src/blazeface/coords.ts": {
"bytes": 37915, "bytes": 37783,
"imports": [] "imports": []
}, },
"src/blazeface/facepipeline.js": { "src/blazeface/facepipeline.ts": {
"bytes": 14275, "bytes": 14254,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/box.js", "path": "src/blazeface/box.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/util.js", "path": "src/blazeface/util.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/coords.js", "path": "src/blazeface/coords.ts",
"kind": "import-statement"
},
{
"path": "src/log.js",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/blazeface/facemesh.js": { "src/blazeface/facemesh.ts": {
"bytes": 2973, "bytes": 2935,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -88,33 +84,33 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/blazeface.js", "path": "src/blazeface/blazeface.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/facepipeline.js", "path": "src/blazeface/facepipeline.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/coords.js", "path": "src/blazeface/coords.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/profile.js": { "src/profile.ts": {
"bytes": 1045, "bytes": 1004,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/faceboxes/faceboxes.js": { "src/faceboxes/faceboxes.ts": {
"bytes": 2612, "bytes": 2852,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -122,16 +118,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/age/age.js": { "src/age/age.ts": {
"bytes": 2037, "bytes": 2064,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -139,16 +135,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/gender/gender.js": { "src/gender/gender.ts": {
"bytes": 2906, "bytes": 2904,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -156,16 +152,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/emotion/emotion.js": { "src/emotion/emotion.ts": {
"bytes": 3056, "bytes": 3033,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -173,16 +169,16 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/embedding/embedding.js": { "src/embedding/embedding.ts": {
"bytes": 2063, "bytes": 1992,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -190,13 +186,13 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/modelBase.js": { "src/posenet/modelBase.ts": {
"bytes": 1343, "bytes": 1333,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -204,93 +200,93 @@
} }
] ]
}, },
"src/posenet/heapSort.js": { "src/posenet/heapSort.ts": {
"bytes": 1590, "bytes": 1645,
"imports": [] "imports": []
}, },
"src/posenet/buildParts.js": { "src/posenet/buildParts.ts": {
"bytes": 1775, "bytes": 1723,
"imports": [ "imports": [
{ {
"path": "src/posenet/heapSort.js", "path": "src/posenet/heapSort.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/keypoints.js": { "src/posenet/keypoints.ts": {
"bytes": 2011, "bytes": 2025,
"imports": [] "imports": []
}, },
"src/posenet/vectors.js": { "src/posenet/vectors.ts": {
"bytes": 1273, "bytes": 1075,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/decoders.js": { "src/posenet/decoders.ts": {
"bytes": 2083, "bytes": 1943,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/decodePose.js": { "src/posenet/decodePose.ts": {
"bytes": 5368, "bytes": 5152,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/vectors.js", "path": "src/posenet/vectors.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decoders.js", "path": "src/posenet/decoders.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/decodeMultiple.js": { "src/posenet/decodeMultiple.ts": {
"bytes": 2373, "bytes": 2259,
"imports": [ "imports": [
{ {
"path": "src/posenet/buildParts.js", "path": "src/posenet/buildParts.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decodePose.js", "path": "src/posenet/decodePose.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/vectors.js", "path": "src/posenet/vectors.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/util.js": { "src/posenet/util.ts": {
"bytes": 2262, "bytes": 2017,
"imports": [ "imports": [
{ {
"path": "src/posenet/keypoints.js", "path": "src/posenet/keypoints.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/modelPoseNet.js": { "src/posenet/posenet.ts": {
"bytes": 2519, "bytes": 2376,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -298,42 +294,25 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/modelBase.js", "path": "src/posenet/modelBase.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decodeMultiple.js", "path": "src/posenet/decodeMultiple.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/decodePose.js", "path": "src/posenet/decodePose.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/util.js", "path": "src/posenet/util.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/posenet/posenet.js": { "src/handpose/box.ts": {
"bytes": 712, "bytes": 2443,
"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": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
@ -341,53 +320,49 @@
} }
] ]
}, },
"src/handpose/handdetector.js": { "src/handpose/handdetector.ts": {
"bytes": 3548, "bytes": 3627,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/box.js", "path": "src/handpose/box.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/handpose/util.js": { "src/handpose/util.ts": {
"bytes": 2346, "bytes": 2254,
"imports": [] "imports": []
}, },
"src/handpose/handpipeline.js": { "src/handpose/handpipeline.ts": {
"bytes": 7246, "bytes": 7344,
"imports": [ "imports": [
{ {
"path": "dist/tfjs.esm.js", "path": "dist/tfjs.esm.js",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/box.js", "path": "src/handpose/box.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/util.js", "path": "src/handpose/util.ts",
"kind": "import-statement"
},
{
"path": "src/log.js",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/handpose/anchors.js": { "src/handpose/anchors.ts": {
"bytes": 224151, "bytes": 224156,
"imports": [] "imports": []
}, },
"src/handpose/handpose.js": { "src/handpose/handpose.ts": {
"bytes": 2578, "bytes": 2529,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -395,32 +370,32 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/handdetector.js", "path": "src/handpose/handdetector.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/handpipeline.js", "path": "src/handpose/handpipeline.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/anchors.js", "path": "src/handpose/anchors.ts",
"kind": "import-statement" "kind": "import-statement"
} }
] ]
}, },
"src/gesture/gesture.js": { "src/gesture/gesture.ts": {
"bytes": 4245, "bytes": 4265,
"imports": [] "imports": []
}, },
"src/imagefx.js": { "src/imagefx.js": {
"bytes": 19445, "bytes": 19447,
"imports": [] "imports": []
}, },
"src/image.js": { "src/image.ts": {
"bytes": 5871, "bytes": 5851,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -437,19 +412,19 @@
"bytes": 9786, "bytes": 9786,
"imports": [] "imports": []
}, },
"src/sample.js": { "src/sample.ts": {
"bytes": 55382, "bytes": 55382,
"imports": [] "imports": []
}, },
"package.json": { "package.json": {
"bytes": 2321, "bytes": 2344,
"imports": [] "imports": []
}, },
"src/human.js": { "src/human.ts": {
"bytes": 18962, "bytes": 19393,
"imports": [ "imports": [
{ {
"path": "src/log.js", "path": "src/log.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -457,51 +432,51 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/tfjs/backend.js", "path": "src/tfjs/backend.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/blazeface/facemesh.js", "path": "src/blazeface/facemesh.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/faceboxes/faceboxes.js", "path": "src/faceboxes/faceboxes.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/age/age.js", "path": "src/age/age.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/gender/gender.js", "path": "src/gender/gender.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/emotion/emotion.js", "path": "src/emotion/emotion.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/embedding/embedding.js", "path": "src/embedding/embedding.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/posenet/posenet.js", "path": "src/posenet/posenet.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/handpose/handpose.js", "path": "src/handpose/handpose.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/gesture/gesture.js", "path": "src/gesture/gesture.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/image.js", "path": "src/image.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/profile.js", "path": "src/profile.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -509,7 +484,7 @@
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
"path": "src/sample.js", "path": "src/sample.ts",
"kind": "import-statement" "kind": "import-statement"
}, },
{ {
@ -520,135 +495,132 @@
} }
}, },
"outputs": { "outputs": {
"dist/human.js.map": { "dist/human.ts.map": {
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": {}, "inputs": {},
"bytes": 1932088 "bytes": 1923057
}, },
"dist/human.js": { "dist/human.ts": {
"imports": [], "imports": [],
"exports": [], "exports": [],
"inputs": { "inputs": {
"src/blazeface/blazeface.js": { "src/blazeface/facemesh.ts": {
"bytesInOutput": 2915 "bytesInOutput": 1445
}, },
"src/blazeface/box.js": { "src/posenet/keypoints.ts": {
"bytesInOutput": 987 "bytesInOutput": 1690
},
"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/imagefx.js": { "src/imagefx.js": {
"bytesInOutput": 11004 "bytesInOutput": 11016
}, },
"src/image.js": { "src/human.ts": {
"bytesInOutput": 2480 "bytesInOutput": 10259
}, },
"src/human.js": { "src/log.ts": {
"bytesInOutput": 10573
},
"src/log.js": {
"bytesInOutput": 252 "bytesInOutput": 252
}, },
"dist/tfjs.esm.js": { "dist/tfjs.esm.js": {
"bytesInOutput": 1062888 "bytesInOutput": 1062782
}, },
"src/tfjs/backend.js": { "src/tfjs/backend.ts": {
"bytesInOutput": 1205 "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 "bytesInOutput": 938
}, },
"src/handpose/util.js": { "src/handpose/handdetector.ts": {
"bytesInOutput": 1668
},
"src/handpose/util.ts": {
"bytesInOutput": 816 "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": { "config.js": {
"bytesInOutput": 1426 "bytesInOutput": 1426
}, },
"src/sample.js": { "src/sample.ts": {
"bytesInOutput": 55295 "bytesInOutput": 55295
}, },
"package.json": { "package.json": {
"bytesInOutput": 16 "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, "bytes": 1784,
"imports": [ "imports": [
{ {
@ -28613,7 +28613,7 @@
"node_modules/@tensorflow/tfjs-backend-wasm/dist/index.js": { "node_modules/@tensorflow/tfjs-backend-wasm/dist/index.js": {
"bytesInOutput": 0 "bytesInOutput": 0
}, },
"src/tfjs/tf-browser.js": { "src/tfjs/tf-browser.ts": {
"bytesInOutput": 154 "bytesInOutput": 154
}, },
"node_modules/@tensorflow/tfjs-core/dist/public/chained_ops/abs.js": { "node_modules/@tensorflow/tfjs-core/dist/public/chained_ops/abs.js": {
@ -29739,7 +29739,7 @@
"bytesInOutput": 15 "bytesInOutput": 15
} }
}, },
"bytes": 1071833 "bytes": 1071825
} }
} }
} }

24
package-lock.json generated
View File

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

View File

@ -35,7 +35,7 @@
"@vladmandic/pilogger": "^0.2.14", "@vladmandic/pilogger": "^0.2.14",
"chokidar": "^3.5.1", "chokidar": "^3.5.1",
"dayjs": "^1.10.4", "dayjs": "^1.10.4",
"esbuild": "^0.8.42", "esbuild": "^0.8.43",
"eslint": "^7.19.0", "eslint": "^7.19.0",
"eslint-config-airbnb-base": "^14.2.1", "eslint-config-airbnb-base": "^14.2.1",
"eslint-plugin-import": "^2.22.1", "eslint-plugin-import": "^2.22.1",
@ -44,7 +44,9 @@
"eslint-plugin-promise": "^4.2.1", "eslint-plugin-promise": "^4.2.1",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"seedrandom": "^3.0.5", "seedrandom": "^3.0.5",
"simple-git": "^2.32.0" "simple-git": "^2.34.2",
"tslib": "^2.1.0",
"typescript": "^4.1.3"
}, },
"scripts": { "scripts": {
"start": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js", "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 // keeps esbuild service instance cached
let es; let es;
let busy = false;
const banner = ` const banner = `
/* /*
Human library Human library
@ -33,7 +34,7 @@ const targets = {
platform: 'node', platform: 'node',
format: 'cjs', format: 'cjs',
metafile: 'dist/tfjs.esm.json', metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-node.js'], entryPoints: ['src/tfjs/tf-node.ts'],
outfile: 'dist/tfjs.esm.js', outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'], external: ['@tensorflow'],
}, },
@ -41,7 +42,7 @@ const targets = {
platform: 'node', platform: 'node',
format: 'cjs', format: 'cjs',
metafile: 'dist/human.node.json', metafile: 'dist/human.node.json',
entryPoints: ['src/human.js'], entryPoints: ['src/human.ts'],
outfile: 'dist/human.node.js', outfile: 'dist/human.node.js',
external: ['@tensorflow'], external: ['@tensorflow'],
}, },
@ -51,7 +52,7 @@ const targets = {
platform: 'node', platform: 'node',
format: 'cjs', format: 'cjs',
metafile: 'dist/tfjs.esm.json', metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-node-gpu.js'], entryPoints: ['src/tfjs/tf-node-gpu.ts'],
outfile: 'dist/tfjs.esm.js', outfile: 'dist/tfjs.esm.js',
external: ['@tensorflow'], external: ['@tensorflow'],
}, },
@ -59,7 +60,7 @@ const targets = {
platform: 'node', platform: 'node',
format: 'cjs', format: 'cjs',
metafile: 'dist/human.node.json', metafile: 'dist/human.node.json',
entryPoints: ['src/human.js'], entryPoints: ['src/human.ts'],
outfile: 'dist/human.node-gpu.js', outfile: 'dist/human.node-gpu.js',
external: ['@tensorflow'], external: ['@tensorflow'],
}, },
@ -69,7 +70,7 @@ const targets = {
platform: 'browser', platform: 'browser',
format: 'esm', format: 'esm',
metafile: 'dist/tfjs.esm.json', metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-browser.js'], entryPoints: ['src/tfjs/tf-browser.ts'],
outfile: 'dist/tfjs.esm.js', outfile: 'dist/tfjs.esm.js',
external: ['fs', 'buffer', 'util', '@tensorflow'], external: ['fs', 'buffer', 'util', '@tensorflow'],
}, },
@ -77,7 +78,7 @@ const targets = {
platform: 'browser', platform: 'browser',
format: 'esm', format: 'esm',
metafile: 'dist/human.esm.json', metafile: 'dist/human.esm.json',
entryPoints: ['src/human.js'], entryPoints: ['src/human.ts'],
outfile: 'dist/human.esm-nobundle.js', outfile: 'dist/human.esm-nobundle.js',
external: ['fs', 'buffer', 'util', '@tensorflow'], external: ['fs', 'buffer', 'util', '@tensorflow'],
}, },
@ -87,7 +88,7 @@ const targets = {
platform: 'browser', platform: 'browser',
format: 'esm', format: 'esm',
metafile: 'dist/tfjs.esm.json', metafile: 'dist/tfjs.esm.json',
entryPoints: ['src/tfjs/tf-browser.js'], entryPoints: ['src/tfjs/tf-browser.ts'],
outfile: 'dist/tfjs.esm.js', outfile: 'dist/tfjs.esm.js',
external: ['fs', 'buffer', 'util'], external: ['fs', 'buffer', 'util'],
}, },
@ -95,16 +96,16 @@ const targets = {
platform: 'browser', platform: 'browser',
format: 'iife', format: 'iife',
globalName: 'Human', globalName: 'Human',
metafile: 'dist/human.json', metafile: 'dist/human.tson',
entryPoints: ['src/human.js'], entryPoints: ['src/human.ts'],
outfile: 'dist/human.js', outfile: 'dist/human.ts',
external: ['fs', 'buffer', 'util'], external: ['fs', 'buffer', 'util'],
}, },
esm: { esm: {
platform: 'browser', platform: 'browser',
format: 'esm', format: 'esm',
metafile: 'dist/human.esm.json', metafile: 'dist/human.esm.json',
entryPoints: ['src/human.js'], entryPoints: ['src/human.ts'],
outfile: 'dist/human.esm.js', outfile: 'dist/human.esm.js',
external: ['fs', 'buffer', 'util'], external: ['fs', 'buffer', 'util'],
}, },
@ -148,6 +149,12 @@ async function getStats(metafile) {
// rebuild on file change // rebuild on file change
async function build(f, msg) { 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); log.info('Build: file', msg, f, 'target:', common.target);
if (!es) es = await esbuild.startService(); if (!es) es = await esbuild.startService();
// common build options // common build options
@ -168,6 +175,7 @@ async function build(f, msg) {
log.error('Build error', JSON.stringify(err.errors || err, null, 2)); log.error('Build error', JSON.stringify(err.errors || err, null, 2));
if (require.main === module) process.exit(1); if (require.main === module) process.exit(1);
} }
busy = false;
} }
if (require.main === module) { if (require.main === module) {

View File

@ -21,9 +21,9 @@ Repository: **<${app.repository.url}>**
`; `;
async function update(f) { async function update(f) {
const all = await git.log(); const gitLog = await git.log();
// @ts-ignore // @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 = ''; let previous = '';
for (const l of log) { for (const l of log) {

View File

@ -52,6 +52,14 @@ const mime = {
'.wasm': 'application/wasm', '.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 // watch filesystem for any changes and notify build when needed
async function watch() { async function watch() {
const watcher = chokidar.watch(options.monitor, { const watcher = chokidar.watch(options.monitor, {
@ -66,9 +74,9 @@ async function watch() {
}); });
// single event handler for file add/change/delete // single event handler for file add/change/delete
watcher watcher
.on('add', (evt) => build.build(evt, 'add')) .on('add', (evt) => buildAll(evt, 'add'))
.on('change', (evt) => build.build(evt, 'modify')) .on('change', (evt) => buildAll(evt, 'modify'))
.on('unlink', (evt) => build.build(evt, 'remove')) .on('unlink', (evt) => buildAll(evt, 'remove'))
.on('error', (err) => log.error(`Client watcher error: ${err}`)) .on('error', (err) => log.error(`Client watcher error: ${err}`))
.on('ready', () => log.state('Monitoring:', options.monitor)); .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 tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js'; import * as profile from '../profile.js';
const models = {}; const models = { age: null };
let last = { age: 0 }; let last = { age: 0 };
let skipped = Number.MAX_SAFE_INTEGER; let skipped = Number.MAX_SAFE_INTEGER;
async function load(config) { export async function load(config) {
if (!models.age) { if (!models.age) {
models.age = await tf.loadGraphModel(config.face.age.modelPath); models.age = await tf.loadGraphModel(config.face.age.modelPath);
log(`load model: ${config.face.age.modelPath.match(/\/(.*)\./)[1]}`); log(`load model: ${config.face.age.modelPath.match(/\/(.*)\./)[1]}`);
@ -14,7 +14,7 @@ async function load(config) {
return models.age; return models.age;
} }
async function predict(image, config) { export async function predict(image, config) {
if (!models.age) return null; if (!models.age) return null;
if ((skipped < config.face.age.skipFrames) && config.videoOptimized && last.age && (last.age > 0)) { if ((skipped < config.face.age.skipFrames) && config.videoOptimized && last.age && (last.age > 0)) {
skipped++; skipped++;
@ -38,15 +38,15 @@ async function predict(image, config) {
tf.dispose(resize); tf.dispose(resize);
let ageT; let ageT;
const obj = {}; const obj = { age: undefined };
if (models.age) {
if (!config.profile) { if (!config.profile) {
if (config.face.age.enabled) ageT = await models.age.predict(enhance); if (config.face.age.enabled) ageT = await models.age.predict(enhance);
} else { } else {
const profileAge = config.face.age.enabled ? await tf.profile(() => models.age.predict(enhance)) : {}; const profileAge = config.face.age.enabled ? await tf.profile(() => models.age.predict(enhance)) : {};
ageT = profileAge.result.clone(); ageT = profileAge.result.clone();
profileAge.result.dispose(); profileAge.result.dispose();
// @ts-ignore
profile.run('age', profileAge); profile.run('age', profileAge);
} }
enhance.dispose(); enhance.dispose();
@ -58,9 +58,7 @@ async function predict(image, config) {
ageT.dispose(); ageT.dispose();
last = obj; last = obj;
}
resolve(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'; import * as tf from '../../dist/tfjs.esm.js';
const NUM_LANDMARKS = 6; const NUM_LANDMARKS = 6;
@ -24,7 +24,7 @@ function generateAnchors(inputSize) {
return anchors; return anchors;
} }
const disposeBox = (box) => { export const disposeBox = (box) => {
box.startEndTensor.dispose(); box.startEndTensor.dispose();
box.startPoint.dispose(); box.startPoint.dispose();
box.endPoint.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) { constructor(model, config) {
this.blazeFaceModel = model; this.blazeFaceModel = model;
this.width = config.face.detector.inputSize; this.width = config.face.detector.inputSize;
@ -132,47 +141,11 @@ class BlazeFaceModel {
scaleFactor: [inputImage.shape[2] / this.width, inputImage.shape[1] / this.height], 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 blazeface = await tf.loadGraphModel(config.face.detector.modelPath, { fromTFHub: config.face.detector.modelPath.includes('tfhub.dev') });
const model = new BlazeFaceModel(blazeface, config); const model = new BlazeFaceModel(blazeface, config);
log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`); log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`);
return model; 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'; 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 startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];
const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]]; const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];
return { startPoint, endPoint }; return { startPoint, endPoint };
} }
exports.scaleBoxCoordinates = scaleBoxCoordinates;
function getBoxSize(box) { export function getBoxSize(box) {
return [ return [
Math.abs(box.endPoint[0] - box.startPoint[0]), Math.abs(box.endPoint[0] - box.startPoint[0]),
Math.abs(box.endPoint[1] - box.startPoint[1]), Math.abs(box.endPoint[1] - box.startPoint[1]),
]; ];
} }
exports.getBoxSize = getBoxSize;
function getBoxCenter(box) { export function getBoxCenter(box) {
return [ return [
box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2, box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,
box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 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 h = image.shape[1];
const w = image.shape[2]; const w = image.shape[2];
const boxes = [[ const boxes = [[
@ -32,9 +29,8 @@ function cutBoxFromImageAndResize(box, image, cropSize) {
]]; ]];
return tf.image.cropAndResize(image, boxes, [0], 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 center = getBoxCenter(box);
const size = getBoxSize(box); const size = getBoxSize(box);
const newHalfSize = [factor * size[0] / 2, factor * size[1] / 2]; 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]]; const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];
return { startPoint, endPoint, landmarks: box.landmarks }; return { startPoint, endPoint, landmarks: box.landmarks };
} }
exports.enlargeBox = enlargeBox;
function squarifyBox(box) { export function squarifyBox(box) {
const centers = getBoxCenter(box); const centers = getBoxCenter(box);
const size = getBoxSize(box); const size = getBoxSize(box);
const maxEdge = Math.max(...size); const maxEdge = Math.max(...size);
@ -53,4 +48,3 @@ function squarifyBox(box) {
const endPoint = [centers[0] + halfSize, centers[1] + halfSize]; const endPoint = [centers[0] + halfSize, centers[1] + halfSize];
return { startPoint, endPoint, landmarks: box.landmarks }; return { startPoint, endPoint, landmarks: box.landmarks };
} }
exports.squarifyBox = squarifyBox;

View File

@ -1,4 +1,4 @@
const MESH_ANNOTATIONS = { export const MESH_ANNOTATIONS = {
silhouette: [ silhouette: [
10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288, 10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288,
397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136, 397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136,
@ -37,7 +37,7 @@ const MESH_ANNOTATIONS = {
leftCheek: [425], 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: 'EyeUpper0', indices: [9, 10, 11, 12, 13, 14, 15] },
{ key: 'EyeUpper1', indices: [25, 26, 27, 28, 29, 30, 31] }, { key: 'EyeUpper1', indices: [25, 26, 27, 28, 29, 30, 31] },
{ key: 'EyeUpper2', indices: [41, 42, 43, 44, 45, 46, 47] }, { 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] }, // { key: 'EyebrowLower', indices: [48, 49, 50, 51, 52, 53] },
]; ];
const UV468 = [ export const UV468 = [
[0.499976992607117, 0.652534008026123], [0.499976992607117, 0.652534008026123],
[0.500025987625122, 0.547487020492554], [0.500025987625122, 0.547487020492554],
[0.499974012374878, 0.602371990680695], [0.499974012374878, 0.602371990680695],
@ -520,7 +520,7 @@ const UV468 = [
[0.723330020904541, 0.363372981548309], [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, 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, 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, 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, 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]; 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, 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, 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, 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, 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, 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]; 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* 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, /* brows */ 70, 63, 105, 66, 107, 336, 296, 334, 293, 300,
/* nose */ 168, 6, 195, 4, 98, 97, 2, 326, 327, /* 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, /* lip */ 57, 40, 37, 0, 267, 270, 287, 321, 314, 17, 84, 91,
/* mouth */ 78, 81, 13, 311, 308, 402, 14, 178, /* 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; 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.MESH_TO_IRIS_INDICES_MAP = MESH_TO_IRIS_INDICES_MAP;
exports.TRI468 = TRI468; export const VTX7 = [33, 133, 362, 263, 1, 78, 308];
exports.TRI68 = TRI68;
exports.TRI33 = TRI33;
exports.TRI7 = TRI7;
exports.UV468 = UV468; export const UV68 = VTX68.map((x) => UV468[x]);
exports.UV68 = VTX68.map((x) => UV468[x]);
exports.UV33 = VTX33.map((x) => UV468[x]); export const UV33 = VTX33.map((x) => UV468[x]);
exports.UV7 = VTX7.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 tf from '../../dist/tfjs.esm.js';
import * as blazeface from './blazeface.js'; import * as blazeface from './blazeface.js';
import * as facepipeline from './facepipeline.js'; import * as facepipeline from './facepipeline.js';
import * as coords from './coords.js'; import * as coords from './coords.js';
class MediaPipeFaceMesh { export class MediaPipeFaceMesh {
facePipeline: any;
config: any;
constructor(blazeFace, blazeMeshModel, irisModel, config) { constructor(blazeFace, blazeMeshModel, irisModel, config) {
// @ts-ignore
this.facePipeline = new facepipeline.Pipeline(blazeFace, blazeMeshModel, irisModel, config); this.facePipeline = new facepipeline.Pipeline(blazeFace, blazeMeshModel, irisModel, config);
this.config = config; this.config = config;
} }
@ -48,7 +50,7 @@ class MediaPipeFaceMesh {
} }
let faceModels = [null, null, null]; let faceModels = [null, null, null];
async function load(config) { export async function load(config) {
faceModels = await Promise.all([ faceModels = await Promise.all([
(!faceModels[0] && config.face.enabled) ? blazeface.load(config) : null, (!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, (!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; return faceMesh;
} }
exports.load = load;
exports.MediaPipeFaceMesh = MediaPipeFaceMesh;
exports.triangulation = coords.TRI468; exports.triangulation = coords.TRI468;

View File

@ -4,7 +4,7 @@ import * as bounding from './box';
import * as util from './util'; import * as util from './util';
import * as coords from './coords.js'; import * as coords from './coords.js';
// eslint-disable-next-line no-unused-vars // eslint-disable-next-line no-unused-vars
import { log } from '../log.js'; import { log } from '../log';
const LANDMARKS_COUNT = 468; const LANDMARKS_COUNT = 468;
const MESH_MOUTH_INDEX = 13; const MESH_MOUTH_INDEX = 13;
@ -22,11 +22,11 @@ const IRIS_IRIS_INDEX = 71;
const IRIS_NUM_COORDINATES = 76; 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. // 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++) { for (let i = 0; i < coords.MESH_TO_IRIS_INDICES_MAP.length; i++) {
const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i]; const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i];
const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`]; const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`];
const shouldReplaceAllKeys = keys == null; const shouldReplaceAllKeys = keys === null;
if (shouldReplaceAllKeys || keys.includes(key)) { if (shouldReplaceAllKeys || keys.includes(key)) {
for (let j = 0; j < indices.length; j++) { for (let j = 0; j < indices.length; j++) {
const index = indices[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. // 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) { constructor(boundingBoxDetector, meshDetector, irisModel, config) {
// An array of facial bounding boxes. // An array of facial bounding boxes.
this.storedBoxes = []; this.storedBoxes = [];
@ -56,7 +68,6 @@ class Pipeline {
} }
transformRawCoords(rawCoords, box, angle, rotationMatrix) { transformRawCoords(rawCoords, box, angle, rotationMatrix) {
// @ts-ignore
const boxSize = bounding.getBoxSize({ startPoint: box.startPoint, endPoint: box.endPoint }); const boxSize = bounding.getBoxSize({ startPoint: box.startPoint, endPoint: box.endPoint });
const scaleFactor = [boxSize[0] / this.meshWidth, boxSize[1] / this.meshHeight]; const scaleFactor = [boxSize[0] / this.meshWidth, boxSize[1] / this.meshHeight];
const coordsScaled = rawCoords.map((coord) => ([ const coordsScaled = rawCoords.map((coord) => ([
@ -66,7 +77,6 @@ class Pipeline {
const coordsRotationMatrix = (angle !== 0) ? util.buildRotationMatrix(angle, [0, 0]) : util.IDENTITY_MATRIX; 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 coordsRotated = (angle !== 0) ? coordsScaled.map((coord) => ([...util.rotatePoint(coord, coordsRotationMatrix), coord[2]])) : coordsScaled;
const inverseRotationMatrix = (angle !== 0) ? util.invertTransformMatrix(rotationMatrix) : util.IDENTITY_MATRIX; const inverseRotationMatrix = (angle !== 0) ? util.invertTransformMatrix(rotationMatrix) : util.IDENTITY_MATRIX;
// @ts-ignore
const boxCenter = [...bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint }), 1]; const boxCenter = [...bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint }), 1];
return coordsRotated.map((coord) => ([ return coordsRotated.map((coord) => ([
coord[0] + util.dot(boxCenter, inverseRotationMatrix[0]), 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. // Returns a box describing a cropped region around the eye fit for passing to the iris model.
getEyeBox(rawCoords, face, eyeInnerCornerIndex, eyeOuterCornerIndex, flip = false) { getEyeBox(rawCoords, face, eyeInnerCornerIndex, eyeOuterCornerIndex, flip = false) {
// @ts-ignore
const box = bounding.squarifyBox(bounding.enlargeBox(this.calculateLandmarksBoundingBox([rawCoords[eyeInnerCornerIndex], rawCoords[eyeOuterCornerIndex]]), this.irisEnlarge)); const box = bounding.squarifyBox(bounding.enlargeBox(this.calculateLandmarksBoundingBox([rawCoords[eyeInnerCornerIndex], rawCoords[eyeOuterCornerIndex]]), this.irisEnlarge));
// @ts-ignore
const boxSize = bounding.getBoxSize(box); const boxSize = bounding.getBoxSize(box);
let crop = tf.image.cropAndResize(face, [[ let crop = tf.image.cropAndResize(face, [[
box.startPoint[1] / this.meshHeight, box.startPoint[1] / this.meshHeight,
@ -159,11 +167,8 @@ class Pipeline {
return null; return null;
} }
for (let i = 0; i < this.storedBoxes.length; i++) { 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); const scaledBox = bounding.scaleBoxCoordinates({ startPoint: this.storedBoxes[i].startPoint, endPoint: this.storedBoxes[i].endPoint }, detector.scaleFactor);
// @ts-ignore
const enlargedBox = bounding.enlargeBox(scaledBox); const enlargedBox = bounding.enlargeBox(scaledBox);
// @ts-ignore
const squarifiedBox = bounding.squarifyBox(enlargedBox); const squarifiedBox = bounding.squarifyBox(enlargedBox);
const landmarks = this.storedBoxes[i].landmarks.arraySync(); const landmarks = this.storedBoxes[i].landmarks.arraySync();
const confidence = this.storedBoxes[i].confidence; const confidence = this.storedBoxes[i].confidence;
@ -188,17 +193,14 @@ class Pipeline {
if (config.face.detector.rotation) { 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; 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]); angle = util.computeRotation(box.landmarks[indexOfMouth], box.landmarks[indexOfForehead]);
// @ts-ignore
const faceCenter = bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint }); const faceCenter = bounding.getBoxCenter({ startPoint: box.startPoint, endPoint: box.endPoint });
const faceCenterNormalized = [faceCenter[0] / input.shape[2], faceCenter[1] / input.shape[1]]; const faceCenterNormalized = [faceCenter[0] / input.shape[2], faceCenter[1] / input.shape[1]];
const rotatedImage = tf.image.rotateWithOffset(input, angle, 0, faceCenterNormalized); const rotatedImage = tf.image.rotateWithOffset(input, angle, 0, faceCenterNormalized);
rotationMatrix = util.buildRotationMatrix(-angle, faceCenter); rotationMatrix = util.buildRotationMatrix(-angle, faceCenter);
// @ts-ignore
face = bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotatedImage, [this.meshHeight, this.meshWidth]).div(255); face = bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, rotatedImage, [this.meshHeight, this.meshWidth]).div(255);
} else { } else {
rotationMatrix = util.IDENTITY_MATRIX; rotationMatrix = util.IDENTITY_MATRIX;
const cloned = input.clone(); const cloned = input.clone();
// @ts-ignore
face = bounding.cutBoxFromImageAndResize({ startPoint: box.startPoint, endPoint: box.endPoint }, cloned, [this.meshHeight, this.meshWidth]).div(255); 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 [, confidence, contourCoords] = this.meshDetector.predict(face); // The first returned tensor represents facial contours, which are included in the coordinates.
const confidenceVal = confidence.dataSync()[0]; const faceConfidence = confidence.dataSync()[0];
if (confidenceVal < config.face.detector.minConfidence) return null; // if below confidence just exit if (faceConfidence < config.face.detector.minConfidence) return null; // if below confidence just exit
const coordsReshaped = tf.reshape(contourCoords, [-1, 3]); const coordsReshaped = tf.reshape(contourCoords, [-1, 3]);
let rawCoords = coordsReshaped.arraySync(); let rawCoords = coordsReshaped.arraySync();
@ -245,20 +247,19 @@ class Pipeline {
} }
const transformedCoordsData = this.transformRawCoords(rawCoords, box, angle, rotationMatrix); const transformedCoordsData = this.transformRawCoords(rawCoords, box, angle, rotationMatrix);
// @ts-ignore
const landmarksBox = bounding.enlargeBox(this.calculateLandmarksBoundingBox(transformedCoordsData)); const landmarksBox = bounding.enlargeBox(this.calculateLandmarksBoundingBox(transformedCoordsData));
// @ts-ignore
const squarifiedLandmarksBox = bounding.squarifyBox(landmarksBox); const squarifiedLandmarksBox = bounding.squarifyBox(landmarksBox);
const transformedCoords = tf.tensor2d(transformedCoordsData); const transformedCoords = tf.tensor2d(transformedCoordsData);
const prediction = { const prediction = {
coords: transformedCoords, coords: transformedCoords,
box: landmarksBox, box: landmarksBox,
faceConfidence: confidenceVal, faceConfidence,
confidence: box.confidence, confidence: box.confidence,
image: face, image: face,
rawCoords,
}; };
if (config.face.mesh.returnRawData) prediction.rawCoords = rawCoords; if (!config.face.mesh.returnRawData) delete prediction.rawCoords;
this.storedBoxes[i] = { ...squarifiedLandmarksBox, landmarks: transformedCoords.arraySync(), confidence: box.confidence, faceConfidence: confidenceVal }; this.storedBoxes[i] = { ...squarifiedLandmarksBox, landmarks: transformedCoords.arraySync(), confidence: box.confidence, faceConfidence };
return prediction; return prediction;
})); }));
@ -275,4 +276,3 @@ class Pipeline {
return { startPoint, endPoint, landmarks }; 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. * Normalizes the provided angle to the range -pi to pi.
* @param angle The angle in radians to be normalized. * @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)); 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. * Computes the angle of rotation between two anchor points.
* @param point1 First anchor point * @param point1 First anchor point
* @param point2 Second 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]); const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);
return normalizeRadians(radians); return normalizeRadians(radians);
} }
exports.computeRotation = computeRotation;
function radToDegrees(rad) { export function radToDegrees(rad) {
return rad * 180 / Math.PI; 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]]; return [[1, 0, x], [0, 1, y], [0, 0, 1]];
} }
function dot(v1, v2) { export function dot(v1, v2) {
let product = 0; let product = 0;
for (let i = 0; i < v1.length; i++) { for (let i = 0; i < v1.length; i++) {
product += v1[i] * v2[i]; product += v1[i] * v2[i];
} }
return product; return product;
} }
exports.dot = dot;
function getColumnFrom2DArr(arr, columnIndex) { export function getColumnFrom2DArr(arr, columnIndex) {
const column = []; const column = [];
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
column.push(arr[i][columnIndex]); column.push(arr[i][columnIndex]);
} }
return column; return column;
} }
exports.getColumnFrom2DArr = getColumnFrom2DArr;
function multiplyTransformMatrices(mat1, mat2) { export function multiplyTransformMatrices(mat1, mat2) {
const product = []; const product = [];
const size = mat1.length; const size = mat1.length;
for (let row = 0; row < size; row++) { for (let row = 0; row < size; row++) {
@ -57,7 +52,8 @@ function multiplyTransformMatrices(mat1, mat2) {
} }
return product; return product;
} }
function buildRotationMatrix(rotation, center) {
export function buildRotationMatrix(rotation, center) {
const cosA = Math.cos(rotation); const cosA = Math.cos(rotation);
const sinA = Math.sin(rotation); const sinA = Math.sin(rotation);
const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]; 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]); const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);
return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix); 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 rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];
const translationComponent = [matrix[0][2], matrix[1][2]]; const translationComponent = [matrix[0][2], matrix[1][2]];
const invertedTranslation = [ const invertedTranslation = [
@ -81,17 +76,14 @@ function invertTransformMatrix(matrix) {
[0, 0, 1], [0, 0, 1],
]; ];
} }
exports.invertTransformMatrix = invertTransformMatrix;
function rotatePoint(homogeneousCoordinate, rotationMatrix) { export function rotatePoint(homogeneousCoordinate, rotationMatrix) {
return [ return [
dot(homogeneousCoordinate, rotationMatrix[0]), dot(homogeneousCoordinate, rotationMatrix[0]),
dot(homogeneousCoordinate, rotationMatrix[1]), 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)); 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 tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js'; import * as profile from '../profile.js';
// based on https://github.com/sirius-ai/MobileFaceNet_TF // 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 // 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) { if (!models.embedding) {
models.embedding = await tf.loadGraphModel(config.face.embedding.modelPath); models.embedding = await tf.loadGraphModel(config.face.embedding.modelPath);
log(`load model: ${config.face.embedding.modelPath.match(/\/(.*)\./)[1]}`); log(`load model: ${config.face.embedding.modelPath.match(/\/(.*)\./)[1]}`);
@ -15,7 +15,7 @@ async function load(config) {
return models.embedding; return models.embedding;
} }
function simmilarity(embedding1, embedding2) { export function simmilarity(embedding1, embedding2) {
if (embedding1?.length !== embedding2?.length) return 0; if (embedding1?.length !== embedding2?.length) return 0;
// general minkowski distance // general minkowski distance
// euclidean distance is limited case where order is 2 // euclidean distance is limited case where order is 2
@ -24,7 +24,7 @@ function simmilarity(embedding1, embedding2) {
return (Math.trunc(1000 * (1 - distance)) / 1000); return (Math.trunc(1000 * (1 - distance)) / 1000);
} }
async function predict(image, config) { export async function predict(image, config) {
if (!models.embedding) return null; if (!models.embedding) return null;
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
const resize = tf.image.resizeBilinear(image, [config.face.embedding.inputSize, config.face.embedding.inputSize], false); 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 })); const profileData = await tf.profile(() => models.embedding.predict({ img_inputs: resize }));
data = [...profileData.result.dataSync()]; data = [...profileData.result.dataSync()];
profileData.result.dispose(); profileData.result.dispose();
// @ts-ignore
profile.run('emotion', profileData); profile.run('emotion', profileData);
} }
} }
@ -48,7 +47,3 @@ async function predict(image, config) {
resolve(data); 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 tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js'; import * as profile from '../profile.js';
const annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral']; const annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];
const models = {}; const models = { emotion: null };
let last = []; let last = [];
let skipped = Number.MAX_SAFE_INTEGER; 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 rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale
const scale = 1; // score multiplication factor const scale = 1; // score multiplication factor
async function load(config) { export async function load(config) {
if (!models.emotion) { if (!models.emotion) {
models.emotion = await tf.loadGraphModel(config.face.emotion.modelPath); models.emotion = await tf.loadGraphModel(config.face.emotion.modelPath);
log(`load model: ${config.face.emotion.modelPath.match(/\/(.*)\./)[1]}`); log(`load model: ${config.face.emotion.modelPath.match(/\/(.*)\./)[1]}`);
@ -19,7 +19,7 @@ async function load(config) {
return models.emotion; return models.emotion;
} }
async function predict(image, config) { export async function predict(image, config) {
if (!models.emotion) return null; if (!models.emotion) return null;
if ((skipped < config.face.emotion.skipFrames) && config.videoOptimized && (last.length > 0)) { if ((skipped < config.face.emotion.skipFrames) && config.videoOptimized && (last.length > 0)) {
skipped++; skipped++;
@ -77,6 +77,3 @@ async function predict(image, config) {
resolve(obj); 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 tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js'; import * as profile from '../profile.js';
class FaceBoxes { export class FaceBoxes {
enlarge: number;
model: any;
config: any;
constructor(model, config) { constructor(model, config) {
this.enlarge = 1.1;
this.model = model; this.model = model;
this.config = config; this.config = config;
} }
@ -36,15 +41,20 @@ class FaceBoxes {
resizeT.dispose(); resizeT.dispose();
for (const i in boxes) { for (const i in boxes) {
if (scores[i] && scores[i] > this.config.face.detector.minConfidence) { if (scores[i] && scores[i] > this.config.face.detector.minConfidence) {
const enlarge = 1.05; const crop = [boxes[i][0] / this.enlarge, boxes[i][1] / this.enlarge, boxes[i][2] * this.enlarge, boxes[i][3] * this.enlarge];
const crop = [boxes[i][0] / enlarge, boxes[i][1] / enlarge, boxes[i][2] * enlarge, boxes[i][3] * enlarge];
const boxRaw = [crop[1], crop[0], (crop[3]) - (crop[1]), (crop[2]) - (crop[0])]; 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 box = [
const image = tf.image.cropAndResize(input, [crop], [0], [this.config.face.detector.inputSize, this.config.face.detector.inputSize]); 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({ results.push({
confidence: scores[i], confidence: scores[i],
box, box,
boxRaw, boxRaw: this.config.face.mesh.returnRawData ? boxRaw : null,
image, image,
// mesh, // mesh,
// meshRaw, // 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); const model = await tf.loadGraphModel(config.face.detector.modelPath);
log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`); log(`load model: ${config.face.detector.modelPath.match(/\/(.*)\./)[1]}`);
const faceboxes = new FaceBoxes(model, config); 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]}`); if (config.face.iris.enabled) log(`load model: ${config.face.iris.modelPath.match(/\/(.*)\./)[1]}`);
return faceboxes; 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 tf from '../../dist/tfjs.esm.js';
import * as profile from '../profile.js'; import * as profile from '../profile.js';
const models = {}; const models = { gender: null };
let last = { gender: '' }; let last = { gender: '' };
let skipped = Number.MAX_SAFE_INTEGER; let skipped = Number.MAX_SAFE_INTEGER;
let alternative = false; let alternative = false;
@ -10,7 +10,7 @@ let alternative = false;
// tuning values // tuning values
const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale 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) { if (!models.gender) {
models.gender = await tf.loadGraphModel(config.face.gender.modelPath); models.gender = await tf.loadGraphModel(config.face.gender.modelPath);
alternative = models.gender.inputs[0].shape[3] === 1; alternative = models.gender.inputs[0].shape[3] === 1;
@ -19,7 +19,7 @@ async function load(config) {
return models.gender; return models.gender;
} }
async function predict(image, config) { export async function predict(image, config) {
if (!models.gender) return null; if (!models.gender) return null;
if ((skipped < config.face.gender.skipFrames) && config.videoOptimized && last.gender !== '') { if ((skipped < config.face.gender.skipFrames) && config.videoOptimized && last.gender !== '') {
skipped++; skipped++;
@ -45,7 +45,7 @@ async function predict(image, config) {
tf.dispose(resize); tf.dispose(resize);
let genderT; let genderT;
const obj = {}; const obj = { gender: undefined, confidence: undefined };
if (!config.profile) { if (!config.profile) {
if (config.face.gender.enabled) genderT = await models.gender.predict(enhance); 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)) : {}; const profileGender = config.face.gender.enabled ? await tf.profile(() => models.gender.predict(enhance)) : {};
genderT = profileGender.result.clone(); genderT = profileGender.result.clone();
profileGender.result.dispose(); profileGender.result.dispose();
// @ts-ignore
profile.run('gender', profileGender); profile.run('gender', profileGender);
} }
enhance.dispose(); enhance.dispose();
@ -82,6 +81,3 @@ async function predict(image, config) {
resolve(obj); resolve(obj);
}); });
} }
exports.predict = predict;
exports.load = load;

View File

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

View File

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

View File

@ -1,18 +1,20 @@
import * as tf from '../../dist/tfjs.esm.js'; import * as tf from '../../dist/tfjs.esm.js';
function getBoxSize(box) { export function getBoxSize(box) {
return [ return [
Math.abs(box.endPoint[0] - box.startPoint[0]), Math.abs(box.endPoint[0] - box.startPoint[0]),
Math.abs(box.endPoint[1] - box.startPoint[1]), Math.abs(box.endPoint[1] - box.startPoint[1]),
]; ];
} }
function getBoxCenter(box) {
export function getBoxCenter(box) {
return [ return [
box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2, box.startPoint[0] + (box.endPoint[0] - box.startPoint[0]) / 2,
box.startPoint[1] + (box.endPoint[1] - box.startPoint[1]) / 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 h = image.shape[1];
const w = image.shape[2]; const w = image.shape[2];
const boxes = [[ const boxes = [[
@ -23,7 +25,8 @@ function cutBoxFromImageAndResize(box, image, cropSize) {
]]; ]];
return tf.image.cropAndResize(image, boxes, [0], 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 startPoint = [box.startPoint[0] * factor[0], box.startPoint[1] * factor[1]];
const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]]; const endPoint = [box.endPoint[0] * factor[0], box.endPoint[1] * factor[1]];
const palmLandmarks = box.palmLandmarks.map((coord) => { const palmLandmarks = box.palmLandmarks.map((coord) => {
@ -32,7 +35,8 @@ function scaleBoxCoordinates(box, factor) {
}); });
return { startPoint, endPoint, palmLandmarks, confidence: box.confidence }; 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 center = getBoxCenter(box);
const size = getBoxSize(box); const size = getBoxSize(box);
const newHalfSize = [factor * size[0] / 2, factor * size[1] / 2]; 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]]; const endPoint = [center[0] + newHalfSize[0], center[1] + newHalfSize[1]];
return { startPoint, endPoint, palmLandmarks: box.palmLandmarks }; return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };
} }
function squarifyBox(box) {
export function squarifyBox(box) {
const centers = getBoxCenter(box); const centers = getBoxCenter(box);
const size = getBoxSize(box); const size = getBoxSize(box);
const maxEdge = Math.max(...size); const maxEdge = Math.max(...size);
@ -49,7 +54,8 @@ function squarifyBox(box) {
const endPoint = [centers[0] + halfSize, centers[1] + halfSize]; const endPoint = [centers[0] + halfSize, centers[1] + halfSize];
return { startPoint, endPoint, palmLandmarks: box.palmLandmarks }; return { startPoint, endPoint, palmLandmarks: box.palmLandmarks };
} }
function shiftBox(box, shiftFactor) {
export function shiftBox(box, shiftFactor) {
const boxSize = [ const boxSize = [
box.endPoint[0] - box.startPoint[0], box.endPoint[0] - box.startPoint[0],
box.endPoint[1] - box.startPoint[1], 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]]; const endPoint = [box.endPoint[0] + shiftVector[0], box.endPoint[1] + shiftVector[1]];
return { startPoint, endPoint, palmLandmarks: box.palmLandmarks }; 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 tf from '../../dist/tfjs.esm.js';
import * as box from './box'; import * as box from './box';
class HandDetector { export class HandDetector {
model: any;
anchors: any;
anchorsTensor: any;
inputSizeTensor: any;
doubleInputSizeTensor: any;
constructor(model, inputSize, anchorsAnnotated) { constructor(model, inputSize, anchorsAnnotated) {
this.model = model; this.model = model;
this.anchors = anchorsAnnotated.map((anchor) => [anchor.x_center, anchor.y_center]); this.anchors = anchorsAnnotated.map((anchor) => [anchor.x_center, anchor.y_center]);
@ -78,4 +84,3 @@ class HandDetector {
return hands; 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 box from './box';
import * as util from './util'; import * as util from './util';
// eslint-disable-next-line no-unused-vars // 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_SHIFT_VECTOR = [0, -0.4];
const PALM_BOX_ENLARGE_FACTOR = 5; // default 3 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_PALM_BASE = 0;
const PALM_LANDMARKS_INDEX_OF_MIDDLE_FINGER_BASE = 2; 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) { constructor(handDetector, landmarkDetector, inputSize) {
this.handDetector = handDetector; this.handDetector = handDetector;
this.landmarkDetector = landmarkDetector; this.landmarkDetector = landmarkDetector;
@ -154,5 +161,3 @@ class HandPipeline {
return { startPoint, endPoint }; return { startPoint, endPoint };
} }
} }
exports.HandPipeline = HandPipeline;

View File

@ -1,6 +1,6 @@
// https://storage.googleapis.com/tfjs-models/demos/handpose/index.html // 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 tf from '../../dist/tfjs.esm.js';
import * as handdetector from './handdetector'; import * as handdetector from './handdetector';
import * as handpipeline from './handpipeline'; import * as handpipeline from './handpipeline';
@ -15,7 +15,9 @@ const MESH_ANNOTATIONS = {
palmBase: [0], palmBase: [0],
}; };
class HandPose { export class HandPose {
handPipeline: any;
constructor(handPipeline) { constructor(handPipeline) {
this.handPipeline = handPipeline; this.handPipeline = handPipeline;
} }
@ -51,20 +53,16 @@ class HandPose {
return hands; return hands;
} }
} }
exports.HandPose = HandPose;
async function load(config) { export async function load(config) {
const [handDetectorModel, handPoseModel] = await Promise.all([ 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.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, 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); const handDetector = new handdetector.HandDetector(handDetectorModel, config.hand.inputSize, anchors.anchors);
// @ts-ignore
const handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel, config.hand.inputSize); const handPipeline = new handpipeline.HandPipeline(handDetector, handPoseModel, config.hand.inputSize);
const handPose = new HandPose(handPipeline); const handPose = new HandPose(handPipeline);
if (config.hand.enabled) log(`load model: ${config.hand.detector.modelPath.match(/\/(.*)\./)[1]}`); 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]}`); if (config.hand.landmarks) log(`load model: ${config.hand.skeleton.modelPath.match(/\/(.*)\./)[1]}`);
return handPose; 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)); 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]); const radians = Math.PI / 2 - Math.atan2(-(point2[1] - point1[1]), point2[0] - point1[0]);
return normalizeRadians(radians); 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; let product = 0;
for (let i = 0; i < v1.length; i++) { for (let i = 0; i < v1.length; i++) {
product += v1[i] * v2[i]; product += v1[i] * v2[i];
} }
return product; return product;
} }
function getColumnFrom2DArr(arr, columnIndex) {
export function getColumnFrom2DArr(arr, columnIndex) {
const column = []; const column = [];
for (let i = 0; i < arr.length; i++) { for (let i = 0; i < arr.length; i++) {
column.push(arr[i][columnIndex]); column.push(arr[i][columnIndex]);
} }
return column; return column;
} }
function multiplyTransformMatrices(mat1, mat2) {
export function multiplyTransformMatrices(mat1, mat2) {
const product = []; const product = [];
const size = mat1.length; const size = mat1.length;
for (let row = 0; row < size; row++) { for (let row = 0; row < size; row++) {
product.push([]); product.push([]);
for (let col = 0; col < size; col++) { for (let col = 0; col < size; col++) {
// @ts-ignore
product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col))); product[row].push(dot(mat1[row], getColumnFrom2DArr(mat2, col)));
} }
} }
return product; return product;
} }
function buildRotationMatrix(rotation, center) {
export function buildRotationMatrix(rotation, center) {
const cosA = Math.cos(rotation); const cosA = Math.cos(rotation);
const sinA = Math.sin(rotation); const sinA = Math.sin(rotation);
const rotationMatrix = [[cosA, -sinA, 0], [sinA, cosA, 0], [0, 0, 1]]; 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]); const negativeTranslationMatrix = buildTranslationMatrix(-center[0], -center[1]);
return multiplyTransformMatrices(translationTimesRotation, negativeTranslationMatrix); 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 rotationComponent = [[matrix[0][0], matrix[1][0]], [matrix[0][1], matrix[1][1]]];
const translationComponent = [matrix[0][2], matrix[1][2]]; const translationComponent = [matrix[0][2], matrix[1][2]];
const invertedTranslation = [ const invertedTranslation = [
@ -54,18 +60,10 @@ function invertTransformMatrix(matrix) {
[0, 0, 1], [0, 0, 1],
]; ];
} }
function rotatePoint(homogeneousCoordinate, rotationMatrix) {
export function rotatePoint(homogeneousCoordinate, rotationMatrix) {
return [ return [
dot(homogeneousCoordinate, rotationMatrix[0]), dot(homogeneousCoordinate, rotationMatrix[0]),
dot(homogeneousCoordinate, rotationMatrix[1]), 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 tf from '../dist/tfjs.esm.js';
import * as backend from './tfjs/backend.js'; import * as backend from './tfjs/backend';
import * as facemesh from './blazeface/facemesh.js'; import * as facemesh from './blazeface/facemesh';
import * as faceboxes from './faceboxes/faceboxes.js'; import * as faceboxes from './faceboxes/faceboxes';
import * as age from './age/age.js'; import * as age from './age/age';
import * as gender from './gender/gender.js'; import * as gender from './gender/gender';
import * as emotion from './emotion/emotion.js'; import * as emotion from './emotion/emotion';
import * as embedding from './embedding/embedding.js'; import * as embedding from './embedding/embedding';
import * as posenet from './posenet/posenet.js'; import * as posenet from './posenet/posenet';
import * as handpose from './handpose/handpose.js'; import * as handpose from './handpose/handpose';
import * as gesture from './gesture/gesture.js'; import * as gesture from './gesture/gesture';
import * as image from './image.js'; import * as image from './image';
import * as profile from './profile.js'; import * as profile from './profile';
import * as config from '../config.js'; import * as config from '../config';
import * as sample from './sample.js'; import * as sample from './sample';
import * as app from '../package.json'; 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 // helper function: gets elapsed time on both browser and nodejs
const now = () => { const now = () => {
if (typeof performance !== 'undefined') return performance.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 // helper function: perform deep merge of multiple objects so it allows full inheriance with overrides
@ -42,6 +43,25 @@ function mergeDeep(...objects) {
} }
class Human { 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 = {}) { constructor(userConfig = {}) {
this.tf = tf; this.tf = tf;
this.version = app.version; this.version = app.version;
@ -108,7 +128,7 @@ class Human {
} }
// preload models, not explicitly required as it's done automatically on first use // preload models, not explicitly required as it's done automatically on first use
async load(userConfig) { async load(userConfig = null) {
this.state = 'load'; this.state = 'load';
const timeStamp = now(); const timeStamp = now();
if (userConfig) this.config = mergeDeep(this.config, userConfig); if (userConfig) this.config = mergeDeep(this.config, userConfig);
@ -160,7 +180,7 @@ class Human {
} }
// check if backend needs initialization if it changed // 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)) { if (this.config.backend && (this.config.backend !== '') && force || (tf.getBackend() !== this.config.backend)) {
const timeStamp = now(); const timeStamp = now();
this.state = 'backend'; this.state = 'backend';
@ -308,7 +328,7 @@ class Human {
emotion: emotionRes, emotion: emotionRes,
embedding: embeddingRes, embedding: embeddingRes,
iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0, iris: (irisSize !== 0) ? Math.trunc(irisSize) / 100 : 0,
image: face.image.toInt().squeeze(), // image: face.image.toInt().squeeze(),
}); });
// dont need face anymore // dont need face anymore
@ -487,7 +507,8 @@ class Human {
async warmupNode() { async warmupNode() {
const atob = (str) => Buffer.from(str, 'base64'); const atob = (str) => Buffer.from(str, 'base64');
const img = this.config.warmup === 'face' ? atob(sample.face) : atob(sample.body); 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); const expanded = data.expandDims(0);
tf.dispose(data); tf.dispose(data);
// log('Input:', expanded); // 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 tf from '../dist/tfjs.esm.js';
import * as fxImage from './imagefx.js'; import * as fxImage from './imagefx';
// internal temp canvases // internal temp canvases
let inCanvas = null; let inCanvas = null;
@ -9,7 +9,7 @@ let outCanvas = null;
// process input image and return tensor // process input image and return tensor
// input can be tensor, imagedata, htmlimageelement, htmlvideoelement // input can be tensor, imagedata, htmlimageelement, htmlvideoelement
// input is resized and run through imagefx filter // input is resized and run through imagefx filter
function process(input, config) { export function process(input, config) {
let tensor; let tensor;
if (input instanceof tf.Tensor) { if (input instanceof tf.Tensor) {
tensor = tf.clone(input); 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'); outCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(inCanvas.width, inCanvas.height) : document.createElement('canvas');
if (outCanvas.width !== inCanvas.width) outCanvas.width = inCanvas.width; if (outCanvas.width !== inCanvas.width) outCanvas.width = inCanvas.width;
if (outCanvas.height !== inCanvas.height) outCanvas.height = inCanvas.height; 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; if (!this.fx) return inCanvas;
this.fx.reset(); this.fx.reset();
@ -106,5 +106,3 @@ function process(input, config) {
} }
return { tensor, canvas: config.filter.return ? outCanvas : null }; 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> <https://github.com/phoboslab/WebGLImageFilter>
*/ */
const WebGLProgram = function (gl, vertexSource, fragmentSource) { const GLProgram = function (gl, vertexSource, fragmentSource) {
const _collect = function (source, prefix, collection) { const _collect = function (source, prefix, collection) {
const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig'); const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig');
source.replace(r, (match, name) => { 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 = { }; if (!params) params = { };
let _drawCount = 0; let _drawCount = 0;
let _sourceTexture = null; let _sourceTexture = null;
@ -180,7 +180,7 @@ const WebGLImageFilter = function (params) {
return { fbo, texture }; return { fbo, texture };
}; };
const _draw = function (flags) { const _draw = function (flags = null) {
let source = null; let source = null;
let target = null; let target = null;
let flipY = false; let flipY = false;
@ -225,7 +225,7 @@ const WebGLImageFilter = function (params) {
} }
// Compile shaders // 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 floatSize = Float32Array.BYTES_PER_ELEMENT;
const vertSize = 4 * floatSize; const vertSize = 4 * floatSize;
@ -606,4 +606,4 @@ const WebGLImageFilter = function (params) {
].join('\n'); ].join('\n');
}; };
exports.Canvas = WebGLImageFilter; exports.GLImageFilter = GLImageFilter;

View File

@ -1,6 +1,6 @@
const console = require('console'); const console = require('console');
const tf = require('@tensorflow/tfjs-node'); 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({ const logger = new console.Console({
stdout: process.stdout, stdout: process.stdout,

View File

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

View File

@ -7,7 +7,6 @@ const kLocalMaximumRadius = 1;
function withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, { x, y }, keypointId) { function withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, { x, y }, keypointId) {
return poses.some(({ keypoints }) => { return poses.some(({ keypoints }) => {
const correspondingKeypoint = keypoints[keypointId].position; const correspondingKeypoint = keypoints[keypointId].position;
// @ts-ignore
return vectors.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius; return vectors.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius;
}); });
} }
@ -20,9 +19,8 @@ function getInstanceScore(existingPoses, squaredNmsRadius, instanceKeypoints) {
return notOverlappedKeypointScores / instanceKeypoints.length; return notOverlappedKeypointScores / instanceKeypoints.length;
} }
function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config) { export function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config) {
const poses = []; const poses = [];
// @ts-ignore
const queue = buildParts.buildPartWithScoreQueue(config.body.scoreThreshold, kLocalMaximumRadius, scoresBuffer); const queue = buildParts.buildPartWithScoreQueue(config.body.scoreThreshold, kLocalMaximumRadius, scoresBuffer);
const squaredNmsRadius = config.body.nmsRadius ^ 2; const squaredNmsRadius = config.body.nmsRadius ^ 2;
// Generate at most maxDetections object instances per image in decreasing root part score order. // 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. // The top element in the queue is the next root candidate.
const root = queue.dequeue(); 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. // 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); const rootImageCoords = vectors.getImageCoords(root.part, config.body.outputStride, offsetsBuffer);
if (withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, rootImageCoords, root.part.id)) continue; if (withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, rootImageCoords, root.part.id)) continue;
// Else start a new detection instance at the position of the root. // 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 keypoints = decodePose.decodePose(root, scoresBuffer, offsetsBuffer, config.body.outputStride, displacementsFwdBuffer, displacementsBwdBuffer);
const score = getInstanceScore(poses, squaredNmsRadius, keypoints); const score = getInstanceScore(poses, squaredNmsRadius, keypoints);
if (score > config.body.scoreThreshold) poses.push({ keypoints, score }); if (score > config.body.scoreThreshold) poses.push({ keypoints, score });
} }
return poses; return poses;
} }
exports.decodeMultiplePoses = decodeMultiplePoses;

View File

@ -14,9 +14,7 @@ function getDisplacement(edgeId, point, displacements) {
} }
function getStridedIndexNearPoint(point, outputStride, height, width) { function getStridedIndexNearPoint(point, outputStride, height, width) {
return { return {
// @ts-ignore
y: vectors.clamp(Math.round(point.y / outputStride), 0, height - 1), y: vectors.clamp(Math.round(point.y / outputStride), 0, height - 1),
// @ts-ignore
x: vectors.clamp(Math.round(point.x / outputStride), 0, width - 1), 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. // Nearest neighbor interpolation for the source->target displacements.
const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width); const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width);
const displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements); const displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements);
// @ts-ignore
const displacedPoint = vectors.addVectors(sourceKeypoint.position, displacement); const displacedPoint = vectors.addVectors(sourceKeypoint.position, displacement);
let targetKeypoint = displacedPoint; let targetKeypoint = displacedPoint;
for (let i = 0; i < offsetRefineStep; i++) { for (let i = 0; i < offsetRefineStep; i++) {
const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width); const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
// @ts-ignore
const offsetPoint = vectors.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets); const offsetPoint = vectors.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
// @ts-ignore
targetKeypoint = vectors.addVectors({ targetKeypoint = vectors.addVectors({
x: targetKeypointIndices.x * outputStride, x: targetKeypointIndices.x * outputStride,
y: targetKeypointIndices.y * outputStride, y: targetKeypointIndices.y * outputStride,
@ -44,13 +39,12 @@ function traverseToTargetKeypoint(edgeId, sourceKeypoint, targetKeypointId, scor
return { position: targetKeypoint, part: keypoints.partNames[targetKeypointId], score }; 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 numParts = scores.shape[2];
const numEdges = parentToChildEdges.length; const numEdges = parentToChildEdges.length;
const instanceKeypoints = new Array(numParts); const instanceKeypoints = new Array(numParts);
// Start a new detection instance at the position of the root. // Start a new detection instance at the position of the root.
const { part: rootPart, score: rootScore } = root; const { part: rootPart, score: rootScore } = root;
// @ts-ignore
const rootPoint = vectors.getImageCoords(rootPart, outputStride, offsets); const rootPoint = vectors.getImageCoords(rootPart, outputStride, offsets);
instanceKeypoints[rootPart.id] = { instanceKeypoints[rootPart.id] = {
score: rootScore, score: rootScore,
@ -75,20 +69,16 @@ function decodePose(root, scores, offsets, outputStride, displacementsFwd, displ
} }
return instanceKeypoints; return instanceKeypoints;
} }
exports.decodePose = decodePose;
async function decodeSinglePose(heatmapScores, offsets, config) { export async function decodeSinglePose(heatmapScores, offsets, config) {
let totalScore = 0.0; let totalScore = 0.0;
// @ts-ignore
const heatmapValues = decoders.argmax2d(heatmapScores); const heatmapValues = decoders.argmax2d(heatmapScores);
const allTensorBuffers = await Promise.all([heatmapScores.buffer(), offsets.buffer(), heatmapValues.buffer()]); const allTensorBuffers = await Promise.all([heatmapScores.buffer(), offsets.buffer(), heatmapValues.buffer()]);
const scoresBuffer = allTensorBuffers[0]; const scoresBuffer = allTensorBuffers[0];
const offsetsBuffer = allTensorBuffers[1]; const offsetsBuffer = allTensorBuffers[1];
const heatmapValuesBuffer = allTensorBuffers[2]; const heatmapValuesBuffer = allTensorBuffers[2];
// @ts-ignore
const offsetPoints = decoders.getOffsetPoints(heatmapValuesBuffer, config.body.outputStride, offsetsBuffer); const offsetPoints = decoders.getOffsetPoints(heatmapValuesBuffer, config.body.outputStride, offsetsBuffer);
const offsetPointsBuffer = await offsetPoints.buffer(); const offsetPointsBuffer = await offsetPoints.buffer();
// @ts-ignore
const keypointConfidence = Array.from(decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer)); const keypointConfidence = Array.from(decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer));
const instanceKeypoints = keypointConfidence.map((score, i) => { const instanceKeypoints = keypointConfidence.map((score, i) => {
totalScore += score; totalScore += score;
@ -106,4 +96,3 @@ async function decodeSinglePose(heatmapScores, offsets, config) {
offsetPoints.dispose(); offsetPoints.dispose();
return { keypoints: filteredKeypoints, score: totalScore / instanceKeypoints.length }; 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 tf from '../../dist/tfjs.esm.js';
import * as kpt from './keypoints'; import * as kpt from './keypoints';
function getPointsConfidence(heatmapScores, heatMapCoords) { export function getPointsConfidence(heatmapScores, heatMapCoords) {
const numKeypoints = heatMapCoords.shape[0]; const numKeypoints = heatMapCoords.shape[0];
const result = new Float32Array(numKeypoints); const result = new Float32Array(numKeypoints);
for (let keypoint = 0; keypoint < numKeypoints; keypoint++) { for (let keypoint = 0; keypoint < numKeypoints; keypoint++) {
@ -11,7 +11,6 @@ function getPointsConfidence(heatmapScores, heatMapCoords) {
} }
return result; return result;
} }
exports.getPointsConfidence = getPointsConfidence;
function getOffsetPoint(y, x, keypoint, offsetsBuffer) { function getOffsetPoint(y, x, keypoint, offsetsBuffer) {
return { return {
@ -20,7 +19,7 @@ function getOffsetPoint(y, x, keypoint, offsetsBuffer) {
}; };
} }
function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) { export function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) {
const result = []; const result = [];
for (let keypoint = 0; keypoint < kpt.NUM_KEYPOINTS; keypoint++) { for (let keypoint = 0; keypoint < kpt.NUM_KEYPOINTS; keypoint++) {
const heatmapY = heatMapCoordsBuffer.get(keypoint, 0).valueOf(); const heatmapY = heatMapCoordsBuffer.get(keypoint, 0).valueOf();
@ -31,12 +30,10 @@ function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) {
} }
return tf.tensor2d(result, [kpt.NUM_KEYPOINTS, 2]); 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))); return tf.tidy(() => heatMapCoordsBuffer.toTensor().mul(tf.scalar(outputStride, 'int32')).toFloat().add(getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer)));
} }
exports.getOffsetPoints = getOffsetPoints;
function mod(a, b) { function mod(a, b) {
return tf.tidy(() => { return tf.tidy(() => {
@ -45,7 +42,7 @@ function mod(a, b) {
}); });
} }
function argmax2d(inputs) { export function argmax2d(inputs) {
const [height, width, depth] = inputs.shape; const [height, width, depth] = inputs.shape;
return tf.tidy(() => { return tf.tidy(() => {
const reshaped = inputs.reshape([height * width, depth]); const reshaped = inputs.reshape([height * width, depth]);
@ -55,4 +52,3 @@ function argmax2d(inputs) {
return tf.concat([yCoords, xCoords], 1); return tf.concat([yCoords, xCoords], 1);
}); });
} }
exports.argmax2d = argmax2d;

View File

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

View File

@ -1,12 +1,12 @@
exports.partNames = [ export const partNames = [
'nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder', 'nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder',
'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist', 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist',
'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle', '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; result[jointName] = i;
return result; return result;
}, {}); }, {});
@ -19,9 +19,9 @@ const connectedPartNames = [
['rightHip', 'rightKnee'], ['rightKnee', 'rightAnkle'], ['rightHip', 'rightKnee'], ['rightKnee', 'rightAnkle'],
['leftShoulder', 'rightShoulder'], ['leftHip', 'rightHip'], ['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'], ['nose', 'leftEye'], ['leftEye', 'leftEar'], ['nose', 'rightEye'],
['rightEye', 'rightEar'], ['nose', 'leftShoulder'], ['rightEye', 'rightEar'], ['nose', 'leftShoulder'],
['leftShoulder', 'leftElbow'], ['leftElbow', 'leftWrist'], ['leftShoulder', 'leftElbow'], ['leftElbow', 'leftWrist'],
@ -32,7 +32,7 @@ exports.poseChain = [
['rightKnee', 'rightAnkle'], ['rightKnee', 'rightAnkle'],
]; ];
exports.partChannels = [ export const partChannels = [
'left_face', 'left_face',
'right_face', 'right_face',
'right_upper_leg_front', 'right_upper_leg_front',

View File

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

View File

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

View File

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

View File

@ -1,14 +1,13 @@
import * as kpt from './keypoints'; import * as kpt from './keypoints';
function getOffsetPoint(y, x, keypoint, offsets) { export function getOffsetPoint(y, x, keypoint, offsets) {
return { return {
y: offsets.get(y, x, keypoint), y: offsets.get(y, x, keypoint),
x: offsets.get(y, x, keypoint + kpt.NUM_KEYPOINTS), 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 { heatmapY, heatmapX, id: keypoint } = part;
const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets); const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);
return { return {
@ -16,37 +15,31 @@ function getImageCoords(part, outputStride, offsets) {
y: part.heatmapY * outputStride + y, y: part.heatmapY * outputStride + y,
}; };
} }
exports.getImageCoords = getImageCoords;
function fillArray(element, size) { export function fillArray(element, size) {
const result = new Array(size); const result = new Array(size);
for (let i = 0; i < size; i++) { for (let i = 0; i < size; i++) {
result[i] = element; result[i] = element;
} }
return result; return result;
} }
exports.fillArray = fillArray;
function clamp(a, min, max) { export function clamp(a, min, max) {
if (a < min) return min; if (a < min) return min;
if (a > max) return max; if (a > max) return max;
return a; return a;
} }
exports.clamp = clamp;
function squaredDistance(y1, x1, y2, x2) { export function squaredDistance(y1, x1, y2, x2) {
const dy = y2 - y1; const dy = y2 - y1;
const dx = x2 - x1; const dx = x2 - x1;
return dy * dy + dx * dx; 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 }; 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) }; 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) { export function run(name, raw) {
if (!data || !data.kernels) return; if (!raw || !raw.kernels) return;
const maxResults = 5; const maxResults = 5;
const time = data.kernels const time = raw.kernels
.filter((a) => a.kernelTimeMs > 0) .filter((a) => a.kernelTimeMs > 0)
.reduce((a, b) => a += b.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; }) .map((a, i) => { a.id = i; return a; })
.filter((a) => a.kernelTimeMs > 0) .filter((a) => a.kernelTimeMs > 0)
.sort((a, b) => b.kernelTimeMs - a.kernelTimeMs); .sort((a, b) => b.kernelTimeMs - a.kernelTimeMs);
const largest = data.kernels const largest = raw.kernels
.map((a, i) => { a.id = i; return a; }) .map((a, i) => { a.id = i; return a; })
.filter((a) => a.totalBytesSnapshot > 0) .filter((a) => a.totalBytesSnapshot > 0)
.sort((a, b) => b.totalBytesSnapshot - a.totalBytesSnapshot); .sort((a, b) => b.totalBytesSnapshot - a.totalBytesSnapshot);
if (slowest.length > maxResults) slowest.length = maxResults; if (slowest.length > maxResults) slowest.length = maxResults;
if (largest.length > maxResults) largest.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 }; const res = { newBytes: raw.newBytes, newTensors: raw.newTensors, peakBytes: raw.peakBytes, numKernelOps: raw.kernels.length, timeKernelOps: time, slowestKernelOps: slowest, largestKernelOps: largest };
profileData[name] = res; data[name] = res;
log('Human profiler', 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'; import * as tf from '../../dist/tfjs.esm.js';
export const config = { export const config = {