From 18a4789639163fa57f652b64a042a8f302e245ac Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Sat, 6 Mar 2021 10:38:04 -0500 Subject: [PATCH] add curve draw output --- config.js | 2 +- demo/browser.js | 23 ++-- demo/gl-bench.js | 2 +- demo/menu.js | 2 +- demo/node.js | 26 ++--- package.json | 2 +- src/draw.ts | 265 ++++++++++++++++------------------------------- src/human.ts | 16 ++- wiki | 2 +- 9 files changed, 134 insertions(+), 206 deletions(-) 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