mirror of https://github.com/vladmandic/human
work on blazepose
parent
77408fc2a7
commit
7396505391
10
config.js
10
config.js
|
@ -144,6 +144,16 @@ export default {
|
||||||
modelType: 'MobileNet', // Human includes MobileNet version, but you can switch to ResNet
|
modelType: 'MobileNet', // Human includes MobileNet version, but you can switch to ResNet
|
||||||
},
|
},
|
||||||
|
|
||||||
|
pose: {
|
||||||
|
enabled: false,
|
||||||
|
scoreThreshold: 0.6, // threshold for deciding when to remove boxes based on score
|
||||||
|
// in non-maximum suppression
|
||||||
|
iouThreshold: 0.3, // threshold for deciding whether boxes overlap too much
|
||||||
|
// in non-maximum suppression
|
||||||
|
modelPath: '../models/blazepose.json',
|
||||||
|
inputSize: 128, // fixed value
|
||||||
|
},
|
||||||
|
|
||||||
hand: {
|
hand: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
rotation: false, // use best-guess rotated hand image or just box with rotation as-is
|
rotation: false, // use best-guess rotated hand image or just box with rotation as-is
|
||||||
|
|
|
@ -4,11 +4,13 @@ import Menu from './menu.js';
|
||||||
import GLBench from './gl-bench.js';
|
import GLBench from './gl-bench.js';
|
||||||
|
|
||||||
const userConfig = {}; // add any user configuration overrides
|
const userConfig = {}; // add any user configuration overrides
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const userConfig = {
|
const userConfig = {
|
||||||
face: { enabled: true, iris: { enabled: false } },
|
face: { enabled: false, iris: { enabled: false } },
|
||||||
body: { enabled: true },
|
body: { enabled: false },
|
||||||
hand: { enabled: false },
|
hand: { enabled: false },
|
||||||
|
pose: { enabled: true },
|
||||||
};
|
};
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"dist/human.esm.js": {
|
"dist/human.esm.js": {
|
||||||
"bytes": 1905603,
|
"bytes": 1912580,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"demo/draw.js": {
|
"demo/draw.js": {
|
||||||
|
@ -17,7 +17,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"demo/browser.js": {
|
"demo/browser.js": {
|
||||||
"bytes": 25470,
|
"bytes": 25500,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/human.esm.js"
|
"path": "dist/human.esm.js"
|
||||||
|
@ -38,14 +38,14 @@
|
||||||
"dist/demo-browser-index.js.map": {
|
"dist/demo-browser-index.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 2025768
|
"bytes": 2040931
|
||||||
},
|
},
|
||||||
"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": 1898232
|
"bytesInOutput": 1905205
|
||||||
},
|
},
|
||||||
"demo/draw.js": {
|
"demo/draw.js": {
|
||||||
"bytesInOutput": 7736
|
"bytesInOutput": 7736
|
||||||
|
@ -60,7 +60,7 @@
|
||||||
"bytesInOutput": 19424
|
"bytesInOutput": 19424
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 1951936
|
"bytes": 1958909
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -16,7 +16,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/blazeface.js": {
|
"src/blazeface/blazeface.js": {
|
||||||
"bytes": 7024,
|
"bytes": 7024,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/box.js": {
|
"src/blazeface/box.js": {
|
||||||
"bytes": 1935,
|
"bytes": 1935,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -35,35 +35,35 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/util.js": {
|
"src/blazeface/util.js": {
|
||||||
"bytes": 3087,
|
"bytes": 3087,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/face/coords.js": {
|
"src/blazeface/coords.js": {
|
||||||
"bytes": 37915,
|
"bytes": 37915,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/face/facepipeline.js": {
|
"src/blazeface/facepipeline.js": {
|
||||||
"bytes": 14306,
|
"bytes": 14306,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/box.js"
|
"path": "src/blazeface/box.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/util.js"
|
"path": "src/blazeface/util.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/coords.js"
|
"path": "src/blazeface/coords.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/log.js"
|
"path": "src/log.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/facemesh.js": {
|
"src/blazeface/facemesh.js": {
|
||||||
"bytes": 2991,
|
"bytes": 2991,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -73,13 +73,13 @@
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/blazeface.js"
|
"path": "src/blazeface/blazeface.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/facepipeline.js"
|
"path": "src/blazeface/facepipeline.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/coords.js"
|
"path": "src/blazeface/coords.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -147,7 +147,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/modelBase.js": {
|
"src/posenet/modelBase.js": {
|
||||||
"bytes": 1343,
|
"bytes": 1343,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -155,78 +155,78 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/heapSort.js": {
|
"src/posenet/heapSort.js": {
|
||||||
"bytes": 1590,
|
"bytes": 1590,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/body/buildParts.js": {
|
"src/posenet/buildParts.js": {
|
||||||
"bytes": 1775,
|
"bytes": 1775,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/heapSort.js"
|
"path": "src/posenet/heapSort.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/keypoints.js": {
|
"src/posenet/keypoints.js": {
|
||||||
"bytes": 2011,
|
"bytes": 2011,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/body/vectors.js": {
|
"src/posenet/vectors.js": {
|
||||||
"bytes": 1273,
|
"bytes": 1273,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/decoders.js": {
|
"src/posenet/decoders.js": {
|
||||||
"bytes": 2083,
|
"bytes": 2083,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/decodePose.js": {
|
"src/posenet/decodePose.js": {
|
||||||
"bytes": 5368,
|
"bytes": 5368,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/vectors.js"
|
"path": "src/posenet/vectors.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decoders.js"
|
"path": "src/posenet/decoders.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/decodeMultiple.js": {
|
"src/posenet/decodeMultiple.js": {
|
||||||
"bytes": 2373,
|
"bytes": 2373,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/buildParts.js"
|
"path": "src/posenet/buildParts.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decodePose.js"
|
"path": "src/posenet/decodePose.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/vectors.js"
|
"path": "src/posenet/vectors.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/util.js": {
|
"src/posenet/util.js": {
|
||||||
"bytes": 2262,
|
"bytes": 2262,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/modelPoseNet.js": {
|
"src/posenet/modelPoseNet.js": {
|
||||||
"bytes": 2519,
|
"bytes": 2519,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -236,34 +236,45 @@
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/modelBase.js"
|
"path": "src/posenet/modelBase.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decodeMultiple.js"
|
"path": "src/posenet/decodeMultiple.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decodePose.js"
|
"path": "src/posenet/decodePose.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/util.js"
|
"path": "src/posenet/util.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/posenet.js": {
|
"src/posenet/posenet.js": {
|
||||||
"bytes": 712,
|
"bytes": 712,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/modelPoseNet.js"
|
"path": "src/posenet/modelPoseNet.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/util.js"
|
"path": "src/posenet/util.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/box.js": {
|
"src/blazepose/blazepose.js": {
|
||||||
|
"bytes": 8999,
|
||||||
|
"imports": [
|
||||||
|
{
|
||||||
|
"path": "src/log.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "dist/tfjs.esm.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"src/handpose/box.js": {
|
||||||
"bytes": 2522,
|
"bytes": 2522,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -271,43 +282,43 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/handdetector.js": {
|
"src/handpose/handdetector.js": {
|
||||||
"bytes": 3548,
|
"bytes": 3548,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/box.js"
|
"path": "src/handpose/box.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/util.js": {
|
"src/handpose/util.js": {
|
||||||
"bytes": 2346,
|
"bytes": 2346,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/handpipeline.js": {
|
"src/handpose/handpipeline.js": {
|
||||||
"bytes": 7246,
|
"bytes": 7246,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/box.js"
|
"path": "src/handpose/box.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/util.js"
|
"path": "src/handpose/util.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/log.js"
|
"path": "src/log.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/handpose/anchors.js": {
|
||||||
"bytes": 224151,
|
"bytes": 224151,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/handpose.js": {
|
"src/handpose/handpose.js": {
|
||||||
"bytes": 2578,
|
"bytes": 2578,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -317,13 +328,13 @@
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/handdetector.js"
|
"path": "src/handpose/handdetector.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/handpipeline.js"
|
"path": "src/handpose/handpipeline.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/anchors.js"
|
"path": "src/handpose/anchors.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -350,7 +361,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"config.js": {
|
"config.js": {
|
||||||
"bytes": 9644,
|
"bytes": 10062,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/sample.js": {
|
"src/sample.js": {
|
||||||
|
@ -362,7 +373,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 17544,
|
"bytes": 17787,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/log.js"
|
"path": "src/log.js"
|
||||||
|
@ -374,7 +385,7 @@
|
||||||
"path": "src/tfjs/backend.js"
|
"path": "src/tfjs/backend.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/facemesh.js"
|
"path": "src/blazeface/facemesh.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/age/age.js"
|
"path": "src/age/age.js"
|
||||||
|
@ -389,10 +400,13 @@
|
||||||
"path": "src/embedding/embedding.js"
|
"path": "src/embedding/embedding.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/posenet.js"
|
"path": "src/posenet/posenet.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/handpose.js"
|
"path": "src/blazepose/blazepose.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "src/handpose/handpose.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/gesture/gesture.js"
|
"path": "src/gesture/gesture.js"
|
||||||
|
@ -419,7 +433,7 @@
|
||||||
"dist/human.esm.js.map": {
|
"dist/human.esm.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 1930371
|
"bytes": 1945558
|
||||||
},
|
},
|
||||||
"dist/human.esm.js": {
|
"dist/human.esm.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
|
@ -427,83 +441,83 @@
|
||||||
"default"
|
"default"
|
||||||
],
|
],
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"src/face/blazeface.js": {
|
"src/blazeface/blazeface.js": {
|
||||||
"bytesInOutput": 5039
|
"bytesInOutput": 5046
|
||||||
},
|
},
|
||||||
"src/face/box.js": {
|
"src/blazeface/box.js": {
|
||||||
"bytesInOutput": 1567
|
"bytesInOutput": 1567
|
||||||
},
|
},
|
||||||
"src/face/util.js": {
|
"src/blazeface/util.js": {
|
||||||
"bytesInOutput": 2418
|
"bytesInOutput": 2418
|
||||||
},
|
},
|
||||||
"src/face/coords.js": {
|
"src/blazeface/coords.js": {
|
||||||
"bytesInOutput": 30718
|
"bytesInOutput": 30718
|
||||||
},
|
},
|
||||||
"src/face/facepipeline.js": {
|
"src/blazeface/facepipeline.js": {
|
||||||
"bytesInOutput": 9386
|
"bytesInOutput": 9386
|
||||||
},
|
},
|
||||||
"src/face/facemesh.js": {
|
"src/blazeface/facemesh.js": {
|
||||||
"bytesInOutput": 2322
|
"bytesInOutput": 2322
|
||||||
},
|
},
|
||||||
"src/profile.js": {
|
"src/profile.js": {
|
||||||
"bytesInOutput": 851
|
"bytesInOutput": 851
|
||||||
},
|
},
|
||||||
"src/age/age.js": {
|
"src/age/age.js": {
|
||||||
"bytesInOutput": 1186
|
"bytesInOutput": 1193
|
||||||
},
|
},
|
||||||
"src/gender/gender.js": {
|
"src/gender/gender.js": {
|
||||||
"bytesInOutput": 1914
|
"bytesInOutput": 1922
|
||||||
},
|
},
|
||||||
"src/emotion/emotion.js": {
|
"src/emotion/emotion.js": {
|
||||||
"bytesInOutput": 1813
|
"bytesInOutput": 1820
|
||||||
},
|
},
|
||||||
"src/embedding/embedding.js": {
|
"src/embedding/embedding.js": {
|
||||||
"bytesInOutput": 1323
|
"bytesInOutput": 1330
|
||||||
},
|
},
|
||||||
"src/body/modelBase.js": {
|
"src/posenet/modelBase.js": {
|
||||||
"bytesInOutput": 1055
|
"bytesInOutput": 1055
|
||||||
},
|
},
|
||||||
"src/body/heapSort.js": {
|
"src/posenet/heapSort.js": {
|
||||||
"bytesInOutput": 1144
|
"bytesInOutput": 1144
|
||||||
},
|
},
|
||||||
"src/body/buildParts.js": {
|
"src/posenet/buildParts.js": {
|
||||||
"bytesInOutput": 1287
|
"bytesInOutput": 1287
|
||||||
},
|
},
|
||||||
"src/body/keypoints.js": {
|
"src/posenet/keypoints.js": {
|
||||||
"bytesInOutput": 1813
|
"bytesInOutput": 1813
|
||||||
},
|
},
|
||||||
"src/body/vectors.js": {
|
"src/posenet/vectors.js": {
|
||||||
"bytesInOutput": 1055
|
"bytesInOutput": 1055
|
||||||
},
|
},
|
||||||
"src/body/decoders.js": {
|
"src/posenet/decoders.js": {
|
||||||
"bytesInOutput": 1709
|
"bytesInOutput": 1709
|
||||||
},
|
},
|
||||||
"src/body/decodePose.js": {
|
"src/posenet/decodePose.js": {
|
||||||
"bytesInOutput": 4098
|
"bytesInOutput": 4098
|
||||||
},
|
},
|
||||||
"src/body/decodeMultiple.js": {
|
"src/posenet/decodeMultiple.js": {
|
||||||
"bytesInOutput": 1643
|
"bytesInOutput": 1643
|
||||||
},
|
},
|
||||||
"src/body/util.js": {
|
"src/posenet/util.js": {
|
||||||
"bytesInOutput": 1892
|
"bytesInOutput": 1892
|
||||||
},
|
},
|
||||||
"src/body/modelPoseNet.js": {
|
"src/posenet/modelPoseNet.js": {
|
||||||
"bytesInOutput": 1997
|
"bytesInOutput": 1997
|
||||||
},
|
},
|
||||||
"src/body/posenet.js": {
|
"src/posenet/posenet.js": {
|
||||||
"bytesInOutput": 627
|
"bytesInOutput": 627
|
||||||
},
|
},
|
||||||
"src/hand/handdetector.js": {
|
"src/handpose/handdetector.js": {
|
||||||
"bytesInOutput": 2747
|
"bytesInOutput": 2747
|
||||||
},
|
},
|
||||||
"src/hand/handpipeline.js": {
|
"src/handpose/handpipeline.js": {
|
||||||
"bytesInOutput": 4484
|
"bytesInOutput": 4484
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/handpose/anchors.js": {
|
||||||
"bytesInOutput": 127037
|
"bytesInOutput": 127037
|
||||||
},
|
},
|
||||||
"src/hand/handpose.js": {
|
"src/handpose/handpose.js": {
|
||||||
"bytesInOutput": 2023
|
"bytesInOutput": 2025
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytesInOutput": 3162
|
"bytesInOutput": 3162
|
||||||
|
@ -524,16 +538,19 @@
|
||||||
"bytesInOutput": 918
|
"bytesInOutput": 918
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 11286
|
"bytesInOutput": 11921
|
||||||
},
|
},
|
||||||
"src/hand/box.js": {
|
"src/blazepose/blazepose.js": {
|
||||||
|
"bytesInOutput": 6201
|
||||||
|
},
|
||||||
|
"src/handpose/box.js": {
|
||||||
"bytesInOutput": 1420
|
"bytesInOutput": 1420
|
||||||
},
|
},
|
||||||
"src/hand/util.js": {
|
"src/handpose/util.js": {
|
||||||
"bytesInOutput": 1796
|
"bytesInOutput": 1796
|
||||||
},
|
},
|
||||||
"config.js": {
|
"config.js": {
|
||||||
"bytesInOutput": 1514
|
"bytesInOutput": 1617
|
||||||
},
|
},
|
||||||
"src/sample.js": {
|
"src/sample.js": {
|
||||||
"bytesInOutput": 55299
|
"bytesInOutput": 55299
|
||||||
|
@ -542,7 +559,7 @@
|
||||||
"bytesInOutput": 23
|
"bytesInOutput": 23
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 1905603
|
"bytes": 1912580
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -16,7 +16,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/blazeface.js": {
|
"src/blazeface/blazeface.js": {
|
||||||
"bytes": 7024,
|
"bytes": 7024,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -27,7 +27,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/box.js": {
|
"src/blazeface/box.js": {
|
||||||
"bytes": 1935,
|
"bytes": 1935,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -35,35 +35,35 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/util.js": {
|
"src/blazeface/util.js": {
|
||||||
"bytes": 3087,
|
"bytes": 3087,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/face/coords.js": {
|
"src/blazeface/coords.js": {
|
||||||
"bytes": 37915,
|
"bytes": 37915,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/face/facepipeline.js": {
|
"src/blazeface/facepipeline.js": {
|
||||||
"bytes": 14306,
|
"bytes": 14306,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/box.js"
|
"path": "src/blazeface/box.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/util.js"
|
"path": "src/blazeface/util.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/coords.js"
|
"path": "src/blazeface/coords.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/log.js"
|
"path": "src/log.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/face/facemesh.js": {
|
"src/blazeface/facemesh.js": {
|
||||||
"bytes": 2991,
|
"bytes": 2991,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -73,13 +73,13 @@
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/blazeface.js"
|
"path": "src/blazeface/blazeface.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/facepipeline.js"
|
"path": "src/blazeface/facepipeline.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/coords.js"
|
"path": "src/blazeface/coords.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -147,7 +147,7 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/modelBase.js": {
|
"src/posenet/modelBase.js": {
|
||||||
"bytes": 1343,
|
"bytes": 1343,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -155,78 +155,78 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/heapSort.js": {
|
"src/posenet/heapSort.js": {
|
||||||
"bytes": 1590,
|
"bytes": 1590,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/body/buildParts.js": {
|
"src/posenet/buildParts.js": {
|
||||||
"bytes": 1775,
|
"bytes": 1775,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/heapSort.js"
|
"path": "src/posenet/heapSort.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/keypoints.js": {
|
"src/posenet/keypoints.js": {
|
||||||
"bytes": 2011,
|
"bytes": 2011,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/body/vectors.js": {
|
"src/posenet/vectors.js": {
|
||||||
"bytes": 1273,
|
"bytes": 1273,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/decoders.js": {
|
"src/posenet/decoders.js": {
|
||||||
"bytes": 2083,
|
"bytes": 2083,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/decodePose.js": {
|
"src/posenet/decodePose.js": {
|
||||||
"bytes": 5368,
|
"bytes": 5368,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/vectors.js"
|
"path": "src/posenet/vectors.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decoders.js"
|
"path": "src/posenet/decoders.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/decodeMultiple.js": {
|
"src/posenet/decodeMultiple.js": {
|
||||||
"bytes": 2373,
|
"bytes": 2373,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/buildParts.js"
|
"path": "src/posenet/buildParts.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decodePose.js"
|
"path": "src/posenet/decodePose.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/vectors.js"
|
"path": "src/posenet/vectors.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/util.js": {
|
"src/posenet/util.js": {
|
||||||
"bytes": 2262,
|
"bytes": 2262,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/modelPoseNet.js": {
|
"src/posenet/modelPoseNet.js": {
|
||||||
"bytes": 2519,
|
"bytes": 2519,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -236,34 +236,45 @@
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/modelBase.js"
|
"path": "src/posenet/modelBase.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decodeMultiple.js"
|
"path": "src/posenet/decodeMultiple.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/decodePose.js"
|
"path": "src/posenet/decodePose.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/util.js"
|
"path": "src/posenet/util.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/body/posenet.js": {
|
"src/posenet/posenet.js": {
|
||||||
"bytes": 712,
|
"bytes": 712,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/body/modelPoseNet.js"
|
"path": "src/posenet/modelPoseNet.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/keypoints.js"
|
"path": "src/posenet/keypoints.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/util.js"
|
"path": "src/posenet/util.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/box.js": {
|
"src/blazepose/blazepose.js": {
|
||||||
|
"bytes": 8999,
|
||||||
|
"imports": [
|
||||||
|
{
|
||||||
|
"path": "src/log.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "dist/tfjs.esm.js"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"src/handpose/box.js": {
|
||||||
"bytes": 2522,
|
"bytes": 2522,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -271,43 +282,43 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/handdetector.js": {
|
"src/handpose/handdetector.js": {
|
||||||
"bytes": 3548,
|
"bytes": 3548,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/box.js"
|
"path": "src/handpose/box.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/util.js": {
|
"src/handpose/util.js": {
|
||||||
"bytes": 2346,
|
"bytes": 2346,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/handpipeline.js": {
|
"src/handpose/handpipeline.js": {
|
||||||
"bytes": 7246,
|
"bytes": 7246,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/box.js"
|
"path": "src/handpose/box.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/util.js"
|
"path": "src/handpose/util.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/log.js"
|
"path": "src/log.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/handpose/anchors.js": {
|
||||||
"bytes": 224151,
|
"bytes": 224151,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/hand/handpose.js": {
|
"src/handpose/handpose.js": {
|
||||||
"bytes": 2578,
|
"bytes": 2578,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
|
@ -317,13 +328,13 @@
|
||||||
"path": "dist/tfjs.esm.js"
|
"path": "dist/tfjs.esm.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/handdetector.js"
|
"path": "src/handpose/handdetector.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/handpipeline.js"
|
"path": "src/handpose/handpipeline.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/anchors.js"
|
"path": "src/handpose/anchors.js"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -350,7 +361,7 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"config.js": {
|
"config.js": {
|
||||||
"bytes": 9644,
|
"bytes": 10062,
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/sample.js": {
|
"src/sample.js": {
|
||||||
|
@ -362,7 +373,7 @@
|
||||||
"imports": []
|
"imports": []
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytes": 17544,
|
"bytes": 17787,
|
||||||
"imports": [
|
"imports": [
|
||||||
{
|
{
|
||||||
"path": "src/log.js"
|
"path": "src/log.js"
|
||||||
|
@ -374,7 +385,7 @@
|
||||||
"path": "src/tfjs/backend.js"
|
"path": "src/tfjs/backend.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/face/facemesh.js"
|
"path": "src/blazeface/facemesh.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/age/age.js"
|
"path": "src/age/age.js"
|
||||||
|
@ -389,10 +400,13 @@
|
||||||
"path": "src/embedding/embedding.js"
|
"path": "src/embedding/embedding.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/body/posenet.js"
|
"path": "src/posenet/posenet.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/hand/handpose.js"
|
"path": "src/blazepose/blazepose.js"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "src/handpose/handpose.js"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"path": "src/gesture/gesture.js"
|
"path": "src/gesture/gesture.js"
|
||||||
|
@ -419,89 +433,89 @@
|
||||||
"dist/human.js.map": {
|
"dist/human.js.map": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"inputs": {},
|
"inputs": {},
|
||||||
"bytes": 1930388
|
"bytes": 1945575
|
||||||
},
|
},
|
||||||
"dist/human.js": {
|
"dist/human.js": {
|
||||||
"imports": [],
|
"imports": [],
|
||||||
"exports": [],
|
"exports": [],
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"src/face/blazeface.js": {
|
"src/blazeface/blazeface.js": {
|
||||||
"bytesInOutput": 5039
|
"bytesInOutput": 5046
|
||||||
},
|
},
|
||||||
"src/face/box.js": {
|
"src/blazeface/box.js": {
|
||||||
"bytesInOutput": 1567
|
"bytesInOutput": 1567
|
||||||
},
|
},
|
||||||
"src/face/util.js": {
|
"src/blazeface/util.js": {
|
||||||
"bytesInOutput": 2418
|
"bytesInOutput": 2418
|
||||||
},
|
},
|
||||||
"src/face/coords.js": {
|
"src/blazeface/coords.js": {
|
||||||
"bytesInOutput": 30718
|
"bytesInOutput": 30718
|
||||||
},
|
},
|
||||||
"src/face/facepipeline.js": {
|
"src/blazeface/facepipeline.js": {
|
||||||
"bytesInOutput": 9386
|
"bytesInOutput": 9386
|
||||||
},
|
},
|
||||||
"src/face/facemesh.js": {
|
"src/blazeface/facemesh.js": {
|
||||||
"bytesInOutput": 2322
|
"bytesInOutput": 2322
|
||||||
},
|
},
|
||||||
"src/profile.js": {
|
"src/profile.js": {
|
||||||
"bytesInOutput": 851
|
"bytesInOutput": 851
|
||||||
},
|
},
|
||||||
"src/age/age.js": {
|
"src/age/age.js": {
|
||||||
"bytesInOutput": 1186
|
"bytesInOutput": 1193
|
||||||
},
|
},
|
||||||
"src/gender/gender.js": {
|
"src/gender/gender.js": {
|
||||||
"bytesInOutput": 1914
|
"bytesInOutput": 1922
|
||||||
},
|
},
|
||||||
"src/emotion/emotion.js": {
|
"src/emotion/emotion.js": {
|
||||||
"bytesInOutput": 1813
|
"bytesInOutput": 1820
|
||||||
},
|
},
|
||||||
"src/embedding/embedding.js": {
|
"src/embedding/embedding.js": {
|
||||||
"bytesInOutput": 1323
|
"bytesInOutput": 1330
|
||||||
},
|
},
|
||||||
"src/body/modelBase.js": {
|
"src/posenet/modelBase.js": {
|
||||||
"bytesInOutput": 1055
|
"bytesInOutput": 1055
|
||||||
},
|
},
|
||||||
"src/body/heapSort.js": {
|
"src/posenet/heapSort.js": {
|
||||||
"bytesInOutput": 1144
|
"bytesInOutput": 1144
|
||||||
},
|
},
|
||||||
"src/body/buildParts.js": {
|
"src/posenet/buildParts.js": {
|
||||||
"bytesInOutput": 1287
|
"bytesInOutput": 1287
|
||||||
},
|
},
|
||||||
"src/body/keypoints.js": {
|
"src/posenet/keypoints.js": {
|
||||||
"bytesInOutput": 1813
|
"bytesInOutput": 1813
|
||||||
},
|
},
|
||||||
"src/body/vectors.js": {
|
"src/posenet/vectors.js": {
|
||||||
"bytesInOutput": 1055
|
"bytesInOutput": 1055
|
||||||
},
|
},
|
||||||
"src/body/decoders.js": {
|
"src/posenet/decoders.js": {
|
||||||
"bytesInOutput": 1709
|
"bytesInOutput": 1709
|
||||||
},
|
},
|
||||||
"src/body/decodePose.js": {
|
"src/posenet/decodePose.js": {
|
||||||
"bytesInOutput": 4098
|
"bytesInOutput": 4098
|
||||||
},
|
},
|
||||||
"src/body/decodeMultiple.js": {
|
"src/posenet/decodeMultiple.js": {
|
||||||
"bytesInOutput": 1643
|
"bytesInOutput": 1643
|
||||||
},
|
},
|
||||||
"src/body/util.js": {
|
"src/posenet/util.js": {
|
||||||
"bytesInOutput": 1892
|
"bytesInOutput": 1892
|
||||||
},
|
},
|
||||||
"src/body/modelPoseNet.js": {
|
"src/posenet/modelPoseNet.js": {
|
||||||
"bytesInOutput": 1997
|
"bytesInOutput": 1997
|
||||||
},
|
},
|
||||||
"src/body/posenet.js": {
|
"src/posenet/posenet.js": {
|
||||||
"bytesInOutput": 627
|
"bytesInOutput": 627
|
||||||
},
|
},
|
||||||
"src/hand/handdetector.js": {
|
"src/handpose/handdetector.js": {
|
||||||
"bytesInOutput": 2747
|
"bytesInOutput": 2747
|
||||||
},
|
},
|
||||||
"src/hand/handpipeline.js": {
|
"src/handpose/handpipeline.js": {
|
||||||
"bytesInOutput": 4484
|
"bytesInOutput": 4484
|
||||||
},
|
},
|
||||||
"src/hand/anchors.js": {
|
"src/handpose/anchors.js": {
|
||||||
"bytesInOutput": 127037
|
"bytesInOutput": 127037
|
||||||
},
|
},
|
||||||
"src/hand/handpose.js": {
|
"src/handpose/handpose.js": {
|
||||||
"bytesInOutput": 2023
|
"bytesInOutput": 2025
|
||||||
},
|
},
|
||||||
"src/gesture/gesture.js": {
|
"src/gesture/gesture.js": {
|
||||||
"bytesInOutput": 3162
|
"bytesInOutput": 3162
|
||||||
|
@ -513,7 +527,7 @@
|
||||||
"bytesInOutput": 3652
|
"bytesInOutput": 3652
|
||||||
},
|
},
|
||||||
"src/human.js": {
|
"src/human.js": {
|
||||||
"bytesInOutput": 11351
|
"bytesInOutput": 11986
|
||||||
},
|
},
|
||||||
"src/log.js": {
|
"src/log.js": {
|
||||||
"bytesInOutput": 266
|
"bytesInOutput": 266
|
||||||
|
@ -524,14 +538,17 @@
|
||||||
"src/tfjs/backend.js": {
|
"src/tfjs/backend.js": {
|
||||||
"bytesInOutput": 918
|
"bytesInOutput": 918
|
||||||
},
|
},
|
||||||
"src/hand/box.js": {
|
"src/blazepose/blazepose.js": {
|
||||||
|
"bytesInOutput": 6201
|
||||||
|
},
|
||||||
|
"src/handpose/box.js": {
|
||||||
"bytesInOutput": 1420
|
"bytesInOutput": 1420
|
||||||
},
|
},
|
||||||
"src/hand/util.js": {
|
"src/handpose/util.js": {
|
||||||
"bytesInOutput": 1796
|
"bytesInOutput": 1796
|
||||||
},
|
},
|
||||||
"config.js": {
|
"config.js": {
|
||||||
"bytesInOutput": 1514
|
"bytesInOutput": 1617
|
||||||
},
|
},
|
||||||
"src/sample.js": {
|
"src/sample.js": {
|
||||||
"bytesInOutput": 55299
|
"bytesInOutput": 55299
|
||||||
|
@ -540,7 +557,7 @@
|
||||||
"bytesInOutput": 23
|
"bytesInOutput": 23
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"bytes": 1905681
|
"bytes": 1912658
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,214 @@
|
||||||
|
import { log } from '../log.js';
|
||||||
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
|
// import * as helpers from './helpers.js';
|
||||||
|
// import * as profile from '../profile.js';
|
||||||
|
|
||||||
|
const models = {};
|
||||||
|
let config = {};
|
||||||
|
const anchors = [];
|
||||||
|
const kMidHipCenter = 0;
|
||||||
|
const kPoseDetectKeyNum = 2;
|
||||||
|
const kFullBodySizeRot = 1;
|
||||||
|
|
||||||
|
function calculateScale(min_scale, max_scale, stride_index, num_strides) {
|
||||||
|
if (num_strides === 1) return (min_scale + max_scale) * 0.5;
|
||||||
|
return min_scale + (max_scale - min_scale) * 1.0 * stride_index / (num_strides - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function generateAnchors() {
|
||||||
|
const options = {};
|
||||||
|
options.strides = [];
|
||||||
|
options.aspect_ratios = [];
|
||||||
|
options.feature_map_height = [];
|
||||||
|
options.num_layers = 4;
|
||||||
|
options.min_scale = 0.1484375;
|
||||||
|
options.max_scale = 0.75;
|
||||||
|
options.input_size_height = 128;
|
||||||
|
options.input_size_width = 128;
|
||||||
|
options.anchor_offset_x = 0.5;
|
||||||
|
options.anchor_offset_y = 0.5;
|
||||||
|
options.strides.push(8);
|
||||||
|
options.strides.push(16);
|
||||||
|
options.strides.push(16);
|
||||||
|
options.strides.push(16);
|
||||||
|
options.aspect_ratios.push(1.0);
|
||||||
|
options.reduce_boxes_in_lowest_layer = false;
|
||||||
|
options.interpolated_scale_aspect_ratio = 1.0;
|
||||||
|
options.fixed_anchor_size = true;
|
||||||
|
let layer_id = 0;
|
||||||
|
while (layer_id < options.strides.length) {
|
||||||
|
const anchor_height = [];
|
||||||
|
const anchor_width = [];
|
||||||
|
const aspect_ratios = [];
|
||||||
|
const scales = [];
|
||||||
|
// For same strides, we merge the anchors in the same order.
|
||||||
|
let last_same_stride_layer = layer_id;
|
||||||
|
while (last_same_stride_layer < options.strides.length && options.strides[last_same_stride_layer] === options.strides[layer_id]) {
|
||||||
|
const scale = calculateScale(options.min_scale, options.max_scale, last_same_stride_layer, options.strides.length);
|
||||||
|
if (last_same_stride_layer === 0 && options.reduce_boxes_in_lowest_layer) {
|
||||||
|
// For first layer, it can be specified to use predefined anchors.
|
||||||
|
aspect_ratios.push(1.0);
|
||||||
|
aspect_ratios.push(2.0);
|
||||||
|
aspect_ratios.push(0.5);
|
||||||
|
scales.push(0.1);
|
||||||
|
scales.push(scale);
|
||||||
|
scales.push(scale);
|
||||||
|
} else {
|
||||||
|
for (let aspect_ratio_id = 0; aspect_ratio_id < options.aspect_ratios.length; ++aspect_ratio_id) {
|
||||||
|
aspect_ratios.push(options.aspect_ratios[aspect_ratio_id]);
|
||||||
|
scales.push(scale);
|
||||||
|
}
|
||||||
|
if (options.interpolated_scale_aspect_ratio > 0.0) {
|
||||||
|
const scale_next = last_same_stride_layer === options.strides.length - 1 ? 1.0 : calculateScale(options.min_scale, options.max_scale, last_same_stride_layer + 1, options.strides.length);
|
||||||
|
scales.push(Math.sqrt(scale * scale_next));
|
||||||
|
aspect_ratios.push(options.interpolated_scale_aspect_ratio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_same_stride_layer++;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < aspect_ratios.length; ++i) {
|
||||||
|
const ratio_sqrts = Math.sqrt(aspect_ratios[i]);
|
||||||
|
anchor_height.push(scales[i] / ratio_sqrts);
|
||||||
|
anchor_width.push(scales[i] * ratio_sqrts);
|
||||||
|
}
|
||||||
|
let feature_map_height = 0;
|
||||||
|
let feature_map_width = 0;
|
||||||
|
if (options.feature_map_height.length) {
|
||||||
|
feature_map_height = options.feature_map_height[layer_id];
|
||||||
|
feature_map_width = options.feature_map_width[layer_id];
|
||||||
|
} else {
|
||||||
|
const stride = options.strides[layer_id];
|
||||||
|
feature_map_height = Math.ceil(1.0 * options.input_size_height / stride);
|
||||||
|
feature_map_width = Math.ceil(1.0 * options.input_size_width / stride);
|
||||||
|
}
|
||||||
|
for (let y = 0; y < feature_map_height; ++y) {
|
||||||
|
for (let x = 0; x < feature_map_width; ++x) {
|
||||||
|
for (let anchor_id = 0; anchor_id < anchor_height.length; ++anchor_id) {
|
||||||
|
const x_center = (x + options.anchor_offset_x) * 1.0 / feature_map_width;
|
||||||
|
const y_center = (y + options.anchor_offset_y) * 1.0 / feature_map_height;
|
||||||
|
const new_anchor = {};
|
||||||
|
new_anchor.x_center = x_center;
|
||||||
|
new_anchor.y_center = y_center;
|
||||||
|
if (options.fixed_anchor_size) {
|
||||||
|
new_anchor.w = 1.0;
|
||||||
|
new_anchor.h = 1.0;
|
||||||
|
} else {
|
||||||
|
new_anchor.w = anchor_width[anchor_id];
|
||||||
|
new_anchor.h = anchor_height[anchor_id];
|
||||||
|
}
|
||||||
|
anchors.push(new_anchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer_id = last_same_stride_layer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function load(cfg) {
|
||||||
|
config = cfg;
|
||||||
|
if (!models.blazepose) {
|
||||||
|
models.blazepose = await tf.loadGraphModel(config.pose.modelPath);
|
||||||
|
log(`load model: ${config.pose.modelPath.match(/\/(.*)\./)[1]}`);
|
||||||
|
}
|
||||||
|
generateAnchors();
|
||||||
|
return models.blazepose;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateRegion(region) {
|
||||||
|
const x0 = region.keys[kMidHipCenter].x;
|
||||||
|
const y0 = region.keys[kMidHipCenter].y;
|
||||||
|
const x1 = (region.box[0] + region.box[2]) * 0.5;
|
||||||
|
const y1 = (region.box[1] + region.box[3]) * 0.5;
|
||||||
|
const target_angle = Math.PI * 0.5;
|
||||||
|
const angle = target_angle - Math.atan2(-(y1 - y0), x1 - x0);
|
||||||
|
return Math.round(1000 * (angle - 2 * Math.PI * Math.floor((angle - (-Math.PI)) / (2 * Math.PI)))) / 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
function rotateVecor(vec, rotation) {
|
||||||
|
const sx = vec.x;
|
||||||
|
const sy = vec.y;
|
||||||
|
vec.x = sx * Math.cos(rotation) - sy * Math.sin(rotation);
|
||||||
|
vec.y = sx * Math.sin(rotation) + sy * Math.cos(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function decode(logits) {
|
||||||
|
const scores = await logits[0].data();
|
||||||
|
const boxes = await logits[1].data();
|
||||||
|
// todo: add nms
|
||||||
|
// todo scale output with image.shape
|
||||||
|
const regions = [];
|
||||||
|
for (let i = 0; i < anchors.length; i++) {
|
||||||
|
const region = {};
|
||||||
|
const score = 1.0 / (1.0 + Math.exp(-scores[i]));
|
||||||
|
if (score > config.pose.scoreThreshold) {
|
||||||
|
const idx = (4 + 2 * kPoseDetectKeyNum) * i;
|
||||||
|
/* boundary box */
|
||||||
|
const sx = boxes[idx + 0];
|
||||||
|
const sy = boxes[idx + 1];
|
||||||
|
const w = boxes[idx + 2] / config.pose.inputSize;
|
||||||
|
const h = boxes[idx + 3] / config.pose.inputSize;
|
||||||
|
const cx = (sx + anchors[i].x_center * config.pose.inputSize) / config.pose.inputSize;
|
||||||
|
const cy = (sy + anchors[i].y_center * config.pose.inputSize) / config.pose.inputSize;
|
||||||
|
region.score = Math.round(1000 * score) / 1000;
|
||||||
|
region.box = [cx - w * 0.5, cy - h * 0.5, w * 0.5, h * 0.5];
|
||||||
|
/* landmark positions (6 keys) */
|
||||||
|
const keys = new Array(kPoseDetectKeyNum);
|
||||||
|
for (let j = 0; j < kPoseDetectKeyNum; j++) {
|
||||||
|
const lx = (boxes[idx + 4 + (2 * j) + 0] + anchors[i].x_center * config.pose.inputSize) / config.pose.inputSize;
|
||||||
|
const ly = (boxes[idx + 4 + (2 * j) + 1] + anchors[i].y_center * config.pose.inputSize) / config.pose.inputSize;
|
||||||
|
keys[j] = { x: lx, y: ly };
|
||||||
|
}
|
||||||
|
region.keys = keys;
|
||||||
|
region.angle = rotateRegion(region);
|
||||||
|
// add points
|
||||||
|
const x_center = region.keys[kMidHipCenter].x * config.pose.inputSize;
|
||||||
|
const y_center = region.keys[kMidHipCenter].y * config.pose.inputSize;
|
||||||
|
const x_scale = region.keys[kFullBodySizeRot].x * config.pose.inputSize;
|
||||||
|
const y_scale = region.keys[kFullBodySizeRot].y * config.pose.inputSize;
|
||||||
|
// Bounding box size as double distance from center to scale point.
|
||||||
|
const box_size = Math.sqrt((x_scale - x_center) * (x_scale - x_center) + (y_scale - y_center) * (y_scale - y_center)) * 2.0;
|
||||||
|
/* RectTransformationCalculator::TransformNormalizedRect() */
|
||||||
|
const roi_cx = region.angle === 0.0 ? x_center + box_size : x_center + box_size * Math.cos(region.angle) - box_size * Math.sin(region.angle);
|
||||||
|
const roi_cy = region.angle === 0.0 ? y_center + box_size : y_center + box_size * Math.sin(region.angle) + box_size * Math.cos(region.angle);
|
||||||
|
const long_side = Math.max(box_size, box_size);
|
||||||
|
const roi_w = long_side * 1.5;
|
||||||
|
const roi_h = long_side * 1.5;
|
||||||
|
region.center = { x: roi_cx / config.pose.inputSize, y: roi_cy / config.pose.inputSize };
|
||||||
|
region.size = { x: roi_w / config.pose.inputSize, y: roi_h / config.pose.inputSize };
|
||||||
|
/* calculate ROI coordinates */
|
||||||
|
const dx = roi_w * 0.5;
|
||||||
|
const dy = roi_h * 0.5;
|
||||||
|
region.coords = [];
|
||||||
|
region.coords[0] = { x: -dx, y: -dy };
|
||||||
|
region.coords[1] = { x: +dx, y: -dy };
|
||||||
|
region.coords[2] = { x: +dx, y: +dy };
|
||||||
|
region.coords[3] = { x: -dx, y: +dy };
|
||||||
|
for (let j = 0; j < 4; j++) {
|
||||||
|
rotateVecor(region.coords[i], region.angle);
|
||||||
|
region.coords[j].x = (region.coords[j].x + roi_cx) / config.pose.inputSize;
|
||||||
|
region.coords[j].y = (region.coords[j].y + roi_cy) / config.pose.inputSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
regions.push(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return regions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function predict(image, cfg) {
|
||||||
|
if (!models.blazepose) return null;
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
config = cfg;
|
||||||
|
const resize = tf.image.resizeBilinear(image, [config.pose.inputSize, config.pose.inputSize], false);
|
||||||
|
const enhance = tf.div(resize, 127.5).sub(1);
|
||||||
|
tf.dispose(resize);
|
||||||
|
const logits = await models.blazepose.predict(enhance);
|
||||||
|
// todo: add landmarks model
|
||||||
|
tf.dispose(enhance);
|
||||||
|
const regions = await decode(logits);
|
||||||
|
logits[0].dispose();
|
||||||
|
logits[1].dispose();
|
||||||
|
log('poses', regions);
|
||||||
|
resolve(regions);
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,295 @@
|
||||||
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
|
import * as mp from './helpers.js';
|
||||||
|
|
||||||
|
/* ------------------------------------------------ *
|
||||||
|
* The MIT License (MIT)
|
||||||
|
* Copyright (c) 2020 terryky1220@gmail.com
|
||||||
|
* ------------------------------------------------ */
|
||||||
|
|
||||||
|
const kMidHipCenter = 0;
|
||||||
|
const kFullBodySizeRot = 1;
|
||||||
|
const kMidShoulderCenter = 2;
|
||||||
|
const kUpperBodySizeRot = 3;
|
||||||
|
const kPoseDetectKeyNum = 2;
|
||||||
|
const POSE_JOINT_NUM = 33;
|
||||||
|
let s_detect_model;
|
||||||
|
let s_detect_tensor_input;
|
||||||
|
let s_landmark_model;
|
||||||
|
let s_landmark_tensor_input;
|
||||||
|
const s_anchors = [];
|
||||||
|
|
||||||
|
function create_ssd_anchors() {
|
||||||
|
const anchor_options = {};
|
||||||
|
anchor_options.strides = [];
|
||||||
|
anchor_options.aspect_ratios = [];
|
||||||
|
anchor_options.feature_map_height = [];
|
||||||
|
anchor_options.num_layers = 4;
|
||||||
|
anchor_options.min_scale = 0.1484375;
|
||||||
|
anchor_options.max_scale = 0.75;
|
||||||
|
anchor_options.input_size_height = 128;
|
||||||
|
anchor_options.input_size_width = 128;
|
||||||
|
anchor_options.anchor_offset_x = 0.5;
|
||||||
|
anchor_options.anchor_offset_y = 0.5;
|
||||||
|
anchor_options.strides.push(8);
|
||||||
|
anchor_options.strides.push(16);
|
||||||
|
anchor_options.strides.push(16);
|
||||||
|
anchor_options.strides.push(16);
|
||||||
|
anchor_options.aspect_ratios.push(1.0);
|
||||||
|
anchor_options.reduce_boxes_in_lowest_layer = false;
|
||||||
|
anchor_options.interpolated_scale_aspect_ratio = 1.0;
|
||||||
|
anchor_options.fixed_anchor_size = true;
|
||||||
|
mp.GenerateAnchors(s_anchors, anchor_options);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------- *
|
||||||
|
* Create TensorFlow.js Model
|
||||||
|
* -------------------------------------------------- */
|
||||||
|
async function init_tfjs_blazepose() {
|
||||||
|
const url = './model/tfjs_model_full_pose_detection_float32/model.json';
|
||||||
|
s_detect_model = await tf.loadGraphModel(url);
|
||||||
|
const url_landmark = './model/tfjs_model_full_pose_landmark_39kp_float32/model.json';
|
||||||
|
s_landmark_model = await tf.loadGraphModel(url_landmark);
|
||||||
|
/* Pose detect */
|
||||||
|
s_detect_tensor_input = tfjs_get_tensor_by_name(s_detect_model, 0, 'input');
|
||||||
|
/* Pose Landmark */
|
||||||
|
s_landmark_tensor_input = tfjs_get_tensor_by_name(s_landmark_model, 0, 'input');
|
||||||
|
const det_input_w = s_detect_tensor_input.shape[2];
|
||||||
|
const det_input_h = s_detect_tensor_input.shape[1];
|
||||||
|
create_ssd_anchors(det_input_w, det_input_h);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------- *
|
||||||
|
* Invoke TensorFlow.js (Pose detection)
|
||||||
|
* -------------------------------------------------- */
|
||||||
|
async function decode_bounds(region_list, logits, score_thresh, input_img_w, input_img_h) {
|
||||||
|
const scores_ptr = await logits[0].data();
|
||||||
|
const bbox_ptr = await logits[1].data();
|
||||||
|
for (let i = 0; i < s_anchors.length; i++) {
|
||||||
|
const region = {};
|
||||||
|
const anchor = s_anchors[i];
|
||||||
|
const score0 = scores_ptr[i];
|
||||||
|
const score = 1.0 / (1.0 + Math.exp(-score0));
|
||||||
|
if (score > score_thresh) {
|
||||||
|
/*
|
||||||
|
* cx, cy, width, height
|
||||||
|
* key0_x, key0_y
|
||||||
|
* key1_x, key1_y
|
||||||
|
*/
|
||||||
|
const numkey = kPoseDetectKeyNum;
|
||||||
|
const bbx_idx = (4 + 2 * numkey) * i;
|
||||||
|
/* boundary box */
|
||||||
|
const sx = bbox_ptr[bbx_idx + 0];
|
||||||
|
const sy = bbox_ptr[bbx_idx + 1];
|
||||||
|
let w = bbox_ptr[bbx_idx + 2];
|
||||||
|
let h = bbox_ptr[bbx_idx + 3];
|
||||||
|
let cx = sx + anchor.x_center * input_img_w;
|
||||||
|
let cy = sy + anchor.y_center * input_img_h;
|
||||||
|
cx /= input_img_w;
|
||||||
|
cy /= input_img_h;
|
||||||
|
w /= input_img_w;
|
||||||
|
h /= input_img_h;
|
||||||
|
const topleft = {};
|
||||||
|
const btmright = {};
|
||||||
|
topleft.x = cx - w * 0.5;
|
||||||
|
topleft.y = cy - h * 0.5;
|
||||||
|
btmright.x = cx + w * 0.5;
|
||||||
|
btmright.y = cy + h * 0.5;
|
||||||
|
region.score = score;
|
||||||
|
region.topleft = topleft;
|
||||||
|
region.btmright = btmright;
|
||||||
|
/* landmark positions (6 keys) */
|
||||||
|
const keys = new Array(kPoseDetectKeyNum);
|
||||||
|
for (let j = 0; j < kPoseDetectKeyNum; j++) {
|
||||||
|
let lx = bbox_ptr[bbx_idx + 4 + (2 * j) + 0];
|
||||||
|
let ly = bbox_ptr[bbx_idx + 4 + (2 * j) + 1];
|
||||||
|
lx += anchor.x_center * input_img_w;
|
||||||
|
ly += anchor.y_center * input_img_h;
|
||||||
|
lx /= input_img_w;
|
||||||
|
ly /= input_img_h;
|
||||||
|
keys[j] = { x: lx, y: ly };
|
||||||
|
}
|
||||||
|
region.keys = keys;
|
||||||
|
region_list.push(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------- *
|
||||||
|
* extract ROI
|
||||||
|
* based on:
|
||||||
|
* - mediapipe/calculators/util/alignment_points_to_rects_calculator.cc
|
||||||
|
* AlignmentPointsRectsCalculator::DetectionToNormalizedRect()
|
||||||
|
* - mediapipe\calculators\util\rect_transformation_calculator.cc
|
||||||
|
* RectTransformationCalculator::TransformNormalizedRect()
|
||||||
|
* -------------------------------------------------- */
|
||||||
|
function normalize_radians(angle) {
|
||||||
|
return angle - 2 * Math.PI * Math.floor((angle - (-Math.PI)) / (2 * Math.PI));
|
||||||
|
}
|
||||||
|
|
||||||
|
function compute_rotation(region) {
|
||||||
|
const x0 = region.keys[kMidHipCenter].x;
|
||||||
|
const y0 = region.keys[kMidHipCenter].y;
|
||||||
|
const x1 = (region.topleft.x + region.btmright.x) * 0.5;
|
||||||
|
const y1 = (region.topleft.y + region.btmright.y) * 0.5;
|
||||||
|
const target_angle = Math.PI * 0.5;
|
||||||
|
const rotation = target_angle - Math.atan2(-(y1 - y0), x1 - x0);
|
||||||
|
region.rotation = normalize_radians(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rot_vec(vec, rotation) {
|
||||||
|
const sx = vec.x;
|
||||||
|
const sy = vec.y;
|
||||||
|
vec.x = sx * Math.cos(rotation) - sy * Math.sin(rotation);
|
||||||
|
vec.y = sx * Math.sin(rotation) + sy * Math.cos(rotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compute_detect_to_roi(region) {
|
||||||
|
const input_img_w = s_detect_tensor_input.shape[2];
|
||||||
|
const input_img_h = s_detect_tensor_input.shape[1];
|
||||||
|
const x_center = region.keys[kMidHipCenter].x * input_img_w;
|
||||||
|
const y_center = region.keys[kMidHipCenter].y * input_img_h;
|
||||||
|
const x_scale = region.keys[kFullBodySizeRot].x * input_img_w;
|
||||||
|
const y_scale = region.keys[kFullBodySizeRot].y * input_img_h;
|
||||||
|
// Bounding box size as double distance from center to scale point.
|
||||||
|
const box_size = Math.sqrt((x_scale - x_center) * (x_scale - x_center) + (y_scale - y_center) * (y_scale - y_center)) * 2.0;
|
||||||
|
/* RectTransformationCalculator::TransformNormalizedRect() */
|
||||||
|
const width = box_size;
|
||||||
|
const height = box_size;
|
||||||
|
const rotation = region.rotation;
|
||||||
|
const shift_x = 0.0;
|
||||||
|
const shift_y = 0.0;
|
||||||
|
let roi_cx;
|
||||||
|
let roi_cy;
|
||||||
|
if (rotation === 0.0) {
|
||||||
|
roi_cx = x_center + (width * shift_x);
|
||||||
|
roi_cy = y_center + (height * shift_y);
|
||||||
|
} else {
|
||||||
|
const dx = (width * shift_x) * Math.cos(rotation) - (height * shift_y) * Math.sin(rotation);
|
||||||
|
const dy = (width * shift_x) * Math.sin(rotation) + (height * shift_y) * Math.cos(rotation);
|
||||||
|
roi_cx = x_center + dx;
|
||||||
|
roi_cy = y_center + dy;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* calculate ROI width and height.
|
||||||
|
* scale parameter is based on
|
||||||
|
* "mediapipe/modules/pose_landmark/pose_detection_to_roi.pbtxt"
|
||||||
|
*/
|
||||||
|
const scale_x = 1.5;
|
||||||
|
const scale_y = 1.5;
|
||||||
|
const long_side = Math.max(width, height);
|
||||||
|
const roi_w = long_side * scale_x;
|
||||||
|
const roi_h = long_side * scale_y;
|
||||||
|
region.roi_center = { x: roi_cx / input_img_w, y: roi_cy / input_img_h };
|
||||||
|
region.roi_size = { x: roi_w / input_img_w, y: roi_h / input_img_h };
|
||||||
|
/* calculate ROI coordinates */
|
||||||
|
const dx = roi_w * 0.5;
|
||||||
|
const dy = roi_h * 0.5;
|
||||||
|
region.roi_coord = [];
|
||||||
|
region.roi_coord[0] = { x: -dx, y: -dy };
|
||||||
|
region.roi_coord[1] = { x: +dx, y: -dy };
|
||||||
|
region.roi_coord[2] = { x: +dx, y: +dy };
|
||||||
|
region.roi_coord[3] = { x: -dx, y: +dy };
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
rot_vec(region.roi_coord[i], rotation);
|
||||||
|
region.roi_coord[i].x += roi_cx;
|
||||||
|
region.roi_coord[i].y += roi_cy;
|
||||||
|
region.roi_coord[i].x /= input_img_h;
|
||||||
|
region.roi_coord[i].y /= input_img_h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function pack_detect_result(detect_result, region_list) {
|
||||||
|
for (let i = 0; i < region_list.length; i++) {
|
||||||
|
region = region_list[i];
|
||||||
|
compute_rotation(region);
|
||||||
|
compute_detect_to_roi(region);
|
||||||
|
detect_result.push(region);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------- *
|
||||||
|
* Invoke TensorFlow.js (Pose detection)
|
||||||
|
* -------------------------------------------------- */
|
||||||
|
function exec_tfjs(img) {
|
||||||
|
const w = s_detect_tensor_input.shape[2];
|
||||||
|
const h = s_detect_tensor_input.shape[1];
|
||||||
|
const logits = tf.tidy(() => {
|
||||||
|
img_tensor1d = tf.tensor1d(img);
|
||||||
|
img_tensor = img_tensor1d.reshape([h, w, 3]);
|
||||||
|
// normalize [0, 255] to [-1, 1].
|
||||||
|
const min = -1;
|
||||||
|
const max = 1;
|
||||||
|
const normalized = img_tensor.toFloat().mul((max - min) / 255.0).add(min);
|
||||||
|
// resize, reshape
|
||||||
|
const batched = normalized.reshape([-1, w, h, 3]);
|
||||||
|
return s_detect_model.predict(batched);
|
||||||
|
});
|
||||||
|
return logits;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function invoke_pose_detect(img) {
|
||||||
|
const logits = exec_tfjs(img);
|
||||||
|
const score_thresh = 0.75;
|
||||||
|
const detect_result = [];
|
||||||
|
const region_list = [];
|
||||||
|
const w = s_detect_tensor_input.shape[2];
|
||||||
|
const h = s_detect_tensor_input.shape[1];
|
||||||
|
await decode_bounds(region_list, logits, score_thresh, w, h);
|
||||||
|
if (true) { /* USE NMS */
|
||||||
|
const iou_thresh = 0.3;
|
||||||
|
const region_nms_list = [];
|
||||||
|
non_max_suppression(region_list, region_nms_list, iou_thresh);
|
||||||
|
pack_detect_result(detect_result, region_nms_list);
|
||||||
|
} else {
|
||||||
|
pack_detect_result(detect_result, region_list);
|
||||||
|
}
|
||||||
|
/* release the resource of output tensor */
|
||||||
|
logits[0].dispose();
|
||||||
|
logits[1].dispose();
|
||||||
|
return detect_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------- *
|
||||||
|
* Invoke TensorFlow.js (Pose landmark)
|
||||||
|
* -------------------------------------------------- */
|
||||||
|
function exec_tfjs_landmark(img) {
|
||||||
|
const w = s_landmark_tensor_input.shape[2];
|
||||||
|
const h = s_landmark_tensor_input.shape[1];
|
||||||
|
const logits = tf.tidy(() => {
|
||||||
|
img_tensor1d = tf.tensor1d(img);
|
||||||
|
img_tensor = img_tensor1d.reshape([h, w, 3]);
|
||||||
|
// normalize [0, 255] to [-1, 1].
|
||||||
|
const min = -1;
|
||||||
|
const max = 1;
|
||||||
|
const normalized = img_tensor.toFloat().mul((max - min) / 255.0).add(min);
|
||||||
|
// resize, reshape
|
||||||
|
const batched = normalized.reshape([-1, w, h, 3]);
|
||||||
|
return s_landmark_model.predict(batched);
|
||||||
|
});
|
||||||
|
return logits;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function invoke_pose_landmark(img) {
|
||||||
|
const logits = exec_tfjs_landmark(img);
|
||||||
|
const poseflag_ptr = await logits[1].data(); /* shape: (1, 1, 1, 1) */
|
||||||
|
const landmark_ptr = await logits[2].data(); /* shape: (1, 156) */
|
||||||
|
const img_w = s_landmark_tensor_input.shape[2];
|
||||||
|
const img_h = s_landmark_tensor_input.shape[1];
|
||||||
|
const landmark_result = {};
|
||||||
|
landmark_result.joint = [];
|
||||||
|
landmark_result.score = poseflag_ptr[0];
|
||||||
|
for (let i = 0; i < POSE_JOINT_NUM; i++) {
|
||||||
|
landmark_result.joint[i] = {
|
||||||
|
x: landmark_ptr[4 * i + 0] / img_w,
|
||||||
|
y: landmark_ptr[4 * i + 1] / img_h,
|
||||||
|
z: landmark_ptr[4 * i + 2],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
logits[0].dispose();
|
||||||
|
logits[1].dispose();
|
||||||
|
logits[2].dispose();
|
||||||
|
return landmark_result;
|
||||||
|
}
|
|
@ -0,0 +1,160 @@
|
||||||
|
/* ------------------------------------------------ *
|
||||||
|
* The MIT License (MIT)
|
||||||
|
* Copyright (c) 2020 terryky1220@gmail.com
|
||||||
|
* ------------------------------------------------ */
|
||||||
|
|
||||||
|
// Copyright 2019 The MediaPipe Authors.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
function CalculateScale(min_scale, max_scale, stride_index, num_strides) {
|
||||||
|
if (num_strides === 1) return (min_scale + max_scale) * 0.5;
|
||||||
|
return min_scale + (max_scale - min_scale) * 1.0 * stride_index / (num_strides - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function GenerateAnchors(anchors, options) {
|
||||||
|
let layer_id = 0;
|
||||||
|
while (layer_id < options.strides.length) {
|
||||||
|
const anchor_height = [];
|
||||||
|
const anchor_width = [];
|
||||||
|
const aspect_ratios = [];
|
||||||
|
const scales = [];
|
||||||
|
// For same strides, we merge the anchors in the same order.
|
||||||
|
let last_same_stride_layer = layer_id;
|
||||||
|
while (last_same_stride_layer < options.strides.length
|
||||||
|
&& options.strides[last_same_stride_layer] === options.strides[layer_id]) {
|
||||||
|
const scale = CalculateScale(options.min_scale, options.max_scale,
|
||||||
|
last_same_stride_layer, options.strides.length);
|
||||||
|
if (last_same_stride_layer === 0 && options.reduce_boxes_in_lowest_layer) {
|
||||||
|
// For first layer, it can be specified to use predefined anchors.
|
||||||
|
aspect_ratios.push(1.0);
|
||||||
|
aspect_ratios.push(2.0);
|
||||||
|
aspect_ratios.push(0.5);
|
||||||
|
scales.push(0.1);
|
||||||
|
scales.push(scale);
|
||||||
|
scales.push(scale);
|
||||||
|
} else {
|
||||||
|
for (let aspect_ratio_id = 0;
|
||||||
|
aspect_ratio_id < options.aspect_ratios.length;
|
||||||
|
++aspect_ratio_id) {
|
||||||
|
aspect_ratios.push(options.aspect_ratios[aspect_ratio_id]);
|
||||||
|
scales.push(scale);
|
||||||
|
}
|
||||||
|
if (options.interpolated_scale_aspect_ratio > 0.0) {
|
||||||
|
const scale_next = last_same_stride_layer === options.strides.length - 1
|
||||||
|
? 1.0
|
||||||
|
: CalculateScale(options.min_scale, options.max_scale,
|
||||||
|
last_same_stride_layer + 1,
|
||||||
|
options.strides.length);
|
||||||
|
scales.push(Math.sqrt(scale * scale_next));
|
||||||
|
aspect_ratios.push(options.interpolated_scale_aspect_ratio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
last_same_stride_layer++;
|
||||||
|
}
|
||||||
|
for (let i = 0; i < aspect_ratios.length; ++i) {
|
||||||
|
const ratio_sqrts = Math.sqrt(aspect_ratios[i]);
|
||||||
|
anchor_height.push(scales[i] / ratio_sqrts);
|
||||||
|
anchor_width.push(scales[i] * ratio_sqrts);
|
||||||
|
}
|
||||||
|
let feature_map_height = 0;
|
||||||
|
let feature_map_width = 0;
|
||||||
|
if (options.feature_map_height.length) {
|
||||||
|
feature_map_height = options.feature_map_height[layer_id];
|
||||||
|
feature_map_width = options.feature_map_width[layer_id];
|
||||||
|
} else {
|
||||||
|
const stride = options.strides[layer_id];
|
||||||
|
feature_map_height = Math.ceil(1.0 * options.input_size_height / stride);
|
||||||
|
feature_map_width = Math.ceil(1.0 * options.input_size_width / stride);
|
||||||
|
}
|
||||||
|
for (let y = 0; y < feature_map_height; ++y) {
|
||||||
|
for (let x = 0; x < feature_map_width; ++x) {
|
||||||
|
for (let anchor_id = 0; anchor_id < anchor_height.length; ++anchor_id) {
|
||||||
|
// TODO: Support specifying anchor_offset_x, anchor_offset_y.
|
||||||
|
const x_center = (x + options.anchor_offset_x) * 1.0 / feature_map_width;
|
||||||
|
const y_center = (y + options.anchor_offset_y) * 1.0 / feature_map_height;
|
||||||
|
const new_anchor = {};
|
||||||
|
new_anchor.x_center = x_center;
|
||||||
|
new_anchor.y_center = y_center;
|
||||||
|
if (options.fixed_anchor_size) {
|
||||||
|
new_anchor.w = 1.0;
|
||||||
|
new_anchor.h = 1.0;
|
||||||
|
} else {
|
||||||
|
new_anchor.w = anchor_width[anchor_id];
|
||||||
|
new_anchor.h = anchor_height[anchor_id];
|
||||||
|
}
|
||||||
|
anchors.push(new_anchor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layer_id = last_same_stride_layer;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------- *
|
||||||
|
* Apply NonMaxSuppression:
|
||||||
|
* https://github.com/tensorflow/tfjs/blob/master/tfjs-core/src/ops/image_ops.ts
|
||||||
|
* -------------------------------------------------- */
|
||||||
|
function calc_intersection_over_union(region0, region1) {
|
||||||
|
const sx0 = region0.box[0];
|
||||||
|
const sy0 = region0.box[1];
|
||||||
|
const ex0 = region0.box[2];
|
||||||
|
const ey0 = region0.box[3];
|
||||||
|
const sx1 = region1.box[0];
|
||||||
|
const sy1 = region1.box[1];
|
||||||
|
const ex1 = region1.box[2];
|
||||||
|
const ey1 = region1.box[3];
|
||||||
|
const xmin0 = Math.min(sx0, ex0);
|
||||||
|
const ymin0 = Math.min(sy0, ey0);
|
||||||
|
const xmax0 = Math.max(sx0, ex0);
|
||||||
|
const ymax0 = Math.max(sy0, ey0);
|
||||||
|
const xmin1 = Math.min(sx1, ex1);
|
||||||
|
const ymin1 = Math.min(sy1, ey1);
|
||||||
|
const xmax1 = Math.max(sx1, ex1);
|
||||||
|
const ymax1 = Math.max(sy1, ey1);
|
||||||
|
const area0 = (ymax0 - ymin0) * (xmax0 - xmin0);
|
||||||
|
const area1 = (ymax1 - ymin1) * (xmax1 - xmin1);
|
||||||
|
if (area0 <= 0 || area1 <= 0) return 0.0;
|
||||||
|
const intersect_xmin = Math.max(xmin0, xmin1);
|
||||||
|
const intersect_ymin = Math.max(ymin0, ymin1);
|
||||||
|
const intersect_xmax = Math.min(xmax0, xmax1);
|
||||||
|
const intersect_ymax = Math.min(ymax0, ymax1);
|
||||||
|
const intersect_area = Math.max(intersect_ymax - intersect_ymin, 0.0) * Math.max(intersect_xmax - intersect_xmin, 0.0);
|
||||||
|
return intersect_area / (area0 + area1 - intersect_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
function compare(v1, v2) {
|
||||||
|
if (v1.score > v2.score) return 1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function NMS(region_list, region_nms_list, iou_thresh) {
|
||||||
|
region_list.sort(compare);
|
||||||
|
for (let i = 0; i < region_list.length; i++) {
|
||||||
|
const region_candidate = region_list[i];
|
||||||
|
let ignore_candidate = false;
|
||||||
|
for (let j = 0; j < region_nms_list.length; j++) {
|
||||||
|
const region_nms = region_nms_list[j];
|
||||||
|
const iou = calc_intersection_over_union(region_candidate, region_nms);
|
||||||
|
if (iou >= iou_thresh) {
|
||||||
|
ignore_candidate = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ignore_candidate) {
|
||||||
|
region_nms_list.push(region_candidate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,374 @@
|
||||||
|
import * as detect from './detect.js';
|
||||||
|
|
||||||
|
/* ------------------------------------------------ *
|
||||||
|
* The MIT License (MIT)
|
||||||
|
* Copyright (c) 2020 terryky1220@gmail.com
|
||||||
|
* ------------------------------------------------ */
|
||||||
|
// tf.setBackend('wasm').then(() => startWebGL());
|
||||||
|
|
||||||
|
let s_debug_log;
|
||||||
|
let s_rtarget_main;
|
||||||
|
let s_rtarget_feed;
|
||||||
|
let s_rtarget_src;
|
||||||
|
|
||||||
|
class GuiProperty {
|
||||||
|
constructor() {
|
||||||
|
this.draw_roi_rect = false;
|
||||||
|
this.draw_pmeter = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const s_gui_prop = new GuiProperty();
|
||||||
|
|
||||||
|
function generate_input_image(gl, texid, win_w, win_h) {
|
||||||
|
const dims = detect.get_pose_detect_input_dims();
|
||||||
|
const buf_rgba = new Uint8Array(dims.w * dims.h * 4);
|
||||||
|
const buf_rgb = new Uint8Array(dims.w * dims.h * 3);
|
||||||
|
GLUtil.set_render_target(gl, s_rtarget_feed);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
r2d.draw_2d_texture(gl, texid, 0, win_h - dims.h, dims.w, dims.h, 1);
|
||||||
|
gl.readPixels(0, 0, dims.w, dims.h, gl.RGBA, gl.UNSIGNED_BYTE, buf_rgba);
|
||||||
|
for (let i = 0, j = 0; i < buf_rgba.length; i++) {
|
||||||
|
if (i % 4 !== 3) buf_rgb[j++] = buf_rgba[i];
|
||||||
|
}
|
||||||
|
GLUtil.set_render_target(gl, s_rtarget_main);
|
||||||
|
return buf_rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
function generate_landmark_input_image(gl, srctex, texw, texh, detection, pose_id) {
|
||||||
|
const dims = get_pose_landmark_input_dims();
|
||||||
|
const buf_rgba = new Uint8Array(dims.w * dims.h * 4);
|
||||||
|
const buf_rgb = new Uint8Array(dims.w * dims.h * 3);
|
||||||
|
const texcoord = [];
|
||||||
|
if (detection.length > pose_id) {
|
||||||
|
region = detection[pose_id];
|
||||||
|
const x0 = region.roi_coord[0].x;
|
||||||
|
const y0 = region.roi_coord[0].y;
|
||||||
|
const x1 = region.roi_coord[1].x; // 0--------1
|
||||||
|
const y1 = region.roi_coord[1].y; // | |
|
||||||
|
const x2 = region.roi_coord[2].x; // | |
|
||||||
|
const y2 = region.roi_coord[2].y; // 3--------2
|
||||||
|
const x3 = region.roi_coord[3].x;
|
||||||
|
const y3 = region.roi_coord[3].y;
|
||||||
|
texcoord[0] = x3; texcoord[1] = y3;
|
||||||
|
texcoord[2] = x0; texcoord[3] = y0;
|
||||||
|
texcoord[4] = x2; texcoord[5] = y2;
|
||||||
|
texcoord[6] = x1; texcoord[7] = y1;
|
||||||
|
}
|
||||||
|
GLUtil.set_render_target(gl, s_rtarget_feed);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
r2d.draw_2d_texture_texcoord_rot(gl, srctex, 0, texh - dims.h, dims.w, dims.h, texcoord, 0, 0, 0);
|
||||||
|
gl.readPixels(0, 0, dims.w, dims.h, gl.RGBA, gl.UNSIGNED_BYTE, buf_rgba);
|
||||||
|
for (let i = 0, j = 0; i < buf_rgba.length; i++) {
|
||||||
|
if (i % 4 != 3) buf_rgb[j++] = buf_rgba[i];
|
||||||
|
}
|
||||||
|
GLUtil.set_render_target(gl, s_rtarget_main);
|
||||||
|
return buf_rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
function
|
||||||
|
render_detect_region(gl, ofstx, ofsty, texw, texh, detection) {
|
||||||
|
const col_white = [1.0, 1.0, 1.0, 1.0];
|
||||||
|
const col_red = [1.0, 0.0, 0.0, 1.0];
|
||||||
|
const col_frame = [1.0, 0.0, 0.0, 1.0];
|
||||||
|
for (let i = 0; i < detection.length; i++) {
|
||||||
|
region = detection[i];
|
||||||
|
const x1 = region.topleft.x * texw + ofstx;
|
||||||
|
const y1 = region.topleft.y * texh + ofsty;
|
||||||
|
const x2 = region.btmright.x * texw + ofstx;
|
||||||
|
const y2 = region.btmright.y * texh + ofsty;
|
||||||
|
const score = region.score;
|
||||||
|
/* rectangle region */
|
||||||
|
r2d.draw_2d_rect(gl, x1, y1, x2 - x1, y2 - y1, col_frame, 2.0);
|
||||||
|
/* class name */
|
||||||
|
const buf = '' + (score * 100).toFixed(0);
|
||||||
|
dbgstr.draw_dbgstr_ex(gl, buf, x1, y1, 1.0, col_white, col_frame);
|
||||||
|
/* key points */
|
||||||
|
const hx = region.keys[kMidHipCenter].x * texw + ofstx;
|
||||||
|
const hy = region.keys[kMidHipCenter].y * texh + ofsty;
|
||||||
|
let sx = (region.topleft.x + region.btmright.x) * 0.5;
|
||||||
|
let sy = (region.topleft.y + region.btmright.y) * 0.5;
|
||||||
|
sx = sx * texw + ofstx;
|
||||||
|
sy = sy * texh + ofsty;
|
||||||
|
r2d.draw_2d_line(gl, hx, hy, sx, sy, col_white, 2.0);
|
||||||
|
let r = 4;
|
||||||
|
r2d.draw_2d_fillrect(gl, hx - (r / 2), hy - (r / 2), r, r, col_frame);
|
||||||
|
r2d.draw_2d_fillrect(gl, sx - (r / 2), sy - (r / 2), r, r, col_frame);
|
||||||
|
for (let j0 = 0; j0 < 4; j0++) {
|
||||||
|
const j1 = (j0 + 1) % 4;
|
||||||
|
const x1 = region.roi_coord[j0].x * texw + ofstx;
|
||||||
|
const y1 = region.roi_coord[j0].y * texh + ofsty;
|
||||||
|
const x2 = region.roi_coord[j1].x * texw + ofstx;
|
||||||
|
const y2 = region.roi_coord[j1].y * texh + ofsty;
|
||||||
|
r2d.draw_2d_line(gl, x1, y1, x2, y2, col_red, 2.0);
|
||||||
|
}
|
||||||
|
const cx = region.roi_center.x * texw + ofstx;
|
||||||
|
const cy = region.roi_center.y * texh + ofsty;
|
||||||
|
r = 10;
|
||||||
|
r2d.draw_2d_fillrect(gl, cx - (r / 2), cy - (r / 2), r, r, col_red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function transform_pose_landmark(transformed_pos, landmark, region) {
|
||||||
|
const scale_x = region.roi_size.x;
|
||||||
|
const scale_y = region.roi_size.y;
|
||||||
|
const pivot_x = region.roi_center.x;
|
||||||
|
const pivot_y = region.roi_center.y;
|
||||||
|
const rotation = region.rotation;
|
||||||
|
const mat = new Array(16);
|
||||||
|
matrix_identity(mat);
|
||||||
|
matrix_translate(mat, pivot_x, pivot_y, 0);
|
||||||
|
matrix_rotate(mat, RAD_TO_DEG(rotation), 0, 0, 1);
|
||||||
|
matrix_scale(mat, scale_x, scale_y, 1.0);
|
||||||
|
matrix_translate(mat, -0.5, -0.5, 0);
|
||||||
|
for (let i = 0; i < POSE_JOINT_NUM; i++) {
|
||||||
|
const vec = [landmark.joint[i].x, landmark.joint[i].y];
|
||||||
|
matrix_multvec2(mat, vec, vec);
|
||||||
|
transformed_pos[i] = { x: vec[0], y: vec[1] };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_bone(gl, ofstx, ofsty, drw_w, drw_h,
|
||||||
|
transformed_pos, id0, id1, col) {
|
||||||
|
const x0 = transformed_pos[id0].x * drw_w + ofstx;
|
||||||
|
const y0 = transformed_pos[id0].y * drw_h + ofsty;
|
||||||
|
const x1 = transformed_pos[id1].x * drw_w + ofstx;
|
||||||
|
const y1 = transformed_pos[id1].y * drw_h + ofsty;
|
||||||
|
r2d.draw_2d_line(gl, x0, y0, x1, y1, col, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_pose_landmark(gl, ofstx, ofsty, texw, texh, landmakr_ret,
|
||||||
|
detection, pose_id) {
|
||||||
|
const col_red = [1.0, 0.0, 0.0, 1.0];
|
||||||
|
const col_orange = [1.0, 0.6, 0.0, 1.0];
|
||||||
|
const col_cyan = [0.0, 1.0, 1.0, 1.0];
|
||||||
|
const col_lime = [0.0, 1.0, 0.3, 1.0];
|
||||||
|
const col_pink = [1.0, 0.0, 1.0, 1.0];
|
||||||
|
const col_blue = [0.0, 0.5, 1.0, 1.0];
|
||||||
|
const col_white = [1.0, 1.0, 1.0, 1.0];
|
||||||
|
if (landmakr_ret.length <= pose_id) return;
|
||||||
|
const landmark = landmakr_ret[pose_id];
|
||||||
|
const score = landmark.score;
|
||||||
|
const buf = 'score:' + (score * 100).toFixed(1);
|
||||||
|
dbgstr.draw_dbgstr_ex(gl, buf, texw - 120, 0, 1.0, col_white, col_red);
|
||||||
|
const transformed_pos = new Array(POSE_JOINT_NUM);
|
||||||
|
transform_pose_landmark(transformed_pos, landmark, detection[pose_id]);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 11, 12, col_cyan);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 12, 24, col_cyan);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 24, 23, col_cyan);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 23, 11, col_cyan);
|
||||||
|
/* right arm */
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 11, 13, col_orange);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 13, 15, col_orange);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 15, 21, col_orange);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 15, 19, col_orange);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 15, 17, col_orange);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 17, 19, col_orange);
|
||||||
|
/* left arm */
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 12, 14, col_lime);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 14, 16, col_lime);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 16, 22, col_lime);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 16, 20, col_lime);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 16, 18, col_lime);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 18, 20, col_lime);
|
||||||
|
/* face */
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 9, 10, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 0, 1, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 1, 2, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 2, 3, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 3, 7, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 0, 4, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 4, 5, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 5, 6, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 6, 8, col_blue);
|
||||||
|
/* right leg */
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 23, 25, col_pink);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 25, 27, col_pink);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 27, 31, col_pink);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 31, 29, col_pink);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 29, 27, col_pink);
|
||||||
|
/* left leg */
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 24, 26, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 26, 28, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 28, 32, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 32, 30, col_blue);
|
||||||
|
render_bone(gl, ofstx, ofsty, texw, texh, transformed_pos, 30, 28, col_blue);
|
||||||
|
for (let i = 0; i < POSE_JOINT_NUM; i++) {
|
||||||
|
const x = transformed_pos[i].x * texw + ofstx;
|
||||||
|
const y = transformed_pos[i].y * texh + ofsty;
|
||||||
|
const r = 9;
|
||||||
|
r2d.draw_2d_fillrect(gl, x - (r / 2), y - (r / 2), r, r, col_red);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function render_cropped_pose_image(gl, srctex, ofstx, ofsty, texw, texh, detection, pose_id) {
|
||||||
|
const texcoord = [];
|
||||||
|
if (detection.length <= pose_id) return;
|
||||||
|
region = detection[pose_id];
|
||||||
|
const x0 = region.roi_coord[0].x;
|
||||||
|
const y0 = region.roi_coord[0].y;
|
||||||
|
const x1 = region.roi_coord[1].x; // 0--------1
|
||||||
|
const y1 = region.roi_coord[1].y; // | |
|
||||||
|
const x2 = region.roi_coord[2].x; // | |
|
||||||
|
const y2 = region.roi_coord[2].y; // 3--------2
|
||||||
|
const x3 = region.roi_coord[3].x;
|
||||||
|
const y3 = region.roi_coord[3].y;
|
||||||
|
texcoord[0] = x0; texcoord[1] = y0;
|
||||||
|
texcoord[2] = x3; texcoord[3] = y3;
|
||||||
|
texcoord[4] = x1; texcoord[5] = y1;
|
||||||
|
texcoord[6] = x2; texcoord[7] = y2;
|
||||||
|
r2d.draw_2d_texture_texcoord_rot(gl, srctex, ofstx, ofsty, texw, texh, texcoord, 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Adjust the texture size to fit the window size
|
||||||
|
*
|
||||||
|
* Portrait
|
||||||
|
* Landscape +------+
|
||||||
|
* +-+------+-+ +------+
|
||||||
|
* | | | | | |
|
||||||
|
* | | | | | |
|
||||||
|
* +-+------+-+ +------+
|
||||||
|
* +------+
|
||||||
|
*/
|
||||||
|
function
|
||||||
|
generate_squared_src_image(gl, texid, src_w, src_h, win_w, win_h) {
|
||||||
|
const win_aspect = win_w / win_h;
|
||||||
|
const tex_aspect = src_w / src_h;
|
||||||
|
let scale;
|
||||||
|
let scaled_w;
|
||||||
|
let scaled_h;
|
||||||
|
let offset_x;
|
||||||
|
let offset_y;
|
||||||
|
if (win_aspect > tex_aspect) {
|
||||||
|
scale = win_h / src_h;
|
||||||
|
scaled_w = scale * src_w;
|
||||||
|
scaled_h = scale * src_h;
|
||||||
|
offset_x = (win_w - scaled_w) * 0.5;
|
||||||
|
offset_y = 0;
|
||||||
|
} else {
|
||||||
|
scale = win_w / src_w;
|
||||||
|
scaled_w = scale * src_w;
|
||||||
|
scaled_h = scale * src_h;
|
||||||
|
offset_x = 0;
|
||||||
|
offset_y = (win_h - scaled_h) * 0.5;
|
||||||
|
}
|
||||||
|
GLUtil.set_render_target(gl, s_rtarget_src);
|
||||||
|
gl.clearColor(0.7, 0.7, 0.7, 1.0);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
r2d.draw_2d_texture(gl, texid, offset_x, offset_y, scaled_w, scaled_h, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function init_gui() {
|
||||||
|
const gui = new dat.GUI();
|
||||||
|
gui.add(s_gui_prop, 'draw_roi_rect');
|
||||||
|
gui.add(s_gui_prop, 'draw_pmeter');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ---------------------------------------------------------------- *
|
||||||
|
* M A I N F U N C T I O N
|
||||||
|
* ---------------------------------------------------------------- */
|
||||||
|
async function startWebGL() {
|
||||||
|
s_debug_log = document.getElementById('debug_log');
|
||||||
|
const canvas = document.querySelector('#glcanvas');
|
||||||
|
const gl = canvas.getContext('webgl');
|
||||||
|
if (!gl) {
|
||||||
|
alert('Failed to initialize WebGL.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
gl.clearColor(0.7, 0.7, 0.7, 1.0);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
init_gui();
|
||||||
|
const camtex = GLUtil.create_camera_texture(gl);
|
||||||
|
// const camtex = GLUtil.create_video_texture (gl, "pexels_dance.mp4");
|
||||||
|
const imgtex = GLUtil.create_image_texture2(gl, 'pexels.jpg');
|
||||||
|
const win_w = canvas.clientWidth;
|
||||||
|
const win_h = canvas.clientHeight;
|
||||||
|
r2d.init_2d_render(gl, win_w, win_h);
|
||||||
|
init_dbgstr(gl, win_w, win_h);
|
||||||
|
pmeter.init_pmeter(gl, win_w, win_h, win_h - 40);
|
||||||
|
const stats = init_stats();
|
||||||
|
await init_tfjs_blazepose();
|
||||||
|
s_debug_log.innerHTML = 'tfjs.Backend = ' + tf.getBackend() + '<br>';
|
||||||
|
s_rtarget_main = GLUtil.create_render_target(gl, win_w, win_h, 0);
|
||||||
|
s_rtarget_feed = GLUtil.create_render_target(gl, win_w, win_w, 1);
|
||||||
|
s_rtarget_src = GLUtil.create_render_target(gl, win_w, win_w, 1);
|
||||||
|
/* stop loading spinner */
|
||||||
|
const spinner = document.getElementById('loading');
|
||||||
|
spinner.classList.add('loaded');
|
||||||
|
let prev_time_ms = performance.now();
|
||||||
|
|
||||||
|
async function render(now) {
|
||||||
|
pmeter.reset_lap(0);
|
||||||
|
pmeter.set_lap(0);
|
||||||
|
const cur_time_ms = performance.now();
|
||||||
|
const interval_ms = cur_time_ms - prev_time_ms;
|
||||||
|
prev_time_ms = cur_time_ms;
|
||||||
|
stats.begin();
|
||||||
|
let src_w = imgtex.image.width;
|
||||||
|
let src_h = imgtex.image.height;
|
||||||
|
let texid = imgtex.texid;
|
||||||
|
if (GLUtil.is_camera_ready(camtex)) {
|
||||||
|
GLUtil.update_camera_texture(gl, camtex);
|
||||||
|
src_w = camtex.video.videoWidth;
|
||||||
|
src_h = camtex.video.videoHeight;
|
||||||
|
texid = camtex.texid;
|
||||||
|
}
|
||||||
|
generate_squared_src_image(gl, texid, src_w, src_h, win_w, win_h);
|
||||||
|
texid = s_rtarget_src.texid;
|
||||||
|
/* --------------------------------------- *
|
||||||
|
* invoke TF.js (Pose detection)
|
||||||
|
* --------------------------------------- */
|
||||||
|
const feed_image = generate_input_image(gl, texid, win_w, win_h);
|
||||||
|
const time_invoke0_start = performance.now();
|
||||||
|
const predictions = await invoke_pose_detect(feed_image);
|
||||||
|
const time_invoke0 = performance.now() - time_invoke0_start;
|
||||||
|
/* --------------------------------------- *
|
||||||
|
* invoke TF.js (Pose landmark)
|
||||||
|
* --------------------------------------- */
|
||||||
|
const landmark_ret = [];
|
||||||
|
let time_invoke1 = 0;
|
||||||
|
for (let pose_id = 0; pose_id < predictions.length; pose_id++) {
|
||||||
|
const feed_image = generate_landmark_input_image(gl, texid, win_w, win_h, predictions, pose_id);
|
||||||
|
const time_invoke1_start = performance.now();
|
||||||
|
landmark_ret[pose_id] = await invoke_pose_landmark(feed_image);
|
||||||
|
time_invoke1 += performance.now() - time_invoke1_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* --------------------------------------- *
|
||||||
|
* render scene
|
||||||
|
* --------------------------------------- */
|
||||||
|
GLUtil.set_render_target(gl, s_rtarget_main);
|
||||||
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||||
|
r2d.draw_2d_texture(gl, texid, 0, 0, win_w, win_h, 0);
|
||||||
|
if (s_gui_prop.draw_roi_rect) {
|
||||||
|
render_detect_region(gl, 0, 0, win_w, win_h, predictions);
|
||||||
|
/* draw cropped image of the pose area */
|
||||||
|
for (let pose_id = 0; pose_id < predictions.length; pose_id++) {
|
||||||
|
const w = 100;
|
||||||
|
const h = 100;
|
||||||
|
const x = win_w - w - 10;
|
||||||
|
const y = h * pose_id + 20;
|
||||||
|
const col_white = [1.0, 1.0, 1.0, 1.0];
|
||||||
|
render_cropped_pose_image(gl, texid, x, y, w, h, predictions, pose_id);
|
||||||
|
r2d.draw_2d_rect(gl, x, y, w, h, col_white, 2.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (let pose_id = 0; pose_id < predictions.length; pose_id++) {
|
||||||
|
render_pose_landmark(gl, 0, 0, win_w, win_h, landmark_ret, predictions, pose_id);
|
||||||
|
}
|
||||||
|
/* --------------------------------------- *
|
||||||
|
* post process
|
||||||
|
* --------------------------------------- */
|
||||||
|
if (s_gui_prop.draw_pmeter) {
|
||||||
|
pmeter.draw_pmeter(gl, 0, 40);
|
||||||
|
}
|
||||||
|
let str = 'Interval: ' + interval_ms.toFixed(1) + ' [ms]';
|
||||||
|
dbgstr.draw_dbgstr(gl, str, 10, 10);
|
||||||
|
str = 'TF.js0 : ' + time_invoke0.toFixed(1) + ' [ms]';
|
||||||
|
dbgstr.draw_dbgstr(gl, str, 10, 10 + 22 * 1);
|
||||||
|
str = 'TF.js1 : ' + time_invoke1.toFixed(1) + ' [ms]';
|
||||||
|
dbgstr.draw_dbgstr(gl, str, 10, 10 + 22 * 2);
|
||||||
|
stats.end();
|
||||||
|
requestAnimationFrame(render);
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
62
src/human.js
62
src/human.js
|
@ -1,13 +1,14 @@
|
||||||
import { log } from './log.js';
|
import { log } from './log.js';
|
||||||
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.js';
|
||||||
import * as facemesh from './face/facemesh.js';
|
import * as facemesh from './blazeface/facemesh.js';
|
||||||
import * as age from './age/age.js';
|
import * as age from './age/age.js';
|
||||||
import * as gender from './gender/gender.js';
|
import * as gender from './gender/gender.js';
|
||||||
import * as emotion from './emotion/emotion.js';
|
import * as emotion from './emotion/emotion.js';
|
||||||
import * as embedding from './embedding/embedding.js';
|
import * as embedding from './embedding/embedding.js';
|
||||||
import * as posenet from './body/posenet.js';
|
import * as posenet from './posenet/posenet.js';
|
||||||
import * as handpose from './hand/handpose.js';
|
import * as blazepose from './blazepose/blazepose.js';
|
||||||
|
import * as handpose from './handpose/handpose.js';
|
||||||
import * as gesture from './gesture/gesture.js';
|
import * as gesture from './gesture/gesture.js';
|
||||||
import * as image from './image.js';
|
import * as image from './image.js';
|
||||||
import * as profile from './profile.js';
|
import * as profile from './profile.js';
|
||||||
|
@ -18,7 +19,6 @@ import * as app from '../package.json';
|
||||||
// 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();
|
||||||
// @ts-ignore
|
|
||||||
return parseInt(Number(process.hrtime.bigint()) / 1000 / 1000);
|
return parseInt(Number(process.hrtime.bigint()) / 1000 / 1000);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -73,7 +73,6 @@ class Human {
|
||||||
}
|
}
|
||||||
|
|
||||||
profile() {
|
profile() {
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.profile) return profile.data;
|
if (this.config.profile) return profile.data;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -104,7 +103,6 @@ class Human {
|
||||||
}
|
}
|
||||||
|
|
||||||
simmilarity(embedding1, embedding2) {
|
simmilarity(embedding1, embedding2) {
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.face.embedding.enabled) return embedding.simmilarity(embedding1, embedding2);
|
if (this.config.face.embedding.enabled) return embedding.simmilarity(embedding1, embedding2);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -134,37 +132,26 @@ class Human {
|
||||||
this.models.embedding,
|
this.models.embedding,
|
||||||
this.models.posenet,
|
this.models.posenet,
|
||||||
this.models.handpose,
|
this.models.handpose,
|
||||||
|
this.models.blazepose,
|
||||||
] = await Promise.all([
|
] = await Promise.all([
|
||||||
// @ts-ignore
|
|
||||||
this.models.facemesh || (this.config.face.enabled ? facemesh.load(this.config) : null),
|
this.models.facemesh || (this.config.face.enabled ? facemesh.load(this.config) : null),
|
||||||
// @ts-ignore
|
|
||||||
this.models.age || ((this.config.face.enabled && this.config.face.age.enabled) ? age.load(this.config) : null),
|
this.models.age || ((this.config.face.enabled && this.config.face.age.enabled) ? age.load(this.config) : null),
|
||||||
// @ts-ignore
|
|
||||||
this.models.gender || ((this.config.face.enabled && this.config.face.gender.enabled) ? gender.load(this.config) : null),
|
this.models.gender || ((this.config.face.enabled && this.config.face.gender.enabled) ? gender.load(this.config) : null),
|
||||||
// @ts-ignore
|
|
||||||
this.models.emotion || ((this.config.face.enabled && this.config.face.emotion.enabled) ? emotion.load(this.config) : null),
|
this.models.emotion || ((this.config.face.enabled && this.config.face.emotion.enabled) ? emotion.load(this.config) : null),
|
||||||
// @ts-ignore
|
|
||||||
this.models.embedding || ((this.config.face.enabled && this.config.face.embedding.enabled) ? embedding.load(this.config) : null),
|
this.models.embedding || ((this.config.face.enabled && this.config.face.embedding.enabled) ? embedding.load(this.config) : null),
|
||||||
// @ts-ignore
|
|
||||||
this.models.posenet || (this.config.body.enabled ? posenet.load(this.config) : null),
|
this.models.posenet || (this.config.body.enabled ? posenet.load(this.config) : null),
|
||||||
// @ts-ignore
|
|
||||||
this.models.handpose || (this.config.hand.enabled ? handpose.load(this.config) : null),
|
this.models.handpose || (this.config.hand.enabled ? handpose.load(this.config) : null),
|
||||||
|
this.models.blazepose || (this.config.pose.enabled ? blazepose.load(this.config) : null),
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.face.enabled && !this.models.facemesh) this.models.facemesh = await facemesh.load(this.config);
|
if (this.config.face.enabled && !this.models.facemesh) this.models.facemesh = await facemesh.load(this.config);
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.face.enabled && this.config.face.age.enabled && !this.models.age) this.models.age = await age.load(this.config);
|
if (this.config.face.enabled && this.config.face.age.enabled && !this.models.age) this.models.age = await age.load(this.config);
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.face.enabled && this.config.face.gender.enabled && !this.models.gender) this.models.gender = await gender.load(this.config);
|
if (this.config.face.enabled && this.config.face.gender.enabled && !this.models.gender) this.models.gender = await gender.load(this.config);
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.face.enabled && this.config.face.emotion.enabled && !this.models.emotion) this.models.emotion = await emotion.load(this.config);
|
if (this.config.face.enabled && this.config.face.emotion.enabled && !this.models.emotion) this.models.emotion = await emotion.load(this.config);
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.face.enabled && this.config.face.embedding.enabled && !this.models.embedding) this.models.embedding = await embedding.load(this.config);
|
if (this.config.face.enabled && this.config.face.embedding.enabled && !this.models.embedding) this.models.embedding = await embedding.load(this.config);
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.body.enabled && !this.models.posenet) this.models.posenet = await posenet.load(this.config);
|
if (this.config.body.enabled && !this.models.posenet) this.models.posenet = await posenet.load(this.config);
|
||||||
// @ts-ignore
|
|
||||||
if (this.config.hand.enabled && !this.models.handpose) this.models.handpose = await handpose.load(this.config);
|
if (this.config.hand.enabled && !this.models.handpose) this.models.handpose = await handpose.load(this.config);
|
||||||
|
if (this.config.pose.enabled && !this.models.blazepose) this.models.blazepose = await blazepose.load(this.config);
|
||||||
}
|
}
|
||||||
const current = Math.trunc(now() - timeStamp);
|
const current = Math.trunc(now() - timeStamp);
|
||||||
if (current > (this.perf.load || 0)) this.perf.load = current;
|
if (current > (this.perf.load || 0)) this.perf.load = current;
|
||||||
|
@ -230,7 +217,6 @@ class Human {
|
||||||
const faceRes = [];
|
const faceRes = [];
|
||||||
this.state = 'run:face';
|
this.state = 'run:face';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
const faces = await this.models.facemesh?.estimateFaces(input, this.config);
|
const faces = await this.models.facemesh?.estimateFaces(input, this.config);
|
||||||
this.perf.face = Math.trunc(now() - timeStamp);
|
this.perf.face = Math.trunc(now() - timeStamp);
|
||||||
for (const face of faces) {
|
for (const face of faces) {
|
||||||
|
@ -245,12 +231,10 @@ class Human {
|
||||||
// run age, inherits face from blazeface
|
// run age, inherits face from blazeface
|
||||||
this.analyze('Start Age:');
|
this.analyze('Start Age:');
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
// @ts-ignore
|
|
||||||
ageRes = this.config.face.age.enabled ? age.predict(face.image, this.config) : {};
|
ageRes = this.config.face.age.enabled ? age.predict(face.image, this.config) : {};
|
||||||
} else {
|
} else {
|
||||||
this.state = 'run:age';
|
this.state = 'run:age';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
ageRes = this.config.face.age.enabled ? await age.predict(face.image, this.config) : {};
|
ageRes = this.config.face.age.enabled ? await age.predict(face.image, this.config) : {};
|
||||||
this.perf.age = Math.trunc(now() - timeStamp);
|
this.perf.age = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
|
@ -258,12 +242,10 @@ class Human {
|
||||||
// run gender, inherits face from blazeface
|
// run gender, inherits face from blazeface
|
||||||
this.analyze('Start Gender:');
|
this.analyze('Start Gender:');
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
// @ts-ignore
|
|
||||||
genderRes = this.config.face.gender.enabled ? gender.predict(face.image, this.config) : {};
|
genderRes = this.config.face.gender.enabled ? gender.predict(face.image, this.config) : {};
|
||||||
} else {
|
} else {
|
||||||
this.state = 'run:gender';
|
this.state = 'run:gender';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
genderRes = this.config.face.gender.enabled ? await gender.predict(face.image, this.config) : {};
|
genderRes = this.config.face.gender.enabled ? await gender.predict(face.image, this.config) : {};
|
||||||
this.perf.gender = Math.trunc(now() - timeStamp);
|
this.perf.gender = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
|
@ -271,12 +253,10 @@ class Human {
|
||||||
// run emotion, inherits face from blazeface
|
// run emotion, inherits face from blazeface
|
||||||
this.analyze('Start Emotion:');
|
this.analyze('Start Emotion:');
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
// @ts-ignore
|
|
||||||
emotionRes = this.config.face.emotion.enabled ? emotion.predict(face.image, this.config) : {};
|
emotionRes = this.config.face.emotion.enabled ? emotion.predict(face.image, this.config) : {};
|
||||||
} else {
|
} else {
|
||||||
this.state = 'run:emotion';
|
this.state = 'run:emotion';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
emotionRes = this.config.face.emotion.enabled ? await emotion.predict(face.image, this.config) : {};
|
emotionRes = this.config.face.emotion.enabled ? await emotion.predict(face.image, this.config) : {};
|
||||||
this.perf.emotion = Math.trunc(now() - timeStamp);
|
this.perf.emotion = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
|
@ -285,12 +265,10 @@ class Human {
|
||||||
// run emotion, inherits face from blazeface
|
// run emotion, inherits face from blazeface
|
||||||
this.analyze('Start Embedding:');
|
this.analyze('Start Embedding:');
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
// @ts-ignore
|
|
||||||
embeddingRes = this.config.face.embedding.enabled ? embedding.predict(face.image, this.config) : {};
|
embeddingRes = this.config.face.embedding.enabled ? embedding.predict(face.image, this.config) : {};
|
||||||
} else {
|
} else {
|
||||||
this.state = 'run:embedding';
|
this.state = 'run:embedding';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
embeddingRes = this.config.face.embedding.enabled ? await embedding.predict(face.image, this.config) : {};
|
embeddingRes = this.config.face.embedding.enabled ? await embedding.predict(face.image, this.config) : {};
|
||||||
this.perf.embedding = Math.trunc(now() - timeStamp);
|
this.perf.embedding = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
|
@ -346,7 +324,6 @@ class Human {
|
||||||
async image(input, userConfig = {}) {
|
async image(input, userConfig = {}) {
|
||||||
this.state = 'image';
|
this.state = 'image';
|
||||||
this.config = mergeDeep(this.config, userConfig);
|
this.config = mergeDeep(this.config, userConfig);
|
||||||
// @ts-ignore
|
|
||||||
const process = image.process(input, this.config);
|
const process = image.process(input, this.config);
|
||||||
process.tensor.dispose();
|
process.tensor.dispose();
|
||||||
return process.canvas;
|
return process.canvas;
|
||||||
|
@ -371,6 +348,7 @@ class Human {
|
||||||
}
|
}
|
||||||
|
|
||||||
let poseRes;
|
let poseRes;
|
||||||
|
let blazeposeRes;
|
||||||
let handRes;
|
let handRes;
|
||||||
let faceRes;
|
let faceRes;
|
||||||
|
|
||||||
|
@ -386,7 +364,6 @@ class Human {
|
||||||
this.analyze('Start Scope:');
|
this.analyze('Start Scope:');
|
||||||
|
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
const process = image.process(input, this.config);
|
const process = image.process(input, this.config);
|
||||||
if (!process || !process.tensor) {
|
if (!process || !process.tensor) {
|
||||||
log('could not convert input to tensor');
|
log('could not convert input to tensor');
|
||||||
|
@ -410,36 +387,45 @@ class Human {
|
||||||
// run posenet
|
// run posenet
|
||||||
this.analyze('Start Body:');
|
this.analyze('Start Body:');
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
// @ts-ignore
|
|
||||||
poseRes = this.config.body.enabled ? this.models.posenet?.estimatePoses(process.tensor, this.config) : [];
|
poseRes = this.config.body.enabled ? this.models.posenet?.estimatePoses(process.tensor, this.config) : [];
|
||||||
if (this.perf.body) delete this.perf.body;
|
if (this.perf.body) delete this.perf.body;
|
||||||
} else {
|
} else {
|
||||||
this.state = 'run:body';
|
this.state = 'run:body';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
poseRes = this.config.body.enabled ? await this.models.posenet?.estimatePoses(process.tensor, this.config) : [];
|
poseRes = this.config.body.enabled ? await this.models.posenet?.estimatePoses(process.tensor, this.config) : [];
|
||||||
this.perf.body = Math.trunc(now() - timeStamp);
|
this.perf.body = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
this.analyze('End Body:');
|
this.analyze('End Body:');
|
||||||
|
|
||||||
|
// run posenet
|
||||||
|
this.analyze('Start Pose:');
|
||||||
|
if (this.config.async) {
|
||||||
|
blazeposeRes = this.config.pose.enabled ? blazepose.predict(process.tensor, this.config) : [];
|
||||||
|
if (this.perf.pose) delete this.perf.pose;
|
||||||
|
} else {
|
||||||
|
this.state = 'run:pose';
|
||||||
|
timeStamp = now();
|
||||||
|
blazeposeRes = this.config.pose.enabled ? await blazepose.predict(process.tensor, this.config) : [];
|
||||||
|
this.perf.pose = Math.trunc(now() - timeStamp);
|
||||||
|
}
|
||||||
|
this.analyze('End Pose:');
|
||||||
|
|
||||||
// run handpose
|
// run handpose
|
||||||
this.analyze('Start Hand:');
|
this.analyze('Start Hand:');
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
// @ts-ignore
|
|
||||||
handRes = this.config.hand.enabled ? this.models.handpose?.estimateHands(process.tensor, this.config) : [];
|
handRes = this.config.hand.enabled ? this.models.handpose?.estimateHands(process.tensor, this.config) : [];
|
||||||
if (this.perf.hand) delete this.perf.hand;
|
if (this.perf.hand) delete this.perf.hand;
|
||||||
} else {
|
} else {
|
||||||
this.state = 'run:hand';
|
this.state = 'run:hand';
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
handRes = this.config.hand.enabled ? await this.models.handpose?.estimateHands(process.tensor, this.config) : [];
|
handRes = this.config.hand.enabled ? await this.models.handpose?.estimateHands(process.tensor, this.config) : [];
|
||||||
this.perf.hand = Math.trunc(now() - timeStamp);
|
this.perf.hand = Math.trunc(now() - timeStamp);
|
||||||
}
|
}
|
||||||
// this.analyze('End Hand:');
|
this.analyze('End Hand:');
|
||||||
|
|
||||||
// if async wait for results
|
// if async wait for results
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
[faceRes, poseRes, handRes] = await Promise.all([faceRes, poseRes, handRes]);
|
[faceRes, poseRes, blazeposeRes, handRes] = await Promise.all([faceRes, poseRes, blazeposeRes, handRes]);
|
||||||
}
|
}
|
||||||
process.tensor.dispose();
|
process.tensor.dispose();
|
||||||
|
|
||||||
|
@ -456,7 +442,7 @@ class Human {
|
||||||
|
|
||||||
this.perf.total = Math.trunc(now() - timeStart);
|
this.perf.total = Math.trunc(now() - timeStart);
|
||||||
this.state = 'idle';
|
this.state = 'idle';
|
||||||
resolve({ face: faceRes, body: poseRes, hand: handRes, gesture: gestureRes, performance: this.perf, canvas: process.canvas });
|
resolve({ face: faceRes, body: poseRes, hand: handRes, pose: blazeposeRes, gesture: gestureRes, performance: this.perf, canvas: process.canvas });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue