add curve draw output

pull/293/head
Vladimir Mandic 2021-03-06 10:38:04 -05:00
parent 988f7a7cbd
commit b9dddcdd0a
9 changed files with 134 additions and 206 deletions

View File

@ -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

View File

@ -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('<hr style="border-style: inset; border-color: dimgray">');
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('<hr style="border-style: inset; border-color: dimgray">');
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) {

View File

@ -20,7 +20,7 @@ const UISVG = `
<svg viewBox="0 0 55 60">
<text x="27" y="56" class="gl-fps">00 FPS</text>
<text x="30" y="8" class="gl-mem"></text>
<rect x="0" y="14" rx="4" ry="4" width="55" height="32"></rect>
<rect x="0" y="14" rx="4" ry="4" width="65" height="32"></rect>
<polyline class="gl-chart"></polyline>
</svg>
<svg viewBox="0 0 14 60" class="gl-cpu-svg">

View File

@ -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; }

View File

@ -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) {

View File

@ -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",

View File

@ -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);
}
}
}

View File

@ -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;
}
}

2
wiki

@ -1 +1 @@
Subproject commit ce4f3e12bd49ee404186c55ab977b4b1612d17f4
Subproject commit 562a698daecaecf8580120fc4e1c9b6ac66ba537