Compare commits

...

24 Commits
3.2.1 ... main

Author SHA1 Message Date
Vladimir Mandic a6fd9a41c1 update readme
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2025-02-05 10:11:17 -05:00
Vladimir Mandic 7e7c6d2ea2 update compatibility notes
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2025-02-05 09:50:45 -05:00
Vladimir Mandic 5208b9ec2d full rebuild
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2025-02-05 09:41:58 -05:00
Vladimir Mandic f515b9c20d 3.3.5 2025-02-05 09:29:56 -05:00
Vladimir Mandic 5a51889edb update build platform
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2025-02-05 09:29:47 -05:00
Vladimir Mandic 745fd626a3 rebuild
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2024-10-24 11:11:55 -04:00
Vladimir Mandic c1dc719a67 add human.draw.tensor method
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2024-10-24 11:09:45 -04:00
Vladimir Mandic 2b0a2fecc2 3.3.4 2024-10-24 11:09:27 -04:00
Vladimir Mandic 38922fe92d update packages
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2024-10-14 09:06:22 -04:00
Vladimir Mandic c80540a934 3.3.3 2024-10-14 09:05:49 -04:00
Vladimir Mandic 49b25830b4 add loaded property to model stats and mark models not loaded correctly.
Signed-off-by: Vladimir Mandic <mandic00@live.com>
2024-10-14 09:04:10 -04:00
Vladimir Mandic df73c8247f update changelog 2024-09-11 12:16:59 -04:00
Vladimir Mandic dd186ab065 release build 2024-09-11 12:16:36 -04:00
Vladimir Mandic a2acfc433e 3.3.2 2024-09-11 12:14:26 -04:00
Vladimir Mandic 644235433d full rebuild 2024-09-11 12:13:42 -04:00
Vladimir Mandic 42dfe18736 update face roll/pitch/yaw math 2024-09-11 12:13:03 -04:00
Vladimir Mandic c5b7b43fca 3.3.1 2024-09-11 11:23:18 -04:00
Vladimir Mandic 715210db51 add config.face.detector.square option 2024-09-11 11:16:07 -04:00
Vladimir Mandic 9e2c612c1f human 3.3 alpha test run 2024-09-10 15:49:23 -04:00
Vladimir Mandic 862de3e6c8 human 3.3 alpha with new build environment 2024-09-10 15:44:39 -04:00
Vladimir Mandic 1114014bfd update changelog 2024-04-17 11:37:23 -04:00
Vladimir Mandic 001a3d58ea release rebuild 2024-04-17 11:36:54 -04:00
Vladimir Mandic d7e66afe1f fix flazeface tensor scale and update build platform 2024-04-17 11:29:51 -04:00
Vladimir Mandic a2fedaba40 3.2.2 2024-04-17 10:31:25 -04:00
165 changed files with 19809 additions and 24578 deletions

View File

@ -1,9 +1,8 @@
{ {
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json", "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
"mainEntryPointFilePath": "types/lib/src/human.d.ts", "mainEntryPointFilePath": "types/lib/src/human.d.ts",
"bundledPackages": ["@tensorflow/tfjs-core", "@tensorflow/tfjs-data", "@tensorflow/tfjs-layers", "@tensorflow/tfjs-converter"],
"compiler": { "compiler": {
"skipLibCheck": false "skipLibCheck": true
}, },
"newlineKind": "lf", "newlineKind": "lf",
"dtsRollup": { "dtsRollup": {

View File

@ -1,5 +1,9 @@
{ {
"globals": {}, "globals": {
},
"rules": {
"@typescript-eslint/no-require-imports":"off"
},
"overrides": [ "overrides": [
{ {
"files": ["**/*.ts"], "files": ["**/*.ts"],
@ -34,6 +38,8 @@
"@typescript-eslint/no-unsafe-call":"off", "@typescript-eslint/no-unsafe-call":"off",
"@typescript-eslint/no-unsafe-member-access":"off", "@typescript-eslint/no-unsafe-member-access":"off",
"@typescript-eslint/no-unsafe-return":"off", "@typescript-eslint/no-unsafe-return":"off",
"@typescript-eslint/no-require-imports":"off",
"@typescript-eslint/no-empty-object-type":"off",
"@typescript-eslint/non-nullable-type-assertion-style":"off", "@typescript-eslint/non-nullable-type-assertion-style":"off",
"@typescript-eslint/prefer-for-of":"off", "@typescript-eslint/prefer-for-of":"off",
"@typescript-eslint/prefer-nullish-coalescing":"off", "@typescript-eslint/prefer-nullish-coalescing":"off",
@ -155,9 +161,7 @@
"node": false, "node": false,
"es2021": false "es2021": false
}, },
"extends": [ "extends": []
"plugin:json/recommended"
]
}, },
{ {
"files": ["**/*.html"], "files": ["**/*.html"],
@ -173,6 +177,7 @@
"extends": ["plugin:@html-eslint/recommended"], "extends": ["plugin:@html-eslint/recommended"],
"rules": { "rules": {
"@html-eslint/element-newline":"off", "@html-eslint/element-newline":"off",
"@html-eslint/attrs-newline":"off",
"@html-eslint/indent": ["error", 2] "@html-eslint/indent": ["error", 2]
} }
}, },

2
.gitignore vendored
View File

@ -5,3 +5,5 @@ package-lock.json
*.swp *.swp
samples/**/*.mp4 samples/**/*.mp4
samples/**/*.webm samples/**/*.webm
temp
tmp

1
.npmrc
View File

@ -2,3 +2,4 @@ force=true
omit=dev omit=dev
legacy-peer-deps=true legacy-peer-deps=true
strict-peer-dependencies=false strict-peer-dependencies=false
node-options='--no-deprecation'

View File

@ -1,6 +1,6 @@
# @vladmandic/human # @vladmandic/human
Version: **3.2.1** Version: **3.3.5**
Description: **Human: AI-powered 3D Face Detection & Rotation Tracking, Face Description & Recognition, Body Pose Tracking, 3D Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction, Gesture Recognition** Description: **Human: AI-powered 3D Face Detection & Rotation Tracking, Face Description & Recognition, Body Pose Tracking, 3D Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction, Gesture Recognition**
Author: **Vladimir Mandic <mandic00@live.com>** Author: **Vladimir Mandic <mandic00@live.com>**
@ -9,12 +9,42 @@
## Changelog ## Changelog
### **3.3.5** 2025/02/05 mandic00@live.com
### **origin/main** 2024/10/24 mandic00@live.com
- add human.draw.tensor method
### **3.3.4** 2024/10/24 mandic00@live.com
### **3.3.3** 2024/10/14 mandic00@live.com
- add loaded property to model stats and mark models not loaded correctly.
- release build
### **3.3.2** 2024/09/11 mandic00@live.com
- full rebuild
### **3.3.1** 2024/09/11 mandic00@live.com
- add config.face.detector.square option
- human 3.3 alpha test run
- human 3.3 alpha with new build environment
- release rebuild
- fix flazeface tensor scale and update build platform
### **3.2.2** 2024/04/17 mandic00@live.com
### **release: 3.2.1** 2024/02/15 mandic00@live.com
### **3.2.1** 2024/02/15 mandic00@live.com ### **3.2.1** 2024/02/15 mandic00@live.com
### **origin/main** 2023/12/06 mandic00@live.com
### **3.2.0** 2023/12/06 mandic00@live.com ### **3.2.0** 2023/12/06 mandic00@live.com
- set browser false when navigator object is empty - set browser false when navigator object is empty

View File

@ -4,7 +4,6 @@
![Last Commit](https://img.shields.io/github/last-commit/vladmandic/human?style=flat-square&svg=true) ![Last Commit](https://img.shields.io/github/last-commit/vladmandic/human?style=flat-square&svg=true)
![License](https://img.shields.io/github/license/vladmandic/human?style=flat-square&svg=true) ![License](https://img.shields.io/github/license/vladmandic/human?style=flat-square&svg=true)
![GitHub Status Checks](https://img.shields.io/github/checks-status/vladmandic/human/main?style=flat-square&svg=true) ![GitHub Status Checks](https://img.shields.io/github/checks-status/vladmandic/human/main?style=flat-square&svg=true)
![Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/vladmandic/human?style=flat-square&svg=true)
# Human Library # Human Library
@ -31,15 +30,20 @@
## Compatibility ## Compatibility
- **Browser**: **Browser**:
Compatible with both desktop and mobile platforms - Compatible with both desktop and mobile platforms
Compatible with *CPU*, *WebGL*, *WASM* backends - Compatible with *WebGPU*, *WebGL*, *WASM*, *CPU* backends
Compatible with *WebWorker* execution - Compatible with *WebWorker* execution
Compatible with *WebView* - Compatible with *WebView*
- **NodeJS**: - Primary platform: *Chromium*-based browsers
Compatibile with *WASM* backend for executions on architectures where *tensorflow* binaries are not available - Secondary platform: *Firefox*, *Safari*
Compatible with *tfjs-node* using software execution via *tensorflow* shared libraries
Compatible with *tfjs-node* using GPU-accelerated execution via *tensorflow* shared libraries and nVidia CUDA **NodeJS**:
- Compatibile with *WASM* backend for executions on architectures where *tensorflow* binaries are not available
- Compatible with *tfjs-node* using software execution via *tensorflow* shared libraries
- Compatible with *tfjs-node* using GPU-accelerated execution via *tensorflow* shared libraries and nVidia CUDA
- Supported versions are from **14.x** to **22.x**
- NodeJS version **23.x** is not supported due to breaking changes and issues with `@tensorflow/tfjs`
<br> <br>

View File

@ -10,12 +10,13 @@ import { Human } from '../../dist/human.esm.js';
let loader; let loader;
const humanConfig = { // user configuration for human, used to fine-tune behavior const humanConfig = { // user configuration for human, used to fine-tune behavior
cacheSensitivity: 0,
debug: true, debug: true,
modelBasePath: 'https://vladmandic.github.io/human-models/models/', modelBasePath: 'https://vladmandic.github.io/human-models/models/',
filter: { enabled: true, equalization: false, flip: false }, filter: { enabled: true, equalization: false, flip: false },
face: { face: {
enabled: true, enabled: true,
detector: { rotation: false, maxDetected: 100, minConfidence: 0.2, return: true }, detector: { rotation: false, maxDetected: 100, minConfidence: 0.2, return: true, square: false },
iris: { enabled: true }, iris: { enabled: true },
description: { enabled: true }, description: { enabled: true },
emotion: { enabled: true }, emotion: { enabled: true },
@ -93,7 +94,7 @@ function addFace(face, source) {
e.preventDefault(); e.preventDefault();
document.getElementById('description').innerHTML = canvas.title; document.getElementById('description').innerHTML = canvas.title;
}; };
human.tf.browser.draw(face.tensor, canvas); human.draw.tensor(face.tensor, canvas);
human.tf.dispose(face.tensor); human.tf.dispose(face.tensor);
return canvas; return canvas;
} }
@ -149,7 +150,7 @@ async function main() {
showLoader('compiling models'); showLoader('compiling models');
await human.warmup(); await human.warmup();
showLoader('loading images'); showLoader('loading images');
const images = ['group-1.jpg', 'group-2.jpg', 'group-3.jpg', 'group-4.jpg', 'group-5.jpg', 'group-6.jpg', 'group-7.jpg', 'solvay1927.jpg', 'stock-group-1.jpg', 'stock-group-2.jpg']; const images = ['group-1.jpg', 'group-2.jpg', 'group-3.jpg', 'group-4.jpg', 'group-5.jpg', 'group-6.jpg', 'group-7.jpg', 'solvay1927.jpg', 'stock-group-1.jpg', 'stock-group-2.jpg', 'stock-models-6.jpg', 'stock-models-7.jpg'];
const imageUris = images.map((a) => `../../samples/in/${a}`); const imageUris = images.map((a) => `../../samples/in/${a}`);
for (let i = 0; i < imageUris.length; i++) addImage(imageUris[i]); for (let i = 0; i < imageUris.length; i++) addImage(imageUris[i]);
initDragAndDrop(); initDragAndDrop();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -11,7 +11,7 @@ import * as H from '../../dist/human.esm.js'; // equivalent of @vladmandic/Human
import * as indexDb from './indexdb'; // methods to deal with indexdb import * as indexDb from './indexdb'; // methods to deal with indexdb
const humanConfig = { // user configuration for human, used to fine-tune behavior const humanConfig = { // user configuration for human, used to fine-tune behavior
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: '../../models', modelBasePath: '../../models',
filter: { enabled: true, equalization: true }, // lets run with histogram equilizer filter: { enabled: true, equalization: true }, // lets run with histogram equilizer
debug: true, debug: true,
@ -240,7 +240,7 @@ async function detectFace() {
if (!current?.face?.tensor || !current?.face?.embedding) return false; if (!current?.face?.tensor || !current?.face?.embedding) return false;
console.log('face record:', current.face); // eslint-disable-line no-console console.log('face record:', current.face); // eslint-disable-line no-console
log(`detected face: ${current.face.gender} ${current.face.age || 0}y distance ${100 * (current.face.distance || 0)}cm/${Math.round(100 * (current.face.distance || 0) / 2.54)}in`); log(`detected face: ${current.face.gender} ${current.face.age || 0}y distance ${100 * (current.face.distance || 0)}cm/${Math.round(100 * (current.face.distance || 0) / 2.54)}in`);
await human.tf.browser.draw(current.face.tensor, dom.canvas); await human.draw.tensor(current.face.tensor, dom.canvas);
if (await indexDb.count() === 0) { if (await indexDb.count() === 0) {
log('face database is empty: nothing to compare face with'); log('face database is empty: nothing to compare face with');
document.body.style.background = 'black'; document.body.style.background = 'black';

View File

@ -11,7 +11,7 @@ const userConfig = {
backend: 'humangl', backend: 'humangl',
async: true, async: true,
warmup: 'none', warmup: 'none',
cacheSensitivity: 0, cacheSensitivity: 0.01,
debug: true, debug: true,
modelBasePath: '../../models/', modelBasePath: '../../models/',
deallocate: true, deallocate: true,
@ -70,7 +70,7 @@ async function selectFaceCanvas(face) {
if (face.tensor) { if (face.tensor) {
title('Sorting Faces by Similarity'); title('Sorting Faces by Similarity');
const c = document.getElementById('orig'); const c = document.getElementById('orig');
await human.tf.browser.draw(face.tensor, c); await human.draw.tensor(face.tensor, c);
const arr = db.map((rec) => rec.embedding); const arr = db.map((rec) => rec.embedding);
const res = await human.match.find(face.embedding, arr); const res = await human.match.find(face.embedding, arr);
log('Match:', db[res.index].name); log('Match:', db[res.index].name);
@ -97,7 +97,7 @@ async function selectFaceCanvas(face) {
canvas.tag.similarity = similarity; canvas.tag.similarity = similarity;
// get best match // get best match
// draw the canvas // draw the canvas
await human.tf.browser.draw(current.tensor, canvas); await human.draw.tensor(current.tensor, canvas);
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
ctx.font = 'small-caps 1rem "Lato"'; ctx.font = 'small-caps 1rem "Lato"';
ctx.fillStyle = 'rgba(0, 0, 0, 1)'; ctx.fillStyle = 'rgba(0, 0, 0, 1)';
@ -144,7 +144,7 @@ async function addFaceCanvas(index, res, fileName) {
gender: ${Math.round(100 * res.face[i].genderScore)}% ${res.face[i].gender} gender: ${Math.round(100 * res.face[i].genderScore)}% ${res.face[i].gender}
emotion: ${emotion} emotion: ${emotion}
`.replace(/ /g, ' '); `.replace(/ /g, ' ');
await human.tf.browser.draw(res.face[i].tensor, canvas); await human.draw.tensor(res.face[i].tensor, canvas);
const ctx = canvas.getContext('2d'); const ctx = canvas.getContext('2d');
if (!ctx) return; if (!ctx) return;
ctx.font = 'small-caps 0.8rem "Lato"'; ctx.font = 'small-caps 0.8rem "Lato"';

View File

@ -223,7 +223,7 @@ async function calcSimmilarity(result) {
log('setting face compare baseline:', result.face[0]); log('setting face compare baseline:', result.face[0]);
if (result.face[0].tensor) { if (result.face[0].tensor) {
const c = document.getElementById('orig'); const c = document.getElementById('orig');
human.tf.browser.draw(result.face[0].tensor, c); human.draw.tensor(result.face[0].tensor, c);
} else { } else {
document.getElementById('compare-canvas').getContext('2d').drawImage(compare.original.canvas, 0, 0, 200, 200); document.getElementById('compare-canvas').getContext('2d').drawImage(compare.original.canvas, 0, 0, 200, 200);
} }

View File

@ -7,7 +7,7 @@ const log = require('@vladmandic/pilogger'); // eslint-disable-line node/no-unpu
const canvas = require('canvas'); // eslint-disable-line node/no-unpublished-require const canvas = require('canvas'); // eslint-disable-line node/no-unpublished-require
const config = { const config = {
cacheSensitivity: 0, cacheSensitivity: 0.01,
wasmPlatformFetch: true, wasmPlatformFetch: true,
modelBasePath: 'https://vladmandic.github.io/human-models/models/', modelBasePath: 'https://vladmandic.github.io/human-models/models/',
}; };

View File

@ -92,7 +92,7 @@ async function detect(input) {
try { try {
result = await human.detect(tensor, myConfig); result = await human.detect(tensor, myConfig);
} catch (err) { } catch (err) {
log.error('caught'); log.error('caught', err);
} }
// dispose image tensor as we no longer need it // dispose image tensor as we no longer need it

View File

@ -20,7 +20,7 @@ const config = { // just enable all and leave default settings
modelBasePath: 'file://models', modelBasePath: 'file://models',
debug: true, debug: true,
softwareKernels: true, // slower but enhanced precision since face rotation can work in software mode in nodejs environments softwareKernels: true, // slower but enhanced precision since face rotation can work in software mode in nodejs environments
cacheSensitivity: 0, cacheSensitivity: 0.01,
face: { enabled: true, detector: { maxDetected: 100, minConfidence: 0.1 } }, face: { enabled: true, detector: { maxDetected: 100, minConfidence: 0.1 } },
object: { enabled: true, maxDetected: 100, minConfidence: 0.1 }, object: { enabled: true, maxDetected: 100, minConfidence: 0.1 },
gesture: { enabled: true }, gesture: { enabled: true },

View File

@ -20,7 +20,7 @@
body { font-size: 1rem; font-family: "CenturyGothic", "Segoe UI", sans-serif; font-variant: small-caps; width: -webkit-fill-available; height: 100%; background: black; color: white; overflow: hidden; margin: 0; } body { font-size: 1rem; font-family: "CenturyGothic", "Segoe UI", sans-serif; font-variant: small-caps; width: -webkit-fill-available; height: 100%; background: black; color: white; overflow: hidden; margin: 0; }
select { font-size: 1rem; font-family: "CenturyGothic", "Segoe UI", sans-serif; font-variant: small-caps; background: gray; color: white; border: none; } select { font-size: 1rem; font-family: "CenturyGothic", "Segoe UI", sans-serif; font-variant: small-caps; background: gray; color: white; border: none; }
</style> </style>
<script src="../segmentation/index.js" type="module"></script> <script src="../segmentation/index.js" type="module"></script>
</head> </head>
<body> <body>
<noscript><h1>javascript is required</h1></noscript> <noscript><h1>javascript is required</h1></noscript>

View File

@ -85,7 +85,7 @@ async function main() {
return; return;
} }
dom.fps.innerText = `fps: ${Math.round(10000 / (t1 - t0)) / 10}`; // mark performance dom.fps.innerText = `fps: ${Math.round(10000 / (t1 - t0)) / 10}`; // mark performance
human.tf.browser.draw(rgba, dom.output); // draw raw output human.draw.tensor(rgba, dom.output); // draw raw output
human.tf.dispose(rgba); // dispose tensors human.tf.dispose(rgba); // dispose tensors
ctxMerge.globalCompositeOperation = 'source-over'; ctxMerge.globalCompositeOperation = 'source-over';
ctxMerge.drawImage(dom.background, 0, 0); // draw original video to first stacked canvas ctxMerge.drawImage(dom.background, 0, 0); // draw original video to first stacked canvas

File diff suppressed because one or more lines are too long

32293
dist/human.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1436
dist/human.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

22
dist/human.node.js vendored

File diff suppressed because one or more lines are too long

1448
dist/tfjs.esm.js vendored

File diff suppressed because one or more lines are too long

View File

@ -4,4 +4,4 @@
author: <https://github.com/vladmandic>' author: <https://github.com/vladmandic>'
*/ */
var e="4.17.0";var s="4.17.0";var t="4.17.0";var n="4.17.0";var r="4.17.0";var i="4.14.0";var h={tfjs:e,"tfjs-core":e,"tfjs-converter":s,"tfjs-backend-cpu":t,"tfjs-backend-webgl":n,"tfjs-backend-wasm":r,"tfjs-backend-webgpu":i};export{h as version}; var e="4.22.0";var s="4.22.0";var t="4.22.0";var n="4.22.0";var r="4.22.0";var i="4.22.0";var h={tfjs:e,"tfjs-core":e,"tfjs-converter":s,"tfjs-backend-cpu":t,"tfjs-backend-webgl":n,"tfjs-backend-wasm":r,"tfjs-backend-webgpu":i};export{h as version};

View File

@ -1,6 +1,6 @@
{ {
"name": "@vladmandic/human", "name": "@vladmandic/human",
"version": "3.2.1", "version": "3.3.5",
"description": "Human: AI-powered 3D Face Detection & Rotation Tracking, Face Description & Recognition, Body Pose Tracking, 3D Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction, Gesture Recognition", "description": "Human: AI-powered 3D Face Detection & Rotation Tracking, Face Description & Recognition, Body Pose Tracking, 3D Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction, Gesture Recognition",
"sideEffects": false, "sideEffects": false,
"main": "dist/human.node.js", "main": "dist/human.node.js",
@ -8,13 +8,7 @@
"browser": "dist/human.esm.js", "browser": "dist/human.esm.js",
"types": "types/human.d.ts", "types": "types/human.d.ts",
"exports": { "exports": {
"node": { "node": "./dist/human.node.js",
"require": "./dist/human.node.js",
"import": "./dist/human.node.js",
"module": "./dist/human.node.js"
},
"require": "./dist/human.node.js",
"import": "./dist/human.esm.js",
"script": "./dist/human.js", "script": "./dist/human.js",
"module": "./dist/human.esm.js", "module": "./dist/human.esm.js",
"types": "./types/human.d.ts", "types": "./types/human.d.ts",
@ -29,7 +23,9 @@
"dist/human.node-wasm": "./dist/human.node-wasm.js", "dist/human.node-wasm": "./dist/human.node-wasm.js",
"dist/human.node-wasm.js": "./dist/human.node-wasm.js", "dist/human.node-wasm.js": "./dist/human.node-wasm.js",
"dist/human.node-gpu": "./dist/human.node-gpu.js", "dist/human.node-gpu": "./dist/human.node-gpu.js",
"dist/human.node-gpu.js": "./dist/human.node-gpu.js" "dist/human.node-gpu.js": "./dist/human.node-gpu.js",
"require": "./dist/human.node.js",
"import": "./dist/human.esm.js"
}, },
"author": "Vladimir Mandic <mandic00@live.com>", "author": "Vladimir Mandic <mandic00@live.com>",
"bugs": { "bugs": {
@ -78,39 +74,40 @@
"tensorflow" "tensorflow"
], ],
"devDependencies": { "devDependencies": {
"@html-eslint/eslint-plugin": "^0.21.0", "@html-eslint/eslint-plugin": "^0.26.0",
"@html-eslint/parser": "^0.21.0", "@html-eslint/parser": "^0.26.0",
"@microsoft/api-extractor": "^7.40.1", "@microsoft/api-extractor": "^7.49.2",
"@tensorflow/tfjs-backend-cpu": "^4.17.0", "@tensorflow/tfjs-backend-cpu": "^4.22.0",
"@tensorflow/tfjs-backend-wasm": "^4.17.0", "@tensorflow/tfjs-backend-wasm": "^4.22.0",
"@tensorflow/tfjs-backend-webgl": "^4.17.0", "@tensorflow/tfjs-backend-webgl": "^4.22.0",
"@tensorflow/tfjs-backend-webgpu": "4.14.0", "@tensorflow/tfjs-backend-webgpu": "4.22.0",
"@tensorflow/tfjs-converter": "^4.17.0", "@tensorflow/tfjs-converter": "^4.22.0",
"@tensorflow/tfjs-core": "^4.17.0", "@tensorflow/tfjs-core": "^4.22.0",
"@tensorflow/tfjs-data": "^4.17.0", "@tensorflow/tfjs-data": "^4.22.0",
"@tensorflow/tfjs-layers": "^4.17.0", "@tensorflow/tfjs-layers": "^4.22.0",
"@tensorflow/tfjs-node": "^4.17.0", "@tensorflow/tfjs-node": "^4.22.0",
"@tensorflow/tfjs-node-gpu": "^4.17.0", "@tensorflow/tfjs-node-gpu": "^4.22.0",
"@types/node": "^20.11.19", "@types/emscripten": "^1.40.0",
"@types/node": "^22.13.1",
"@types/offscreencanvas": "^2019.7.3", "@types/offscreencanvas": "^2019.7.3",
"@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/eslint-plugin": "^8.8.1",
"@typescript-eslint/parser": "^6.21.0", "@typescript-eslint/parser": "^8.8.1",
"@vladmandic/build": "^0.9.3", "@vladmandic/build": "^0.10.2",
"@vladmandic/pilogger": "^0.4.9", "@vladmandic/pilogger": "^0.5.1",
"@vladmandic/tfjs": "github:vladmandic/tfjs", "@vladmandic/tfjs": "github:vladmandic/tfjs",
"canvas": "^2.11.2", "canvas": "^3.1.0",
"esbuild": "^0.19.12", "esbuild": "^0.24.2",
"eslint": "8.55.0", "eslint": "8.57.0",
"eslint-config-airbnb-base": "^15.0.0", "eslint-config-airbnb-base": "^15.0.0",
"eslint-plugin-html": "^7.1.0", "eslint-plugin-html": "^8.1.2",
"eslint-plugin-import": "^2.29.1", "eslint-plugin-import": "^2.31.0",
"eslint-plugin-json": "^3.1.0", "eslint-plugin-json": "^4.0.1",
"eslint-plugin-markdown": "^3.0.1", "eslint-plugin-markdown": "^5.1.0",
"eslint-plugin-node": "^11.1.0", "eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^7.1.0",
"rimraf": "^5.0.5", "rimraf": "^6.0.1",
"tslib": "^2.6.2", "tslib": "^2.8.1",
"typedoc": "0.25.4", "typedoc": "0.27.6",
"typescript": "~5.3.3" "typescript": "5.7.3"
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 145 KiB

After

Width:  |  Height:  |  Size: 150 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

@ -1,7 +1,7 @@
/* eslint-disable no-multi-spaces */ /* eslint-disable no-multi-spaces */
/** Possible TensorFlow backends */ /** Possible TensorFlow backends */
export type BackendEnum = '' | 'cpu' | 'wasm' | 'webgl' | 'humangl' | 'tensorflow' | 'webgpu'; export type BackendEnum = '' | 'cpu' | 'wasm' | 'webgl' | 'humangl' | 'tensorflow' | 'webgpu' | 'none';
/** Possible values for `human.warmup` */ /** Possible values for `human.warmup` */
export type WarmupEnum = '' | 'none' | 'face' | 'full' | 'body'; export type WarmupEnum = '' | 'none' | 'face' | 'full' | 'body';
@ -39,6 +39,8 @@ export interface FaceDetectorConfig extends GenericConfig {
iouThreshold: number, iouThreshold: number,
/** how much should face box be enlarged over the min/max facial coordinates */ /** how much should face box be enlarged over the min/max facial coordinates */
scale: number, scale: number,
/** automatically pad image to square */
square: boolean,
/** should child models perform on masked image of a face */ /** should child models perform on masked image of a face */
mask: boolean, mask: boolean,
/** should face detection return processed and cropped face tensor that can with an external model for addtional processing? /** should face detection return processed and cropped face tensor that can with an external model for addtional processing?

View File

@ -2,6 +2,7 @@
* Module that implements helper draw functions, exposed as human.draw * Module that implements helper draw functions, exposed as human.draw
*/ */
import * as tf from 'dist/tfjs.esm.js';
import { mergeDeep, now } from '../util/util'; import { mergeDeep, now } from '../util/util';
import { env } from '../util/env'; import { env } from '../util/env';
import { getCanvasContext, rect } from './primitives'; import { getCanvasContext, rect } from './primitives';
@ -14,6 +15,7 @@ import { gesture } from './gesture';
import { defaultLabels } from './labels'; import { defaultLabels } from './labels';
import type { Result, PersonResult } from '../result'; import type { Result, PersonResult } from '../result';
import type { AnyCanvas, DrawOptions } from '../exports'; import type { AnyCanvas, DrawOptions } from '../exports';
import type { Tensor2D } from '../tfjs/types';
let drawTime = 0; let drawTime = 0;
@ -60,6 +62,22 @@ export function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, o
ctx.drawImage(input, 0, 0); ctx.drawImage(input, 0, 0);
} }
/** draw processed canvas */
export async function tensor(input: Tensor2D, output: HTMLCanvasElement) {
if (!input || !output) return;
if (!env.browser) return;
// const backend = tf.getBackend();
// if (backend === 'webgpu') tf.browser.draw(input, output);
// else await tf.browser.toPixels(input, output);
await tf.browser.toPixels(input, output);
// const ctx = getCanvasContext(output) as CanvasRenderingContext2D;
// if (!ctx) return;
// const image = await process(input);
// result.canvas = image.canvas;
// human.tf.dispose(image.tensor);
// ctx.drawImage(image.canvas, 0, 0);
}
/** meta-function that performs draw for: canvas, face, body, hand */ /** meta-function that performs draw for: canvas, face, body, hand */
export async function all(inCanvas: AnyCanvas, result: Result, drawOptions?: Partial<DrawOptions>) { export async function all(inCanvas: AnyCanvas, result: Result, drawOptions?: Partial<DrawOptions>) {
if (!result?.performance || !inCanvas) return null; if (!result?.performance || !inCanvas) return null;

View File

@ -60,7 +60,9 @@ export const calculateFaceAngle = (face: FaceResult, imageSize: [number, number]
let thetaZ: number; let thetaZ: number;
if (r10 < 1) { // YZX calculation if (r10 < 1) { // YZX calculation
if (r10 > -1) { if (r10 > -1) {
thetaZ = Math.asin(r10); // thetaZ = Math.asin(r10);
const cosThetaZ = Math.sqrt(r00 * r00 + r20 * r20); // <https://github.com/vladmandic/human/issues/464>
thetaZ = Math.atan2(r10, cosThetaZ);
thetaY = Math.atan2(-r20, r00); thetaY = Math.atan2(-r20, r00);
thetaX = Math.atan2(-r12, r11); thetaX = Math.atan2(-r12, r11);
} else { } else {
@ -76,9 +78,9 @@ export const calculateFaceAngle = (face: FaceResult, imageSize: [number, number]
if (Number.isNaN(thetaX)) thetaX = 0; if (Number.isNaN(thetaX)) thetaX = 0;
if (Number.isNaN(thetaY)) thetaY = 0; if (Number.isNaN(thetaY)) thetaY = 0;
if (Number.isNaN(thetaZ)) thetaZ = 0; if (Number.isNaN(thetaZ)) thetaZ = 0;
return { pitch: 2 * -thetaX, yaw: 2 * -thetaY, roll: 2 * -thetaZ }; // return { pitch: 2 * -thetaX, yaw: 2 * -thetaY, roll: 2 * -thetaZ };
return { pitch: -thetaX, yaw: -thetaY, roll: -thetaZ };
}; };
/* /*
const meshToEulerAngle = (mesh) => { // simple Euler angle calculation based existing 3D mesh const meshToEulerAngle = (mesh) => { // simple Euler angle calculation based existing 3D mesh
const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1); const radians = (a1, a2, b1, b2) => Math.atan2(b2 - a2, b1 - a1);

View File

@ -55,9 +55,20 @@ export async function getBoxes(inputImage: Tensor4D, config: Config): Promise<De
// sanity check on input // sanity check on input
if ((!inputImage) || (inputImage['isDisposedInternal']) || (inputImage.shape.length !== 4) || (inputImage.shape[1] < 1) || (inputImage.shape[2] < 1)) return []; if ((!inputImage) || (inputImage['isDisposedInternal']) || (inputImage.shape.length !== 4) || (inputImage.shape[1] < 1) || (inputImage.shape[2] < 1)) return [];
const t: Record<string, Tensor> = {}; const t: Record<string, Tensor> = {};
t.resized = tf.image.resizeBilinear(inputImage, [inputSize, inputSize]); let pad = [0, 0];
let scale = [1, 1];
if (config?.face?.detector?.square) {
const xy = Math.max(inputImage.shape[2], inputImage.shape[1]);
pad = [Math.floor((xy - inputImage.shape[2]) / 2), Math.floor((xy - inputImage.shape[1]) / 2)];
t.padded = tf.pad(inputImage, [[0, 0], [pad[1], pad[1]], [pad[0], pad[0]], [0, 0]]);
scale = [inputImage.shape[2] / xy, inputImage.shape[1] / xy];
pad = [pad[0] / inputSize, pad[1] / inputSize];
} else {
t.padded = inputImage.clone();
}
t.resized = tf.image.resizeBilinear(t.padded as Tensor4D, [inputSize, inputSize]);
t.div = tf.div(t.resized, constants.tf127); t.div = tf.div(t.resized, constants.tf127);
t.normalized = tf.sub(t.div, constants.tf05); t.normalized = tf.sub(t.div, constants.tf1);
const res = model?.execute(t.normalized) as Tensor[]; const res = model?.execute(t.normalized) as Tensor[];
if (Array.isArray(res) && res.length > 2) { // pinto converted model? if (Array.isArray(res) && res.length > 2) { // pinto converted model?
const sorted = res.sort((a, b) => a.size - b.size); const sorted = res.sort((a, b) => a.size - b.size);
@ -81,7 +92,6 @@ export async function getBoxes(inputImage: Tensor4D, config: Config): Promise<De
const scores = await t.scores.data(); const scores = await t.scores.data();
for (let i = 0; i < nms.length; i++) { for (let i = 0; i < nms.length; i++) {
const confidence = scores[nms[i]]; const confidence = scores[nms[i]];
if (confidence > (config.face.detector?.minConfidence || 0)) { if (confidence > (config.face.detector?.minConfidence || 0)) {
const b: Record<string, Tensor> = {}; const b: Record<string, Tensor> = {};
b.bbox = tf.slice(t.boxes, [nms[i], 0], [1, -1]); b.bbox = tf.slice(t.boxes, [nms[i], 0], [1, -1]);
@ -89,9 +99,15 @@ export async function getBoxes(inputImage: Tensor4D, config: Config): Promise<De
b.squeeze = tf.squeeze(b.slice); b.squeeze = tf.squeeze(b.slice);
b.landmarks = tf.reshape(b.squeeze, [keypointsCount, -1]); b.landmarks = tf.reshape(b.squeeze, [keypointsCount, -1]);
const points = await b.bbox.data(); const points = await b.bbox.data();
const unpadded = [ // TODO fix this math
points[0] * scale[0] - pad[0],
points[1] * scale[1] - pad[1],
points[2] * scale[0] - pad[0],
points[3] * scale[1] - pad[1],
];
const rawBox = { const rawBox = {
startPoint: [points[0], points[1]] as Point, startPoint: [unpadded[0], unpadded[1]] as Point,
endPoint: [points[2], points[3]] as Point, endPoint: [unpadded[2], unpadded[3]] as Point,
landmarks: (await b.landmarks.array()) as Point[], landmarks: (await b.landmarks.array()) as Point[],
confidence, confidence,
}; };

View File

@ -17,7 +17,8 @@ export function distance(descriptor1: Descriptor, descriptor2: Descriptor, optio
const diff = (!options.order || options.order === 2) ? (descriptor1[i] - descriptor2[i]) : (Math.abs(descriptor1[i] - descriptor2[i])); const diff = (!options.order || options.order === 2) ? (descriptor1[i] - descriptor2[i]) : (Math.abs(descriptor1[i] - descriptor2[i]));
sum += (!options.order || options.order === 2) ? (diff * diff) : (diff ** options.order); sum += (!options.order || options.order === 2) ? (diff * diff) : (diff ** options.order);
} }
return (options.multiplier || 20) * sum; const dist = Math.round(100 * (options.multiplier || 20) * sum) / 100;
return dist;
} }
// invert distance to similarity, normalize to given range and clamp // invert distance to similarity, normalize to given range and clamp
@ -25,7 +26,7 @@ const normalizeDistance = (dist, order, min, max) => {
if (dist === 0) return 1; // short circuit for identical inputs if (dist === 0) return 1; // short circuit for identical inputs
const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order); // take root of distance const root = order === 2 ? Math.sqrt(dist) : dist ** (1 / order); // take root of distance
const norm = (1 - (root / 100) - min) / (max - min); // normalize to range const norm = (1 - (root / 100) - min) / (max - min); // normalize to range
const clamp = Math.max(Math.min(norm, 1), 0); // clamp to 0..1 const clamp = Math.round(100 * Math.max(Math.min(norm, 1), 0)) / 100; // clamp to 0..1
return clamp; return clamp;
}; };

View File

@ -290,7 +290,6 @@ const checksum = async (input: Tensor): Promise<number> => { // use tf sum or js
export async function skip(config: Partial<Config>, input: Tensor) { export async function skip(config: Partial<Config>, input: Tensor) {
let skipFrame = false; let skipFrame = false;
if (config.cacheSensitivity === 0 || !input.shape || input.shape.length !== 4 || input.shape[1] > 3840 || input.shape[2] > 2160) return skipFrame; // cache disabled or input is invalid or too large for cache analysis if (config.cacheSensitivity === 0 || !input.shape || input.shape.length !== 4 || input.shape[1] > 3840 || input.shape[2] > 2160) return skipFrame; // cache disabled or input is invalid or too large for cache analysis
/* /*
const checkSum = await checksum(input); const checkSum = await checksum(input);
const diff = 100 * (Math.max(checkSum, last.inputSum) / Math.min(checkSum, last.inputSum) - 1); const diff = 100 * (Math.max(checkSum, last.inputSum) / Math.min(checkSum, last.inputSum) - 1);

View File

@ -27,7 +27,7 @@ class GLProgram {
this.gl = gl; this.gl = gl;
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER); const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER); const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
this.id = this.gl.createProgram() as WebGLProgram; this.id = this.gl.createProgram();
if (!vertexShader || !fragmentShader) return; if (!vertexShader || !fragmentShader) return;
if (!this.id) { if (!this.id) {
log('filter: could not create webgl program'); log('filter: could not create webgl program');

View File

@ -100,13 +100,13 @@ export class Models {
let totalSizeWeights = 0; let totalSizeWeights = 0;
let totalSizeLoading = 0; let totalSizeLoading = 0;
for (const m of Object.values(modelStats)) { for (const m of Object.values(modelStats)) {
totalSizeFromManifest += m.sizeFromManifest; totalSizeFromManifest += Number.isNaN(+m.sizeFromManifest) ? 0 : m.sizeFromManifest;
totalSizeWeights += m.sizeLoadedWeights; totalSizeWeights += Number.isNaN(+m.sizeLoadedWeights) ? 0 : m.sizeLoadedWeights;
totalSizeLoading += m.sizeDesired; totalSizeLoading += Number.isNaN(+m.sizeDesired) ? 0 : m.sizeDesired;
} }
const percentageLoaded = totalSizeLoading > 0 ? totalSizeWeights / totalSizeLoading : 0; const percentageLoaded = totalSizeLoading > 0 ? totalSizeWeights / totalSizeLoading : 0;
return { return {
numLoadedModels: Object.values(modelStats).length, numLoadedModels: Object.values(modelStats).filter((m) => m?.loaded).length,
numDefinedModels: Object.keys(this.models).length, numDefinedModels: Object.keys(this.models).length,
percentageLoaded, percentageLoaded,
totalSizeFromManifest, totalSizeFromManifest,
@ -178,7 +178,7 @@ export class Models {
return models; return models;
} }
loaded() { loaded(): string[] {
const list = this.list(); const list = this.list();
const loaded = list.filter((model) => model.loaded).map((model) => model.name); const loaded = list.filter((model) => model.loaded).map((model) => model.name);
return loaded; return loaded;

View File

@ -3,7 +3,7 @@
*/ */
// data:image/jpeg;base64, // data:image/jpeg;base64,
export const face = ` export const face: string = `
/9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUA /9j/4AAQSkZJRgABAQEAYABgAAD/4QBoRXhpZgAATU0AKgAAAAgABAEaAAUAAAABAAAAPgEbAAUA
AAABAAAARgEoAAMAAAABAAIAAAExAAIAAAARAAAATgAAAAAAAABgAAAAAQAAAGAAAAABcGFpbnQu AAABAAAARgEoAAMAAAABAAIAAAExAAIAAAARAAAATgAAAAAAAABgAAAAAQAAAGAAAAABcGFpbnQu
bmV0IDQuMi4xMwAA/9sAQwAGBAUGBQQGBgUGBwcGCAoQCgoJCQoUDg8MEBcUGBgXFBYWGh0lHxob bmV0IDQuMi4xMwAA/9sAQwAGBAUGBQQGBgUGBwcGCAoQCgoJCQoUDg8MEBcUGBgXFBYWGh0lHxob

View File

@ -121,14 +121,17 @@ export async function check(instance: Human, force = false) {
log('override: backend set to webgpu but browser does not support webgpu'); log('override: backend set to webgpu but browser does not support webgpu');
instance.config.backend = 'webgl'; instance.config.backend = 'webgl';
} else { } else {
const adapter = await navigator.gpu.requestAdapter(); const adapter: GPUAdapter = await navigator.gpu.requestAdapter() as GPUAdapter;
if (instance.config.debug) log('enumerated webgpu adapter:', adapter); if (instance.config.debug) log('enumerated webgpu adapter:', adapter);
if (!adapter) { if (!adapter) {
log('override: backend set to webgpu but browser reports no available gpu'); log('override: backend set to webgpu but browser reports no available gpu');
instance.config.backend = 'webgl'; instance.config.backend = 'webgl';
} else { } else {
// @ts-ignore requestAdapterInfo is not in tslib let adapterInfo;
const adapterInfo = 'requestAdapterInfo' in adapter ? await adapter.requestAdapterInfo() : undefined; // @ts-ignore gpu adapter info
if ('requestAdapterInfo' in adapter) adapterInfo = await adapter?.requestAdapterInfo();
// @ts-ignore gpu adapter info
else adapterInfo = adapter.info;
// if (adapter.features) adapter.features.forEach((feature) => log('webgpu features:', feature)); // if (adapter.features) adapter.features.forEach((feature) => log('webgpu features:', feature));
log('webgpu adapter info:', adapterInfo); log('webgpu adapter info:', adapterInfo);
} }

View File

@ -14,6 +14,7 @@ const options = {
export interface ModelInfo { export interface ModelInfo {
name: string, name: string,
loaded: boolean,
inCache: boolean, inCache: boolean,
sizeDesired: number, sizeDesired: number,
sizeFromManifest: number, sizeFromManifest: number,
@ -42,6 +43,7 @@ export async function loadModel(modelPath: string | undefined): Promise<GraphMod
const cachedModelName = 'indexeddb://' + shortModelName; // generate short model name for cache const cachedModelName = 'indexeddb://' + shortModelName; // generate short model name for cache
modelStats[shortModelName] = { modelStats[shortModelName] = {
name: shortModelName, name: shortModelName,
loaded: false,
sizeFromManifest: 0, sizeFromManifest: 0,
sizeLoadedWeights: 0, sizeLoadedWeights: 0,
sizeDesired: modelsDefs[shortModelName], sizeDesired: modelsDefs[shortModelName],
@ -59,7 +61,7 @@ export async function loadModel(modelPath: string | undefined): Promise<GraphMod
modelStats[shortModelName].url = modelStats[shortModelName].inCache ? cachedModelName : modelUrl; modelStats[shortModelName].url = modelStats[shortModelName].inCache ? cachedModelName : modelUrl;
const tfLoadOptions = typeof fetch === 'undefined' ? {} : { fetchFunc: (url: string, init?: RequestInit) => httpHandler(url, init) }; const tfLoadOptions = typeof fetch === 'undefined' ? {} : { fetchFunc: (url: string, init?: RequestInit) => httpHandler(url, init) };
let model: GraphModel = new tf.GraphModel(modelStats[shortModelName].url, tfLoadOptions) as unknown as GraphModel; // create model prototype and decide if load from cache or from original modelurl let model: GraphModel = new tf.GraphModel(modelStats[shortModelName].url, tfLoadOptions) as unknown as GraphModel; // create model prototype and decide if load from cache or from original modelurl
let loaded = false; modelStats[shortModelName].loaded = false;
try { try {
// @ts-ignore private function // @ts-ignore private function
model.findIOHandler(); // decide how to actually load a model model.findIOHandler(); // decide how to actually load a model
@ -74,13 +76,13 @@ export async function loadModel(modelPath: string | undefined): Promise<GraphMod
if (artifacts) model.loadSync(artifacts); // load weights if (artifacts) model.loadSync(artifacts); // load weights
else model = await tf.loadGraphModel(modelStats[shortModelName].inCache ? cachedModelName : modelUrl, tfLoadOptions) as unknown as GraphModel; else model = await tf.loadGraphModel(modelStats[shortModelName].inCache ? cachedModelName : modelUrl, tfLoadOptions) as unknown as GraphModel;
// @ts-ignore private property // @ts-ignore private property
modelStats[shortModelName].sizeLoadedWeights = model.artifacts?.weightData?.byteLength || 0; modelStats[shortModelName].sizeLoadedWeights = model.artifacts?.weightData?.byteLength || model.artifacts?.weightData?.[0].byteLength || 0;
if (options.verbose) log('load:', { model: shortModelName, url: model['modelUrl'], bytes: modelStats[shortModelName].sizeLoadedWeights }); if (options.verbose) log('load:', { model: shortModelName, url: model['modelUrl'], bytes: modelStats[shortModelName].sizeLoadedWeights });
loaded = true; modelStats[shortModelName].loaded = true;
} catch (err) { } catch (err) {
log('error loading model:', modelUrl, err); log('error loading model:', modelUrl, err);
} }
if (loaded && options.cacheModels && options.cacheSupported && !modelStats[shortModelName].inCache) { // save model to cache if (modelStats[shortModelName].loaded && options.cacheModels && options.cacheSupported && !modelStats[shortModelName].inCache) { // save model to cache
try { try {
const saveResult = await model.save(cachedModelName); const saveResult = await model.save(cachedModelName);
if (options.debug) log('model saved:', cachedModelName, saveResult); if (options.debug) log('model saved:', cachedModelName, saveResult);

View File

@ -154,7 +154,12 @@ export class Env {
try { try {
if (this.webgpu.supported) { if (this.webgpu.supported) {
const adapter = await navigator.gpu.requestAdapter(); const adapter = await navigator.gpu.requestAdapter();
this.webgpu.adapter = await adapter?.requestAdapterInfo(); if (adapter) {
// @ts-ignore requestAdapterInfo is not in tslib
if ('requestAdapterInfo' in adapter) this.webgpu.adapter = await adapter.requestAdapterInfo();
// @ts-ignore adapter.info is not in tslib
else this.webgpu.adapter = await adapter.info;
}
} }
} catch { } catch {
this.webgpu.supported = false; this.webgpu.supported = false;

View File

@ -166,6 +166,7 @@ export async function warmup(instance: Human, userConfig?: Partial<Config>): Pro
} }
return new Promise(async (resolve) => { return new Promise(async (resolve) => {
await instance.models.load(); await instance.models.load();
await tf.ready();
await runCompile(instance); await runCompile(instance);
const res = await runInference(instance); const res = await runInference(instance);
const t1 = now(); const t1 = now();

View File

@ -1,51 +1,51 @@
2024-02-15 12:49:25 DATA:  Build {"name":"@vladmandic/human","version":"3.2.1"} 2025-02-05 09:39:04 DATA:  Build {"name":"@vladmandic/human","version":"3.3.5"}
2024-02-15 12:49:25 INFO:  Application: {"name":"@vladmandic/human","version":"3.2.1"} 2025-02-05 09:39:04 INFO:  Application: {"name":"@vladmandic/human","version":"3.3.5"}
2024-02-15 12:49:25 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true} 2025-02-05 09:39:04 INFO:  Environment: {"profile":"production","config":".build.json","package":"package.json","tsconfig":true,"eslintrc":true,"git":true}
2024-02-15 12:49:25 INFO:  Toolchain: {"build":"0.9.2","esbuild":"0.19.12","typescript":"5.3.3","typedoc":"0.25.4","eslint":"8.55.0"} 2025-02-05 09:39:04 INFO:  Toolchain: {"build":"0.10.2","esbuild":"0.24.2","typescript":"5.7.3","typedoc":"0.27.6","eslint":"8.57.0"}
2024-02-15 12:49:25 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]} 2025-02-05 09:39:04 INFO:  Build: {"profile":"production","steps":["clean","compile","typings","typedoc","lint","changelog"]}
2024-02-15 12:49:25 STATE: Clean: {"locations":["dist/*","types/*","typedoc/*"]} 2025-02-05 09:39:04 STATE: Clean: {"locations":["dist/*","types/*","typedoc/*"]}
2024-02-15 12:49:25 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1289,"outputBytes":358} 2025-02-05 09:39:04 STATE: Compile: {"name":"tfjs/browser/version","format":"esm","platform":"browser","input":"tfjs/tf-version.ts","output":"dist/tfjs.version.js","files":1,"inputBytes":1289,"outputBytes":358}
2024-02-15 12:49:25 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":566,"outputBytes":957} 2025-02-05 09:39:04 STATE: Compile: {"name":"tfjs/nodejs/cpu","format":"cjs","platform":"node","input":"tfjs/tf-node.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":566,"outputBytes":957}
2024-02-15 12:49:25 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":80,"inputBytes":676266,"outputBytes":320934} 2025-02-05 09:39:04 STATE: Compile: {"name":"human/nodejs/cpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node.js","files":80,"inputBytes":678664,"outputBytes":321804}
2024-02-15 12:49:25 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":574,"outputBytes":965} 2025-02-05 09:39:04 STATE: Compile: {"name":"tfjs/nodejs/gpu","format":"cjs","platform":"node","input":"tfjs/tf-node-gpu.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":574,"outputBytes":965}
2024-02-15 12:49:25 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":80,"inputBytes":676274,"outputBytes":320938} 2025-02-05 09:39:04 STATE: Compile: {"name":"human/nodejs/gpu","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-gpu.js","files":80,"inputBytes":678672,"outputBytes":321808}
2024-02-15 12:49:25 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":662,"outputBytes":2003} 2025-02-05 09:39:04 STATE: Compile: {"name":"tfjs/nodejs/wasm","format":"cjs","platform":"node","input":"tfjs/tf-node-wasm.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":662,"outputBytes":2003}
2024-02-15 12:49:25 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":80,"inputBytes":677312,"outputBytes":321049} 2025-02-05 09:39:04 STATE: Compile: {"name":"human/nodejs/wasm","format":"cjs","platform":"node","input":"src/human.ts","output":"dist/human.node-wasm.js","files":80,"inputBytes":679710,"outputBytes":321919}
2024-02-15 12:49:25 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1403,"outputBytes":690} 2025-02-05 09:39:04 STATE: Compile: {"name":"tfjs/browser/esm/nobundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":2,"inputBytes":1403,"outputBytes":690}
2024-02-15 12:49:25 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":80,"inputBytes":675999,"outputBytes":319515} 2025-02-05 09:39:04 STATE: Compile: {"name":"human/browser/esm/nobundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm-nobundle.js","files":80,"inputBytes":678397,"outputBytes":320365}
2024-02-15 12:49:25 STATE: Compile: {"name":"tfjs/browser/esm/bundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":10,"inputBytes":1403,"outputBytes":1294474} 2025-02-05 09:39:04 STATE: Compile: {"name":"tfjs/browser/esm/bundle","format":"esm","platform":"browser","input":"tfjs/tf-browser.ts","output":"dist/tfjs.esm.js","files":10,"inputBytes":1403,"outputBytes":1267320}
2024-02-15 12:49:25 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":80,"inputBytes":1969783,"outputBytes":1609692} 2025-02-05 09:39:04 STATE: Compile: {"name":"human/browser/iife/bundle","format":"iife","platform":"browser","input":"src/human.ts","output":"dist/human.js","files":80,"inputBytes":1945027,"outputBytes":1583413}
2024-02-15 12:49:25 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":80,"inputBytes":1969783,"outputBytes":2120081} 2025-02-05 09:39:04 STATE: Compile: {"name":"human/browser/esm/bundle","format":"esm","platform":"browser","input":"src/human.ts","output":"dist/human.esm.js","files":80,"inputBytes":1945027,"outputBytes":2067530}
2024-02-15 12:49:26 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":14} 2025-02-05 09:39:06 STATE: Typings: {"input":"src/human.ts","output":"types/lib","files":78}
2024-02-15 12:49:28 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":81,"generated":true} 2025-02-05 09:39:08 STATE: TypeDoc: {"input":"src/human.ts","output":"typedoc","objects":81,"generated":true}
2024-02-15 12:49:28 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6318,"outputBytes":2970} 2025-02-05 09:39:08 STATE: Compile: {"name":"demo/typescript","format":"esm","platform":"browser","input":"demo/typescript/index.ts","output":"demo/typescript/index.js","files":1,"inputBytes":6318,"outputBytes":2970}
2024-02-15 12:49:28 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":17499,"outputBytes":9399} 2025-02-05 09:39:08 STATE: Compile: {"name":"demo/faceid","format":"esm","platform":"browser","input":"demo/faceid/index.ts","output":"demo/faceid/index.js","files":2,"inputBytes":17498,"outputBytes":9397}
2024-02-15 12:49:28 STATE: Compile: {"name":"demo/tracker","format":"esm","platform":"browser","input":"demo/tracker/index.ts","output":"demo/tracker/index.js","files":2,"inputBytes":54375,"outputBytes":22791} 2025-02-05 09:39:08 STATE: Compile: {"name":"demo/tracker","format":"esm","platform":"browser","input":"demo/tracker/index.ts","output":"demo/tracker/index.js","files":2,"inputBytes":54375,"outputBytes":22791}
2024-02-15 12:49:35 STATE: Lint: {"locations":["**/*.json","src/**/*.ts","test/**/*.js","demo/**/*.js","**/*.md"],"files":172,"errors":0,"warnings":0} 2025-02-05 09:39:16 STATE: Lint: {"locations":["**/*.json","src/**/*.ts","test/**/*.js","demo/**/*.js","**/*.md"],"files":171,"errors":0,"warnings":0}
2024-02-15 12:49:35 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"} 2025-02-05 09:39:16 STATE: ChangeLog: {"repository":"https://github.com/vladmandic/human","branch":"main","output":"CHANGELOG.md"}
2024-02-15 12:49:35 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs-core.d.ts","output":"types/tfjs-core.d.ts"} 2025-02-05 09:39:16 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs-core.d.ts","output":"types/tfjs-core.d.ts"}
2024-02-15 12:49:35 INFO:  Done... 2025-02-05 09:39:16 INFO:  Done...
2024-02-15 12:49:35 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs.d.ts","output":"types/tfjs.esm.d.ts"} 2025-02-05 09:39:16 STATE: Copy: {"input":"node_modules/@vladmandic/tfjs/types/tfjs.d.ts","output":"types/tfjs.esm.d.ts"}
2024-02-15 12:49:35 STATE: Copy: {"input":"src/types/tsconfig.json","output":"types/tsconfig.json"} 2025-02-05 09:39:16 STATE: Copy: {"input":"src/types/tsconfig.json","output":"types/tsconfig.json"}
2024-02-15 12:49:35 STATE: Copy: {"input":"src/types/eslint.json","output":"types/.eslintrc.json"} 2025-02-05 09:39:16 STATE: Copy: {"input":"src/types/eslint.json","output":"types/.eslintrc.json"}
2024-02-15 12:49:35 STATE: Copy: {"input":"src/types/tfjs.esm.d.ts","output":"dist/tfjs.esm.d.ts"} 2025-02-05 09:39:16 STATE: Copy: {"input":"src/types/tfjs.esm.d.ts","output":"dist/tfjs.esm.d.ts"}
2024-02-15 12:49:35 STATE: Filter: {"input":"types/tfjs-core.d.ts"} 2025-02-05 09:39:16 STATE: Filter: {"input":"types/tfjs-core.d.ts"}
2024-02-15 12:49:36 ERROR: API-Extractor: {} 2025-02-05 09:39:17 STATE: API-Extractor: {"succeeeded":true,"errors":0,"warnings":0}
2024-02-15 12:49:36 STATE: Filter: {"input":"types/human.d.ts"} 2025-02-05 09:39:17 STATE: Filter: {"input":"types/human.d.ts"}
2024-02-15 12:49:36 STATE: Write: {"output":"dist/human.esm-nobundle.d.ts"} 2025-02-05 09:39:17 STATE: Write: {"output":"dist/human.esm-nobundle.d.ts"}
2024-02-15 12:49:36 STATE: Write: {"output":"dist/human.esm.d.ts"} 2025-02-05 09:39:17 STATE: Write: {"output":"dist/human.esm.d.ts"}
2024-02-15 12:49:36 STATE: Write: {"output":"dist/human.d.ts"} 2025-02-05 09:39:17 STATE: Write: {"output":"dist/human.d.ts"}
2024-02-15 12:49:36 STATE: Write: {"output":"dist/human.node-gpu.d.ts"} 2025-02-05 09:39:17 STATE: Write: {"output":"dist/human.node-gpu.d.ts"}
2024-02-15 12:49:36 STATE: Write: {"output":"dist/human.node.d.ts"} 2025-02-05 09:39:17 STATE: Write: {"output":"dist/human.node.d.ts"}
2024-02-15 12:49:36 STATE: Write: {"output":"dist/human.node-wasm.d.ts"} 2025-02-05 09:39:17 STATE: Write: {"output":"dist/human.node-wasm.d.ts"}
2024-02-15 12:49:36 INFO:  Analyze models: {"folders":8,"result":"models/models.json"} 2025-02-05 09:39:17 INFO:  Analyze models: {"folders":8,"result":"models/models.json"}
2024-02-15 12:49:36 STATE: Models {"folder":"./models","models":12} 2025-02-05 09:39:17 STATE: Models {"folder":"./models","models":12}
2024-02-15 12:49:36 STATE: Models {"folder":"../human-models/models","models":44} 2025-02-05 09:39:17 STATE: Models {"folder":"../human-models/models","models":44}
2024-02-15 12:49:36 STATE: Models {"folder":"../blazepose/model/","models":4} 2025-02-05 09:39:17 STATE: Models {"folder":"../blazepose/model/","models":4}
2024-02-15 12:49:36 STATE: Models {"folder":"../anti-spoofing/model","models":1} 2025-02-05 09:39:17 STATE: Models {"folder":"../anti-spoofing/model","models":1}
2024-02-15 12:49:36 STATE: Models {"folder":"../efficientpose/models","models":3} 2025-02-05 09:39:17 STATE: Models {"folder":"../efficientpose/models","models":3}
2024-02-15 12:49:36 STATE: Models {"folder":"../insightface/models","models":5} 2025-02-05 09:39:17 STATE: Models {"folder":"../insightface/models","models":5}
2024-02-15 12:49:36 STATE: Models {"folder":"../movenet/models","models":3} 2025-02-05 09:39:17 STATE: Models {"folder":"../movenet/models","models":3}
2024-02-15 12:49:36 STATE: Models {"folder":"../nanodet/models","models":4} 2025-02-05 09:39:17 STATE: Models {"folder":"../nanodet/models","models":4}
2024-02-15 12:49:36 STATE: Models: {"count":58,"totalSize":380063249} 2025-02-05 09:39:17 STATE: Models: {"count":58,"totalSize":380063249}
2024-02-15 12:49:36 INFO:  Human Build complete... {"logFile":"test/build.log"} 2025-02-05 09:39:17 INFO:  Human Build complete... {"logFile":"test/build.log"}

View File

@ -3,7 +3,7 @@ const H = require('../dist/human.node.js');
const test = require('./test-node-main.js').test; const test = require('./test-node-main.js').test;
const config = { const config = {
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: 'file://models/', modelBasePath: 'file://models/',
backend: 'cpu', backend: 'cpu',
debug: false, debug: false,

View File

@ -3,7 +3,7 @@ const H = require('../dist/human.node-gpu.js');
const test = require('./test-node-main.js').test; const test = require('./test-node-main.js').test;
const config = { const config = {
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: 'file://models/', modelBasePath: 'file://models/',
backend: 'tensorflow', backend: 'tensorflow',
debug: false, debug: false,

View File

@ -10,7 +10,7 @@ H.env.Canvas = Canvas; // requires monkey-patch as wasm does not have tf.browser
H.env.Image = Image; // requires monkey-patch as wasm does not have tf.browser namespace H.env.Image = Image; // requires monkey-patch as wasm does not have tf.browser namespace
const config = { const config = {
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: 'https://vladmandic.github.io/human-models/models/', modelBasePath: 'https://vladmandic.github.io/human-models/models/',
backend: 'wasm', backend: 'wasm',
// wasmPath: 'node_modules/@tensorflow/tfjs-backend-wasm/dist/', // wasmPath: 'node_modules/@tensorflow/tfjs-backend-wasm/dist/',

View File

@ -4,7 +4,7 @@ const H = require('../dist/human.node.js');
const test = require('./test-node-main.js').test; const test = require('./test-node-main.js').test;
const config = { const config = {
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: 'file://models/', modelBasePath: 'file://models/',
backend: 'tensorflow', backend: 'tensorflow',
debug: false, debug: false,

View File

@ -6,7 +6,7 @@ const H = require('../dist/human.node.js');
const models = ['emotion.json', 'gear-e1.json', 'gear-e2.json', 'affectnet-mobilenet.json']; const models = ['emotion.json', 'gear-e1.json', 'gear-e2.json', 'affectnet-mobilenet.json'];
const humanConfig = { const humanConfig = {
debug: false, debug: false,
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: 'https://vladmandic.github.io/human-models/models/', modelBasePath: 'https://vladmandic.github.io/human-models/models/',
face: { face: {
scale: 1.4, scale: 1.4,

View File

@ -12,7 +12,7 @@ process.env.TF_CPP_MIN_LOG_LEVEL = '2';
const humanConfig = { const humanConfig = {
backend: 'tensorflow', backend: 'tensorflow',
debug: false, debug: false,
cacheSensitivity: 0, cacheSensitivity: 0.01,
modelBasePath: 'https://vladmandic.github.io/human-models/models/', modelBasePath: 'https://vladmandic.github.io/human-models/models/',
face: { face: {
detector: { enabled: true, modelPath: 'blazeface-back.json' }, detector: { enabled: true, modelPath: 'blazeface-back.json' },

View File

@ -107,7 +107,7 @@ async function testWarmup(human, title) {
try { try {
warmup = await human.warmup(config); warmup = await human.warmup(config);
} catch (err) { } catch (err) {
log('error', 'error warmup'); log('error', 'error warmup', err);
} }
if (warmup) { if (warmup) {
log('state', 'passed: warmup:', config.warmup, title); log('state', 'passed: warmup:', config.warmup, title);

File diff suppressed because it is too large Load Diff

View File

@ -51,9 +51,9 @@
"tabSize": 2 "tabSize": 2
}, },
"exclude": ["node_modules/", "types/", "dist/**/*.js"], "exclude": ["node_modules/", "types/", "dist/**/*.js"],
"include": ["src", "tfjs/*.ts", "types/human.d.ts", "test/**/*.ts", "demo/**/*.ts", "demo/facedetect/loader.js"], "include": ["src", "tfjs/*.ts", "types/human.d.ts", "test/**/*.ts"],
"typedocOptions": { "typedocOptions": {
"excludeExternals": true, "excludeExternals": true,
"externalPattern": ["**/node_modules/**", "tfjs/"] "externalPattern": ["**/node_modules/**", "tfjs/", "demo/"]
} }
} }

View File

@ -0,0 +1 @@
window.hierarchyData = "eJyV1D1vgzAQBuD/crPTYvPN1s+0UqsOGasMFI7ELdiR7Vaqovz3yhkKmOWygAX38nDG+AhGa2eheuciyrYMDHY9Nk5qZaE6gr/qz6oeECpYo0IjmzutOrkDBl9StVCJNGPwbXqoQCqHpqsbtNez2qu9G3pg0PS1tVCBs+3Kh1f/AX9zL/vWoDq/DeeMC5EyLmI/inPGRSL8oWBcpIk/lIyLzI/yiHFR+FHJGY+jnPGYp9sTA/+gSQOPdYP36LBx2pC6WAYIrZxdkQbuK9o92RyLqV4c9vlspCV7YzHZywPvxjlUfuWQ0SBBlROx+KK2MfJwkb3IkPUi0B8GfZE8q6eqaRLOtnJyc9C6o8/2PEGWy0B+kT+o0NLX1jxAdbOw4zXW9H92LKZ6eRR4ZOsyp5j2davbX5IzFlKdcrofPNWqJTljIdGJo+k+8PbxiY0jSdNSqsWne+oGdwMqV5N/vmWA4p5Of40CVuo="

View File

@ -15,8 +15,6 @@
--dark-hl-6: #DCDCAA; --dark-hl-6: #DCDCAA;
--light-hl-7: #098658; --light-hl-7: #098658;
--dark-hl-7: #B5CEA8; --dark-hl-7: #B5CEA8;
--light-hl-8: #000000;
--dark-hl-8: #C8C8C8;
--light-code-background: #FFFFFF; --light-code-background: #FFFFFF;
--dark-code-background: #1E1E1E; --dark-code-background: #1E1E1E;
} }
@ -30,7 +28,6 @@
--hl-5: var(--light-hl-5); --hl-5: var(--light-hl-5);
--hl-6: var(--light-hl-6); --hl-6: var(--light-hl-6);
--hl-7: var(--light-hl-7); --hl-7: var(--light-hl-7);
--hl-8: var(--light-hl-8);
--code-background: var(--light-code-background); --code-background: var(--light-code-background);
} } } }
@ -43,7 +40,6 @@
--hl-5: var(--dark-hl-5); --hl-5: var(--dark-hl-5);
--hl-6: var(--dark-hl-6); --hl-6: var(--dark-hl-6);
--hl-7: var(--dark-hl-7); --hl-7: var(--dark-hl-7);
--hl-8: var(--dark-hl-8);
--code-background: var(--dark-code-background); --code-background: var(--dark-code-background);
} } } }
@ -56,7 +52,6 @@
--hl-5: var(--light-hl-5); --hl-5: var(--light-hl-5);
--hl-6: var(--light-hl-6); --hl-6: var(--light-hl-6);
--hl-7: var(--light-hl-7); --hl-7: var(--light-hl-7);
--hl-8: var(--light-hl-8);
--code-background: var(--light-code-background); --code-background: var(--light-code-background);
} }
@ -69,7 +64,6 @@
--hl-5: var(--dark-hl-5); --hl-5: var(--dark-hl-5);
--hl-6: var(--dark-hl-6); --hl-6: var(--dark-hl-6);
--hl-7: var(--dark-hl-7); --hl-7: var(--dark-hl-7);
--hl-8: var(--dark-hl-8);
--code-background: var(--dark-code-background); --code-background: var(--dark-code-background);
} }
@ -81,5 +75,4 @@
.hl-5 { color: var(--hl-5); } .hl-5 { color: var(--hl-5); }
.hl-6 { color: var(--hl-6); } .hl-6 { color: var(--hl-6); }
.hl-7 { color: var(--hl-7); } .hl-7 { color: var(--hl-7); }
.hl-8 { color: var(--hl-8); }
pre, code { background: var(--code-background); } pre, code { background: var(--code-background); }

18
typedoc/assets/icons.js Normal file

File diff suppressed because one or more lines are too long

1
typedoc/assets/icons.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
window.navigationData = "data:application/octet-stream;base64,H4sIAAAAAAAAA5WZT3PbNhDFvwt7dZtIVtLGN/9RFU+s2mNnmkOmB5hcSajIBQcEFaudfvcOCUkACXCXuu577ydwAZIg9P3fxMCbSa6SDFaizk1ykZTCbJKrRGIGb79sTJH/5LStxCy5mk0+zS7fz/67OKW/AlZKu3ChsjqH6p2ttxSX9nKZFj/CVFPtZS6SdCPzTAMmV99PcVUaqbByhJ3QUryeGAe9y7qcegMQee7SqxrTNmDTIs+7yY/+0F9Vth+MNiKRTQXuRDWYtjKRX4kUBtONSGTXUJlaD8cPOkHYCMwG441IZCVKM5htRCKrXv+GdDhtZSJfgq4UDuatHOT/8giFMOkmXK9tedSCvYMq1bI0/r1i9uWJ4fQubvr+06+TD/7CXTb+x/7691m+g6NlsjIC44vK0o4OalXK+LqwgEYlwpUsZC60NNGbyiKch54llUFeRaaprY+ap2UPkeaiqhxiGSFNpr95Y/gCGiF/LCv/gWpANzfnCXMy9abnw0d/ohvvixGGRDkXxdqJXGbCQOuO9tnSOj6y188Ctw4EWBfVu6bWDfmdmeMu7Oscd1Q3F1qUm96gj1GnUYTPdSEwDLdlKtd/sR2Dtv7zhMp+g9dbUYRZW6eSNyrb3ypcyXV0zp1MTXbj+gL7Ukk0g5ijgQM9Q9XbHXQwVqYgxOXwl3KnxY/gWecRPJ3C/C5SuEYjX0qlVsSAIj4WawxgMwAO2/VxWIY2DnJ8qfCjC5w82kBqlGa5vo2Dzgs1YqwdF4dcgODG6Cwc7F7LioE5Cwd7kDtAqDhg18ZBl1BtGKCzcDDi1ncyCZG5AbL9noECLQBBy5QgdRw0qt3lkijPQaE+C8wIjpM5CNFoJ7NbhXtcqSjjpFKIx3YTTVyOb+BBxCX5Bgr01G7LCZBvoEAEgg+/wLoANIJ5MIU2Cmo3AgTON1Cga9zf9j4p7ZfASeA+AK5xf1+INUQAbX1E/k+ZgYrk2zqXvxHpFjCbY130EZ7EUlS2v0ZUdgICUEc9j3WTi3/gSVVBgwZs59Hnq5VMJaDhf6FjHfMri/73vqMuYp/6ccqDwKwQehvDHLVzOGQ/A9M55FOD/gBDwX3fOfyl2gGDPljOoTZXyVAPFp76FlLeuNRhN9VPHspsegdogoePrbLZNwMaRR5/gHVVjmX3cdH17kljKEPr3ddYjsQ1BAc9tjoue1vrPJ5vlHGMO6khjc1tT+ZoC8AsvBpb5bNt4/tv4CPCEzlSsxEamGFPGkP5ui+jiKbO5dtXot3ABCvW11gOlnXQj7bIJrWsBvrgSRzFDjPWCadwjKfu+YKNP0XOFILkc+cU2wafg8PrMOdvsmIbhr7O8exZzuSuzznWx+WnA/npyPzlQP5yZH42kJ+NzD/IbTAbTuEY34Qu6jI2G05hD6Ht30zxv3MOGvFXDvgHiy4JuOsf03VjRRk/c26F8PDzf7TeFt4zGwAA" window.navigationData = "eJyVmU9z2zYQxb8Le3WbSFbSxjf/URVP7Npje5pDJgeYXEmoyAUHBBWrnXz3DglJAAlwl7rue+8nEABJcPXtv8TAm0kukkyLH8lZUgqzTi6SQmV1DtW7pvrb2hR5cpZsJGbJxewsSdcyzzRgcvHtGFelkQorR9gKLcXrkbHXu6zz6c+zI0HkuUsva0zbgE2LPO8mP8685KvKdoPRRiSyqcCtqAbTVibyS5HCYLoRiewKKlPr4fheJwhrgdlgvBGJrERpBrONSGTV6z+QDqetTORL0JXCwbyVibwBrJQezFs5yH/3CIUw6Trc72151Ia/gSrVsjT+MMyuPDKc3sVN33/6ffLB3/j3jf+hf//4LN/B0TJZGYHxTWlpBwe1q2V8X1lAoxLhShYyF1qa6E1pEc5Dr5LKIK8iy9TWR63TfQ+R5qKqHOI+QppM//DG8AU0Qv5QegyJBnRzcx8xR1NveT589Be68T4bYUiUc1GsrchlJgy07ug8W1rHR871S++eOsz1S+Rm8pf7SeDGpQDronrX1LoJf0bnuA3XY45bahUWWpTr3sUeok6jCJ/rQmAYbstUrj8vh6Ct/zqhsl/h9VoUYdbWqeSVynbXCpdyFd0rTqY2SeP6ArtSSTSDmIOBAz1BVefDGCtTEOJy+Eu50eJH8Iz0CJ5OYf4UKVyikc+lUktiQBEfizUGsBkAh+36OCxDGwc5vIz40QVOHm0gNUqzXN/GQeeFGjHWjotDLkBwY3QWDnarZcXAnIWD3cktIFQcsGvjoPdQrRmgs3Aw4tZ3MgmRuQFy+j0DBVoAgpYpQeo4aFR7uiZRnoNCfRaYERwncxBiop3MHjFucamijKNKIR7awztxOb6BBxGX5Bso0GP7OUCAfAMFIhB8+BlWBaARzIMptFFQexAgcL6BAl3i7rr3KWu/II4C9+FwibvbQqwgAmjrI/J/ywxUJN/WufyVSDeA2Rzroo/wJJaist0lorILEIA66mmsq1z8C4+qCiZowHYafb5cylQCGv4XOtYxv7Lo9xkcdRFrMcQpdwKzQuhNDHPQTuGQ8xmYTiEfJ+gvMBTc953Cv1dbYNB7yynU5ioZ6t7CU99CyhuX2p+m+sl9mU1vAU3w8LFVNvtmQKPI4w+wrsqx7Dkuut89aQxlaL/7GsuRuIKgQWSr47LXtc7j+UYZx7iRGtLY2vZkjrYAzMKrsVU+2058/w18QHgiR2oOQgMr7EljKC+7Mopo6ly+fSXaA0ywY32N5WBZB/PRFtmkltXAPHgSR7HDjM2EUzjGY7e/YOOPkZ5CkHzqdM9t8Clomoc5/5AVOzD0dY5nezmTmz7nUB+Xnw7kpyPz5wP585H52UB+NjJ/JzfBajiFY3wVuqjL2Go4hW1ew1LUuYn/jbTXiL+QwG8suiTgtt+m68aKMt6rbgWi070fkn9wz8C+aH9x2r5lOvk0O38/+/n9f3cUMM8="

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,2 @@
<!DOCTYPE html><html class="default" lang="en" data-base=".."><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>tensor | @vladmandic/human - v3.3.5</title><meta name="description" content="Documentation for @vladmandic/human"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search"><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">@vladmandic/human - v3.3.5</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../index.html">@vladmandic/human</a></li><li><a href="../modules/draw.html">draw</a></li><li><a href="draw.tensor.html">tensor</a></li></ul><h1>Function tensor</h1></div><section class="tsd-panel"><ul class="tsd-signatures"><li class="tsd-signature tsd-anchor-link"><a id="tensor" class="tsd-anchor"></a><span class="tsd-kind-call-signature">tensor</span><span class="tsd-signature-symbol">(</span><span class="tsd-kind-parameter">input</span><span class="tsd-signature-symbol">:</span> <a href="../types/Tensor2D.html" class="tsd-signature-type tsd-kind-type-alias">Tensor2D</a><span class="tsd-signature-symbol">,</span> <span class="tsd-kind-parameter">output</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">HTMLCanvasElement</span><span class="tsd-signature-symbol">)</span><span class="tsd-signature-symbol">:</span> <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span><a href="#tensor" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></li><li class="tsd-description"><div class="tsd-comment tsd-typography"><p>draw processed canvas</p>
</div><div class="tsd-parameters"><h4 class="tsd-parameters-title">Parameters</h4><ul class="tsd-parameter-list"><li><span><span class="tsd-kind-parameter">input</span>: <a href="../types/Tensor2D.html" class="tsd-signature-type tsd-kind-type-alias">Tensor2D</a></span></li><li><span><span class="tsd-kind-parameter">output</span>: <span class="tsd-signature-type">HTMLCanvasElement</span></span></li></ul></div><h4 class="tsd-returns-title">Returns <span class="tsd-signature-type">Promise</span><span class="tsd-signature-symbol">&lt;</span><span class="tsd-signature-type">void</span><span class="tsd-signature-symbol">&gt;</span></h4><div class="tsd-comment tsd-typography"></div><aside class="tsd-sources"><ul><li>Defined in <a href="https://github.com/vladmandic/human/blob/main/src/draw/draw.ts#L66">src/draw/draw.ts:66</a></li></ul></aside></li></ul></section></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div></div><div class="site-menu"><nav class="tsd-navigation"><a href="../index.html">@vladmandic/human - v3.3.5</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1
typedoc/hierarchy.html Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Some files were not shown because too many files have changed in this diff Show More