diff --git a/config.js b/config.js
index fba6f6a6..7541b96d 100644
--- a/config.js
+++ b/config.js
@@ -71,7 +71,7 @@ export default {
// 'blazeface-back' is blazeface model optimized for smaller and/or distanct faces
// 'faceboxes' is alternative model to 'blazeface'
inputSize: 256, // fixed value: 128 for front and 256 for 'back'
- rotation: false, // use best-guess rotated face image or just box with rotation as-is
+ rotation: true, // use best-guess rotated face image or just box with rotation as-is
// false means higher performance, but incorrect mesh mapping if face angle is above 20 degrees
maxFaces: 10, // maximum number of faces detected in the input
// should be set to the minimum number for performance
diff --git a/demo/browser.js b/demo/browser.js
index f4b6793e..e717960b 100644
--- a/demo/browser.js
+++ b/demo/browser.js
@@ -2,7 +2,7 @@ import Human from '../dist/human.esm.js'; // equivalent of @vladmandic/human
import Menu from './menu.js';
import GLBench from './gl-bench.js';
-const userConfig = { }; // add any user configuration overrides
+const userConfig = { backend: 'wasm' }; // add any user configuration overrides
/*
const userConfig = {
@@ -40,11 +40,11 @@ const ui = {
drawFPS: [], // internal, holds fps values for draw performance
buffered: false, // experimental, should output be buffered between frames
drawWarmup: false, // debug only, should warmup image processing be displayed on startup
- drawThread: null, // perform draw operations in a separate thread
- detectThread: null, // perform detect operations in a separate thread
+ drawThread: null, // internl, perform draw operations in a separate thread
+ detectThread: null, // internl, perform detect operations in a separate thread
framesDraw: 0, // internal, statistics on frames drawn
framesDetect: 0, // internal, statistics on frames detected
- bench: false, // show gl fps benchmark window
+ bench: true, // show gl fps benchmark window
lastFrame: 0, // time of last frame processing
};
@@ -110,7 +110,11 @@ async function drawResults(input) {
await menu.process.updateChart('FPS', ui.detectFPS);
// get updated canvas
- if (ui.buffered || !result.canvas) result.canvas = await human.image(input).canvas;
+ if (ui.buffered || !result.canvas) {
+ const image = await human.image(input);
+ result.canvas = image.canvas;
+ human.tf.dispose(image.tensor);
+ }
// draw image from video
const ctx = canvas.getContext('2d');
@@ -421,10 +425,10 @@ function setupMenu() {
menu.display.addHTML('
');
menu.display.addBool('use 3D depth', human.draw.options, 'useDepth');
menu.display.addBool('print labels', human.draw.options, 'drawLabels');
+ menu.display.addBool('draw points', human.draw.options, 'drawPoints');
menu.display.addBool('draw boxes', human.draw.options, 'drawBoxes');
menu.display.addBool('draw polygons', human.draw.options, 'drawPolygons');
- menu.display.addBool('Fill Polygons', human.draw.options, 'fillPolygons');
- menu.display.addBool('draw points', human.draw.options, 'drawPoints');
+ menu.display.addBool('fill polygons', human.draw.options, 'fillPolygons');
menu.image = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[1] });
menu.image.addBool('enabled', human.config.filter, 'enabled', (val) => human.config.filter.enabled = val);
@@ -449,8 +453,8 @@ function setupMenu() {
menu.process = new Menu(document.body, '', { top: `${document.getElementById('menubar').offsetHeight}px`, left: x[2] });
menu.process.addList('backend', ['cpu', 'webgl', 'wasm', 'humangl'], human.config.backend, (val) => human.config.backend = val);
menu.process.addBool('async operations', human.config, 'async', (val) => human.config.async = val);
- menu.process.addBool('enable profiler', human.config, 'profile', (val) => human.config.profile = val);
- menu.process.addBool('memory shield', human.config, 'deallocate', (val) => human.config.deallocate = val);
+ // menu.process.addBool('enable profiler', human.config, 'profile', (val) => human.config.profile = val);
+ // menu.process.addBool('memory shield', human.config, 'deallocate', (val) => human.config.deallocate = val);
menu.process.addBool('use web worker', ui, 'useWorker');
menu.process.addHTML(' ');
menu.process.addLabel('model parameters');
@@ -526,7 +530,6 @@ async function drawWarmup(res) {
async function main() {
log('Demo starting ...');
- log('Browser:', navigator?.userAgent);
setupMenu();
document.getElementById('log').innerText = `Human: version ${human.version}`;
if (ui.modelsPreload && !ui.useWorker) {
diff --git a/demo/gl-bench.js b/demo/gl-bench.js
index 90b5839a..7093c66c 100644
--- a/demo/gl-bench.js
+++ b/demo/gl-bench.js
@@ -20,7 +20,7 @@ const UISVG = `
00 FPS
-
+
diff --git a/demo/menu.js b/demo/menu.js
index 3eeac1f6..bb68ee7d 100644
--- a/demo/menu.js
+++ b/demo/menu.js
@@ -18,7 +18,7 @@ let theme = {
function createCSS() {
if (CSScreated) return;
const css = `
- :root { --rounded: 0.2rem; }
+ :root { --rounded: 0.1rem; }
.menu { position: absolute; top: 0rem; right: 0; width: max-content; padding: 0 0.2rem 0 0.2rem; line-height: 1.8rem; z-index: 10;
box-shadow: 0 0 8px dimgrey; background: ${theme.background}; border-radius: var(--rounded); border-color: black; border-style: solid; border-width: thin; }
diff --git a/demo/node.js b/demo/node.js
index 29442994..452aa5f7 100644
--- a/demo/node.js
+++ b/demo/node.js
@@ -40,8 +40,6 @@ async function init() {
// pre-load models
log.info('Human:', human.version);
log.info('Active Configuration', human.config);
- log.info('TFJS Version:', human.tf.version_core, 'Backend:', tf.getBackend());
- log.info('TFJS Flags:', human.tf.env().features);
await human.load();
const loaded = Object.keys(human.models).filter((a) => human.models[a]);
log.info('Loaded:', loaded);
@@ -63,27 +61,31 @@ async function detect(input) {
// dispose image tensor as we no longer need it
image.dispose();
// print data to console
- log.data(result);
+ log.data('Face: ', result.face);
+ log.data('Body:', result.body);
+ log.data('Hand:', result.hand);
+ log.data('Gesture:', result.gesture);
}
async function test() {
- // test with embedded face image
+ // test with embedded full body image
+ let result;
+
log.state('Processing embedded warmup image: face');
myConfig.warmup = 'face';
- const resultFace = await human.warmup(myConfig);
- log.data('Face: ', resultFace.face);
+ result = await human.warmup(myConfig);
+ log.data('Face: ', result.face);
- // test with embedded full body image
log.state('Processing embedded warmup image: full');
myConfig.warmup = 'full';
- const resultFull = await human.warmup(myConfig);
- log.data('Body:', resultFull.body);
- log.data('Hand:', resultFull.hand);
- log.data('Gesture:', resultFull.gesture);
+ result = await human.warmup(myConfig);
+ log.data('Body:', result.body);
+ log.data('Hand:', result.hand);
+ log.data('Gesture:', result.gesture);
}
async function main() {
- log.info('NodeJS:', process.version);
+ log.header();
log.info('Current folder:', process.env.PWD);
await init();
if (process.argv.length !== 3) {
diff --git a/package.json b/package.json
index 15bd076e..9c3de638 100644
--- a/package.json
+++ b/package.json
@@ -50,7 +50,7 @@
"seedrandom": "^3.0.5",
"simple-git": "^2.36.0",
"tslib": "^2.1.0",
- "typescript": "^4.3.0-dev.20210305"
+ "typescript": "^4.2.3"
},
"scripts": {
"start": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",
diff --git a/src/draw.ts b/src/draw.ts
index 92aada95..a4c3ecc9 100644
--- a/src/draw.ts
+++ b/src/draw.ts
@@ -9,13 +9,14 @@ export const options = {
lineHeight: 20,
lineWidth: 6,
pointSize: 2,
- roundRect: 8,
+ roundRect: 28,
drawPoints: false,
drawLabels: true,
drawBoxes: true,
drawPolygons: true,
fillPolygons: false,
useDepth: true,
+ useCurves: true,
bufferedOutput: false,
};
@@ -27,9 +28,13 @@ function point(ctx, x, y) {
}
function rect(ctx, x, y, width, height) {
- if (options.roundRect && options.roundRect > 0) {
+ ctx.beginPath();
+ if (options.useCurves) {
+ const cx = (x + x + width) / 2;
+ const cy = (y + y + height) / 2;
+ ctx.ellipse(cx, cy, width / 2, height / 2, 0, 0, 2 * Math.PI);
+ } else {
ctx.lineWidth = options.lineWidth;
- ctx.beginPath();
ctx.moveTo(x + options.roundRect, y);
ctx.lineTo(x + width - options.roundRect, y);
ctx.quadraticCurveTo(x + width, y, x + width, y + options.roundRect);
@@ -40,122 +45,40 @@ function rect(ctx, x, y, width, height) {
ctx.lineTo(x, y + options.roundRect);
ctx.quadraticCurveTo(x, y, x + options.roundRect, y);
ctx.closePath();
- ctx.stroke();
- } else {
- rect(ctx, x, y, width, height);
}
+ ctx.stroke();
}
-// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
-function lines(ctx, points) {
+function lines(ctx, points: number[] = []) {
+ if (points === undefined || points.length === 0) return;
ctx.beginPath();
- const path = new Path2D();
- path.moveTo(points[0][0], points[0][1]);
- for (const pt of points) {
- path.lineTo(pt[0], parseInt(pt[1]));
- }
- ctx.stroke(path);
+ ctx.moveTo(points[0][0], points[0][1]);
+ for (const pt of points) ctx.lineTo(pt[0], parseInt(pt[1]));
+ ctx.stroke();
if (options.fillPolygons) {
ctx.closePath();
- ctx.fill(path);
+ ctx.fill();
}
}
-// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
-function curve(ctx, points = []) {
- if (points.length < 2) return;
- ctx.lineWidth = options.lineWidth;
- ctx.beginPath();
+function curves(ctx, points: number[] = []) {
+ if (points === undefined || points.length === 0) return;
+ if (!options.useCurves || points.length <= 2) {
+ lines(ctx, points);
+ return;
+ }
ctx.moveTo(points[0][0], points[0][1]);
- for (let i = 0; i < points.length - 1; i++) {
- const xMid = (points[i][0] + points[i + 1][0]) / 2;
- const yMid = (points[i][1] + points[i + 1][1]) / 2;
- const cpX1 = (xMid + points[i][0]) / 2;
- const cpX2 = (xMid + points[i + 1][1]) / 2;
- ctx.quadraticCurveTo(cpX1, points[i][1], xMid, yMid);
- ctx.quadraticCurveTo(cpX2, points[i + 1][1], points[i + 1][0], points[i + 1][0]);
+ for (let i = 0; i < points.length - 2; i++) {
+ const xc = (points[i][0] + points[i + 1][0]) / 2;
+ const yc = (points[i][1] + points[i + 1][1]) / 2;
+ ctx.quadraticCurveTo(points[i][0], points[i][1], xc, yc);
}
- ctx.strokeStyle = options.color;
+ ctx.quadraticCurveTo(points[points.length - 2][0], points[points.length - 2][1], points[points.length - 1][0], points[points.length - 1][1]);
ctx.stroke();
-}
-
-// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
-function bezier(ctx, points) {
- const tension = 0; // tension at 0 will be straight line
- const factor = 1; // factor is normally 1, but changing the value can control the smoothness too
- if (points.length < 2) return;
- ctx.lineWidth = options.lineWidth;
- ctx.strokeStyle = options.color;
- ctx.fillStyle = options.color;
- ctx.beginPath();
- ctx.moveTo(points[0][0], points[0][1]);
- let dx1 = 0;
- let dy1 = 0;
- let preP = points[0];
- for (let i = 1; i < points.length; i++) {
- const curP = points[i];
- const nexP = points[i + 1];
- const m = nexP ? (nexP[1] - preP[1]) / (nexP[0] - preP[0]) : 0;
- const dx2 = nexP ? (nexP[0] - curP[0]) * -factor : 0;
- const dy2 = nexP ? dx2 * m * tension : 0;
- ctx.bezierCurveTo(preP[0] - dx1, preP[1] - dy1, curP[0] + dx2, curP[1] + dy2, curP[0], curP[1]);
- dx1 = dx2;
- dy1 = dy2;
- preP = curP;
+ if (options.fillPolygons) {
+ ctx.closePath();
+ ctx.fill();
}
- ctx.stroke();
-}
-
-// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
-function spline(ctx, points) {
- const tension = 0.8;
- if (points.length < 2) return;
- const va = (arr, i, j) => [arr[2 * j] - arr[2 * i], arr[2 * j + 1] - arr[2 * i + 1]];
- const distance = (arr, i, j) => Math.sqrt(((arr[2 * i] - arr[2 * j]) ** 2) + ((arr[2 * i + 1] - arr[2 * j + 1]) ** 2));
- // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars
- const ctlpts = (x1, y1, x2, y2, x3, y3) => {
- // eslint-disable-next-line prefer-rest-params
- const v = va(arguments, 0, 2);
- // eslint-disable-next-line prefer-rest-params
- const d01 = distance(arguments, 0, 1);
- // eslint-disable-next-line prefer-rest-params
- const d12 = distance(arguments, 1, 2);
- const d012 = d01 + d12;
- return [
- x2 - v[0] * tension * d01 / d012, y2 - v[1] * tension * d01 / d012,
- x2 + v[0] * tension * d12 / d012, y2 + v[1] * tension * d12 / d012,
- ];
- };
- const pts: any[] = [];
- for (const pt of points) {
- pts.push(pt[0]);
- pts.push(pt[1]);
- }
- let cps = [];
- for (let i = 0; i < pts.length - 2; i += 1) {
- // @ts-ignore
- cps = cps.concat(ctlpts(pts[2 * i + 0], pts[2 * i + 1], pts[2 * i + 2], pts[2 * i + 3], pts[2 * i + 4], pts[2 * i + 5]));
- }
- ctx.lineWidth = options.lineWidth;
- ctx.strokeStyle = options.color;
- if (points.length === 2) {
- ctx.beginPath();
- ctx.moveTo(pts[0], pts[1]);
- ctx.lineTo(pts[2], pts[3]);
- } else {
- ctx.beginPath();
- ctx.moveTo(pts[0], pts[1]);
- // first segment is a quadratic
- ctx.quadraticCurveTo(cps[0], cps[1], pts[2], pts[3]);
- // for all middle points, connect with bezier
- let i;
- for (i = 2; i < ((pts.length / 2) - 1); i += 1) {
- ctx.bezierCurveTo(cps[(2 * (i - 1) - 1) * 2], cps[(2 * (i - 1) - 1) * 2 + 1], cps[(2 * (i - 1)) * 2], cps[(2 * (i - 1)) * 2 + 1], pts[i * 2], pts[i * 2 + 1]);
- }
- // last segment is a quadratic
- ctx.quadraticCurveTo(cps[(2 * (i - 1) - 1) * 2], cps[(2 * (i - 1) - 1) * 2 + 1], pts[i * 2], pts[i * 2 + 1]);
- }
- ctx.stroke();
}
export async function gesture(inCanvas, result) {
@@ -193,7 +116,9 @@ export async function face(inCanvas, result) {
ctx.font = options.font;
ctx.strokeStyle = options.color;
ctx.fillStyle = options.color;
- if (options.drawBoxes) rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3]);
+ if (options.drawBoxes) {
+ rect(ctx, f.box[0], f.box[1], f.box[2], f.box[3]);
+ }
// silly hack since fillText does not suport new line
const labels:string[] = [];
labels.push(`face confidence: ${Math.trunc(100 * f.confidence)}%`);
@@ -299,82 +224,70 @@ export async function body(inCanvas, result) {
}
}
if (options.drawPolygons) {
- const path = new Path2D();
- let root;
let part;
+ const points: any[] = [];
// torso
- root = result[i].keypoints.find((a) => a.part === 'leftShoulder');
- if (root && root.score > config.body.scoreThreshold) {
- const points: any[] = [];
- points.push([root.position.x, root.position.y, 'leftShoulder']);
- part = result[i].keypoints.find((a) => a.part === 'rightShoulder');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightHip');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftHip');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftShoulder');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- lines(ctx, points);
- }
+ points.length = 0;
+ part = result[i].keypoints.find((a) => a.part === 'leftShoulder');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightShoulder');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightHip');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftHip');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftShoulder');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ if (points.length === 5) lines(ctx, points); // only draw if we have complete torso
// leg left
- root = result[i].keypoints.find((a) => a.part === 'leftHip');
- if (root && root.score > config.body.scoreThreshold) {
- const points: any[] = [];
- points.push([root.position.x, root.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftKnee');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftAnkle');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftHeel');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftFoot');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- lines(ctx, points);
- }
+ points.length = 0;
+ part = result[i].keypoints.find((a) => a.part === 'leftHip');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftKnee');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftAnkle');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftHeel');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftFoot');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ curves(ctx, points);
// leg right
- root = result[i].keypoints.find((a) => a.part === 'rightHip');
- if (root && root.score > config.body.scoreThreshold) {
- const points: any[] = [];
- points.push([root.position.x, root.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightKnee');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightAnkle');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightHeel');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightFoot');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- lines(ctx, points);
- }
+ points.length = 0;
+ part = result[i].keypoints.find((a) => a.part === 'rightHip');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightKnee');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightAnkle');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightHeel');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightFoot');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ curves(ctx, points);
// arm left
- root = result[i].keypoints.find((a) => a.part === 'leftShoulder');
- if (root && root.score > config.body.scoreThreshold) {
- const points: any[] = [];
- points.push([root.position.x, root.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftElbow');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftWrist');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'leftPalm');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- lines(ctx, points);
- }
+ points.length = 0;
+ part = result[i].keypoints.find((a) => a.part === 'leftShoulder');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftElbow');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftWrist');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'leftPalm');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ curves(ctx, points);
// arm right
- root = result[i].keypoints.find((a) => a.part === 'rightShoulder');
- if (root && root.score > config.body.scoreThreshold) {
- const points: any[] = [];
- points.push([root.position.x, root.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightElbow');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightWrist');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- part = result[i].keypoints.find((a) => a.part === 'rightPalm');
- if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
- lines(ctx, points);
- }
+ points.length = 0;
+ part = result[i].keypoints.find((a) => a.part === 'rightShoulder');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightElbow');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightWrist');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ part = result[i].keypoints.find((a) => a.part === 'rightPalm');
+ if (part && part.score > config.body.scoreThreshold) points.push([part.position.x, part.position.y]);
+ curves(ctx, points);
// draw all
- ctx.stroke(path);
}
}
}
diff --git a/src/human.ts b/src/human.ts
index 0f0b3516..2e62de50 100644
--- a/src/human.ts
+++ b/src/human.ts
@@ -1,4 +1,5 @@
import { log } from './log';
+import * as sysinfo from './sysinfo';
import * as tf from '../dist/tfjs.esm.js';
import * as backend from './tfjs/backend';
import * as facemesh from './blazeface/facemesh';
@@ -61,6 +62,7 @@ class Human {
emotion: any;
body: any;
hand: any;
+ sysinfo: any;
constructor(userConfig = {}) {
this.tf = tf;
@@ -95,6 +97,8 @@ class Human {
this.emotion = emotion;
this.body = this.config.body.modelType.startsWith('posenet') ? posenet : blazepose;
this.hand = handpose;
+ // include platform info
+ this.sysinfo = sysinfo.info();
}
profile() {
@@ -139,7 +143,11 @@ class Human {
if (userConfig) this.config = mergeDeep(this.config, userConfig);
if (this.firstRun) {
- if (this.config.debug) log(`version: ${this.version} TensorFlow/JS version: ${this.tf.version_core}`);
+ if (this.config.debug) log(`version: ${this.version}`);
+ if (this.config.debug) log(`tfjs version: ${this.tf.version_core}`);
+ if (this.config.debug) log('platform:', this.sysinfo.platform);
+ if (this.config.debug) log('agent:', this.sysinfo.agent);
+
await this.checkBackend(true);
if (this.tf.ENV.flags.IS_BROWSER) {
if (this.config.debug) log('configuration:', this.config);
@@ -206,9 +214,11 @@ class Human {
if (this.config.debug) log('setting backend:', this.config.backend);
if (this.config.backend === 'wasm') {
- if (this.config.debug) log('settings wasm path:', this.config.wasmPath);
+ if (this.config.debug) log('wasm path:', this.config.wasmPath);
this.tf.setWasmPaths(this.config.wasmPath);
const simd = await this.tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
+ const mt = await this.tf.env().getAsync('WASM_HAS_MULTITHREAD_SUPPORT');
+ if (this.config.debug) log(`wasm execution: ${simd ? 'SIMD' : 'no SIMD'} ${mt ? 'multithreaded' : 'singlethreaded'}`);
if (!simd) log('warning: wasm simd support is not enabled');
}
@@ -538,7 +548,7 @@ class Human {
else res = await this.warmupNode();
this.config.videoOptimized = video;
const t1 = now();
- if (this.config.debug) log('Warmup', this.config.warmup, Math.round(t1 - t0), 'ms', res);
+ if (this.config.debug) log('Warmup', this.config.warmup, Math.round(t1 - t0), 'ms');
return res;
}
}
diff --git a/wiki b/wiki
index ce4f3e12..562a698d 160000
--- a/wiki
+++ b/wiki
@@ -1 +1 @@
-Subproject commit ce4f3e12bd49ee404186c55ab977b4b1612d17f4
+Subproject commit 562a698daecaecf8580120fc4e1c9b6ac66ba537