mirror of https://github.com/vladmandic/human
exception handling
parent
79c7ddd1c6
commit
58d0585027
|
@ -1,6 +1,6 @@
|
||||||
# @vladmandic/human
|
# @vladmandic/human
|
||||||
|
|
||||||
Version: **1.4.0**
|
Version: **1.4.1**
|
||||||
Description: **Human: AI-powered 3D Face Detection, Face Description & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition**
|
Description: **Human: AI-powered 3D Face Detection, Face Description & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition**
|
||||||
|
|
||||||
Author: **Vladimir Mandic <mandic00@live.com>**
|
Author: **Vladimir Mandic <mandic00@live.com>**
|
||||||
|
@ -9,8 +9,9 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### **HEAD -> main** 2021/04/08 mandic00@live.com
|
### **1.4.1** 2021/04/09 mandic00@live.com
|
||||||
|
|
||||||
|
- add modelbasepath option
|
||||||
|
|
||||||
### **1.3.5** 2021/04/06 mandic00@live.com
|
### **1.3.5** 2021/04/06 mandic00@live.com
|
||||||
|
|
||||||
|
|
|
@ -30,9 +30,10 @@ Check out [**Live Demo**](https://vladmandic.github.io/human/demo/index.html) fo
|
||||||
|
|
||||||
## Demos
|
## Demos
|
||||||
|
|
||||||
- [**Demo Application**](https://vladmandic.github.io/human/demo/index.html)
|
- [**Main Application**](https://vladmandic.github.io/human/demo/index.html)
|
||||||
- [**Face Extraction, Description, Identification and Matching**](https://vladmandic.github.io/human/demo/facematch.html)
|
- [**Face Extraction, Description, Identification and Matching**](https://vladmandic.github.io/human/demo/facematch.html)
|
||||||
- [**Face Extraction and 3D Rendering**](https://vladmandic.github.io/human/demo/face3d.html)
|
- [**Face Extraction and 3D Rendering**](https://vladmandic.github.io/human/demo/face3d.html)
|
||||||
|
- [**Details on Demo Applications**](https://github.com/vladmandic/human/wiki/Demos)
|
||||||
|
|
||||||
## Project pages
|
## Project pages
|
||||||
|
|
||||||
|
@ -47,7 +48,6 @@ Check out [**Live Demo**](https://vladmandic.github.io/human/demo/index.html) fo
|
||||||
## Wiki pages
|
## Wiki pages
|
||||||
|
|
||||||
- [**Home**](https://github.com/vladmandic/human/wiki)
|
- [**Home**](https://github.com/vladmandic/human/wiki)
|
||||||
- [**Demos**](https://github.com/vladmandic/human/wiki/Demos)
|
|
||||||
- [**Installation**](https://github.com/vladmandic/human/wiki/Install)
|
- [**Installation**](https://github.com/vladmandic/human/wiki/Install)
|
||||||
- [**Usage & Functions**](https://github.com/vladmandic/human/wiki/Usage)
|
- [**Usage & Functions**](https://github.com/vladmandic/human/wiki/Usage)
|
||||||
- [**Configuration Details**](https://github.com/vladmandic/human/wiki/Configuration)
|
- [**Configuration Details**](https://github.com/vladmandic/human/wiki/Configuration)
|
||||||
|
@ -185,7 +185,7 @@ For more info, see [**Configuration Details**](https://github.com/vladmandic/hum
|
||||||
|
|
||||||
<br><hr><br>
|
<br><hr><br>
|
||||||
|
|
||||||
`Human` library is written in `TypeScript` [4.3](https://www.typescriptlang.org/docs/handbook/intro.html)
|
`Human` library is written in `TypeScript` [4.2](https://www.typescriptlang.org/docs/handbook/intro.html)
|
||||||
Conforming to `JavaScript` [ECMAScript version 2020](https://www.ecma-international.org/ecma-262/11.0/index.html) standard
|
Conforming to `JavaScript` [ECMAScript version 2020](https://www.ecma-international.org/ecma-262/11.0/index.html) standard
|
||||||
Build target is `JavaScript` **EMCAScript version 2018**
|
Build target is `JavaScript` **EMCAScript version 2018**
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
let instance = 0;
|
let instance = 0;
|
||||||
let CSScreated = false;
|
let CSScreated = false;
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Menu from './helpers/menu.js';
|
||||||
import GLBench from './helpers/gl-bench.js';
|
import GLBench from './helpers/gl-bench.js';
|
||||||
|
|
||||||
const userConfig = { backend: 'webgl' }; // add any user configuration overrides
|
const userConfig = { backend: 'webgl' }; // add any user configuration overrides
|
||||||
|
let human;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
const userConfig = {
|
const userConfig = {
|
||||||
|
@ -42,6 +43,7 @@ const ui = {
|
||||||
console: true, // log messages to browser console
|
console: true, // log messages to browser console
|
||||||
maxFPSframes: 10, // keep fps history for how many frames
|
maxFPSframes: 10, // keep fps history for how many frames
|
||||||
modelsPreload: true, // preload human models on startup
|
modelsPreload: true, // preload human models on startup
|
||||||
|
modelsWarmup: true, // warmup human models on startup
|
||||||
busy: false, // internal camera busy flag
|
busy: false, // internal camera busy flag
|
||||||
menuWidth: 0, // internal
|
menuWidth: 0, // internal
|
||||||
menuHeight: 0, // internal
|
menuHeight: 0, // internal
|
||||||
|
@ -89,12 +91,6 @@ function status(msg) {
|
||||||
if (div) div.innerText = msg;
|
if (div) div.innerText = msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
const human = new Human(userConfig);
|
|
||||||
if (typeof tf !== 'undefined') {
|
|
||||||
log('TensorFlow external version:', tf.version);
|
|
||||||
human.tf = tf; // use externally loaded version of tfjs
|
|
||||||
}
|
|
||||||
|
|
||||||
const compare = { enabled: false, original: null };
|
const compare = { enabled: false, original: null };
|
||||||
async function calcSimmilariry(result) {
|
async function calcSimmilariry(result) {
|
||||||
document.getElementById('compare-container').style.display = compare.enabled ? 'block' : 'none';
|
document.getElementById('compare-container').style.display = compare.enabled ? 'block' : 'none';
|
||||||
|
@ -564,20 +560,57 @@ async function drawWarmup(res) {
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
log('demo starting ...');
|
log('demo starting ...');
|
||||||
|
|
||||||
|
// parse url search params
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
log('url options:', params.toString());
|
||||||
|
if (params.has('worker')) {
|
||||||
|
ui.useWorker = JSON.parse(params.get('worker'));
|
||||||
|
log('overriding worker:', ui.useWorker);
|
||||||
|
}
|
||||||
|
if (params.has('backend')) {
|
||||||
|
userConfig.backend = JSON.parse(params.get('backend'));
|
||||||
|
log('overriding backend:', userConfig.backend);
|
||||||
|
}
|
||||||
|
if (params.has('preload')) {
|
||||||
|
ui.modelsPreload = JSON.parse(params.get('preload'));
|
||||||
|
log('overriding preload:', ui.modelsPreload);
|
||||||
|
}
|
||||||
|
if (params.has('warmup')) {
|
||||||
|
ui.modelsWarmup = JSON.parse(params.get('warmup'));
|
||||||
|
log('overriding warmup:', ui.modelsWarmup);
|
||||||
|
}
|
||||||
|
|
||||||
|
// create instance of human
|
||||||
|
human = new Human(userConfig);
|
||||||
|
if (typeof tf !== 'undefined') {
|
||||||
|
log('TensorFlow external version:', tf.version);
|
||||||
|
human.tf = tf; // use externally loaded version of tfjs
|
||||||
|
}
|
||||||
|
|
||||||
|
// setup main menu
|
||||||
setupMenu();
|
setupMenu();
|
||||||
document.getElementById('log').innerText = `Human: version ${human.version}`;
|
document.getElementById('log').innerText = `Human: version ${human.version}`;
|
||||||
|
|
||||||
|
// preload models
|
||||||
if (ui.modelsPreload && !ui.useWorker) {
|
if (ui.modelsPreload && !ui.useWorker) {
|
||||||
status('loading');
|
status('loading');
|
||||||
await human.load(userConfig); // this is not required, just pre-loads all models
|
await human.load(userConfig); // this is not required, just pre-loads all models
|
||||||
const loaded = Object.keys(human.models).filter((a) => human.models[a]);
|
const loaded = Object.keys(human.models).filter((a) => human.models[a]);
|
||||||
log('demo loaded models:', loaded);
|
log('demo loaded models:', loaded);
|
||||||
}
|
}
|
||||||
if (!ui.useWorker) {
|
|
||||||
|
// warmup models
|
||||||
|
if (ui.modelsWarmup && !ui.useWorker) {
|
||||||
status('initializing');
|
status('initializing');
|
||||||
const res = await human.warmup(userConfig); // this is not required, just pre-warms all models for faster initial inference
|
const res = await human.warmup(userConfig); // this is not required, just pre-warms all models for faster initial inference
|
||||||
if (res && res.canvas && ui.drawWarmup) await drawWarmup(res);
|
if (res && res.canvas && ui.drawWarmup) await drawWarmup(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setup camera
|
||||||
await setupCamera();
|
await setupCamera();
|
||||||
|
|
||||||
|
// ready
|
||||||
status('human: ready');
|
status('human: ready');
|
||||||
document.getElementById('loader').style.display = 'none';
|
document.getElementById('loader').style.display = 'none';
|
||||||
document.getElementById('play').style.display = 'block';
|
document.getElementById('play').style.display = 'block';
|
||||||
|
|
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
|
@ -184,8 +184,7 @@ async function compile(entryPoint, options) {
|
||||||
.getPreEmitDiagnostics(program)
|
.getPreEmitDiagnostics(program)
|
||||||
.concat(emit.diagnostics);
|
.concat(emit.diagnostics);
|
||||||
for (const info of diag) {
|
for (const info of diag) {
|
||||||
// @ts-ignore
|
const msg = info.messageText['messageText'] || info.messageText;
|
||||||
const msg = info.messageText.messageText || info.messageText;
|
|
||||||
if (msg.includes('package.json')) continue;
|
if (msg.includes('package.json')) continue;
|
||||||
if (info.file) {
|
if (info.file) {
|
||||||
const pos = info.file.getLineAndCharacterOfPosition(info.start || 0);
|
const pos = info.file.getLineAndCharacterOfPosition(info.start || 0);
|
||||||
|
@ -225,9 +224,9 @@ async function build(f, msg, dev = false) {
|
||||||
// if triggered from watch mode, rebuild only browser bundle
|
// if triggered from watch mode, rebuild only browser bundle
|
||||||
// if ((require.main !== module) && ((targetGroupName === 'browserNoBundle') || (targetGroupName === 'nodeGPU'))) continue;
|
// if ((require.main !== module) && ((targetGroupName === 'browserNoBundle') || (targetGroupName === 'nodeGPU'))) continue;
|
||||||
const meta = dev
|
const meta = dev
|
||||||
// @ts-ignore
|
// @ts-ignore // eslint-typescript complains about string enums used in js code
|
||||||
? await esbuild.build({ ...config.common, ...config.debug, ...targetOptions })
|
? await esbuild.build({ ...config.common, ...config.debug, ...targetOptions })
|
||||||
// @ts-ignore
|
// @ts-ignore // eslint-typescript complains about string enums used in js code
|
||||||
: await esbuild.build({ ...config.common, ...config.production, ...targetOptions });
|
: await esbuild.build({ ...config.common, ...config.production, ...targetOptions });
|
||||||
const stats = await getStats(meta);
|
const stats = await getStats(meta);
|
||||||
log.state(`Build for: ${targetGroupName} type: ${targetName}:`, stats);
|
log.state(`Build for: ${targetGroupName} type: ${targetName}:`, stats);
|
||||||
|
|
|
@ -21,8 +21,8 @@ Repository: **<${app.repository.url}>**
|
||||||
|
|
||||||
async function update(f) {
|
async function update(f) {
|
||||||
const gitLog = await git.log();
|
const gitLog = await git.log();
|
||||||
// @ts-ignore
|
const entries = [...gitLog.all];
|
||||||
const log = gitLog.all.sort((a, b) => (new Date(b.date).getTime() - new Date(a.date).getTime()));
|
const log = entries.sort((a, b) => (new Date(b.date).getTime() - new Date(a.date).getTime()));
|
||||||
|
|
||||||
let previous = '';
|
let previous = '';
|
||||||
const headings = [];
|
const headings = [];
|
||||||
|
|
|
@ -109,6 +109,7 @@ function handle(url) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function handle(url) {
|
function handle(url) {
|
||||||
|
url = url.split(/[?#]/)[0];
|
||||||
const result = { ok: false, stat: {}, file: '' };
|
const result = { ok: false, stat: {}, file: '' };
|
||||||
const checkFile = (f) => {
|
const checkFile = (f) => {
|
||||||
result.file = f;
|
result.file = f;
|
||||||
|
|
|
@ -41,7 +41,6 @@ function replaceRawCoordinates(rawCoords, newCoords, prefix, keys) {
|
||||||
for (let i = 0; i < coords.MESH_TO_IRIS_INDICES_MAP.length; i++) {
|
for (let i = 0; i < coords.MESH_TO_IRIS_INDICES_MAP.length; i++) {
|
||||||
const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i];
|
const { key, indices } = coords.MESH_TO_IRIS_INDICES_MAP[i];
|
||||||
const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`];
|
const originalIndices = coords.MESH_ANNOTATIONS[`${prefix}${key}`];
|
||||||
// @ts-ignore
|
|
||||||
if (!keys || keys.includes(key)) {
|
if (!keys || keys.includes(key)) {
|
||||||
for (let j = 0; j < indices.length; j++) {
|
for (let j = 0; j < indices.length; j++) {
|
||||||
const index = indices[j];
|
const index = indices[j];
|
||||||
|
|
|
@ -64,8 +64,7 @@ export const hand = (res) => {
|
||||||
for (let i = 0; i < res.length; i++) {
|
for (let i = 0; i < res.length; i++) {
|
||||||
const fingers: Array<{ name: string, position: number }> = [];
|
const fingers: Array<{ name: string, position: number }> = [];
|
||||||
for (const [finger, pos] of Object.entries(res[i]['annotations'])) {
|
for (const [finger, pos] of Object.entries(res[i]['annotations'])) {
|
||||||
// @ts-ignore
|
if (finger !== 'palmBase' && Array.isArray(pos)) fingers.push({ name: finger.toLowerCase(), position: pos[0] }); // get tip of each finger
|
||||||
if (finger !== 'palmBase') fingers.push({ name: finger.toLowerCase(), position: pos[0] }); // get tip of each finger
|
|
||||||
}
|
}
|
||||||
if (fingers && fingers.length > 0) {
|
if (fingers && fingers.length > 0) {
|
||||||
const closest = fingers.reduce((best, a) => (best.position[2] < a.position[2] ? best : a));
|
const closest = fingers.reduce((best, a) => (best.position[2] < a.position[2] ? best : a));
|
||||||
|
|
15
src/human.ts
15
src/human.ts
|
@ -124,7 +124,7 @@ export class Human {
|
||||||
faceres: null,
|
faceres: null,
|
||||||
};
|
};
|
||||||
// export access to image processing
|
// export access to image processing
|
||||||
// @ts-ignore
|
// @ts-ignore // typescript cannot infer type
|
||||||
this.image = (input: Input) => image.process(input, this.config);
|
this.image = (input: Input) => image.process(input, this.config);
|
||||||
// export raw access to underlying models
|
// export raw access to underlying models
|
||||||
this.classes = {
|
this.classes = {
|
||||||
|
@ -214,9 +214,9 @@ export class Human {
|
||||||
this.models.gender,
|
this.models.gender,
|
||||||
this.models.emotion,
|
this.models.emotion,
|
||||||
this.models.embedding,
|
this.models.embedding,
|
||||||
// @ts-ignore
|
// @ts-ignore // typescript cannot infer type
|
||||||
this.models.handpose,
|
this.models.handpose,
|
||||||
// @ts-ignore false warning with latest @typescript-eslint
|
// @ts-ignore // typescript cannot infer type
|
||||||
this.models.posenet,
|
this.models.posenet,
|
||||||
this.models.blazepose,
|
this.models.blazepose,
|
||||||
this.models.efficientpose,
|
this.models.efficientpose,
|
||||||
|
@ -422,15 +422,14 @@ export class Human {
|
||||||
if (this.config.async) {
|
if (this.config.async) {
|
||||||
[faceRes, bodyRes, handRes, objectRes] = await Promise.all([faceRes, bodyRes, handRes, objectRes]);
|
[faceRes, bodyRes, handRes, objectRes] = await Promise.all([faceRes, bodyRes, handRes, objectRes]);
|
||||||
}
|
}
|
||||||
process.tensor.dispose();
|
tf.dispose(process.tensor);
|
||||||
|
|
||||||
if (this.config.scoped) this.tf.engine().endScope();
|
if (this.config.scoped) this.tf.engine().endScope();
|
||||||
this.analyze('End Scope:');
|
this.analyze('End Scope:');
|
||||||
|
|
||||||
let gestureRes = [];
|
let gestureRes: any[] = [];
|
||||||
if (this.config.gesture.enabled) {
|
if (this.config.gesture.enabled) {
|
||||||
timeStamp = now();
|
timeStamp = now();
|
||||||
// @ts-ignore
|
|
||||||
gestureRes = [...gesture.face(faceRes), ...gesture.body(bodyRes), ...gesture.hand(handRes), ...gesture.iris(faceRes)];
|
gestureRes = [...gesture.face(faceRes), ...gesture.body(bodyRes), ...gesture.hand(handRes), ...gesture.iris(faceRes)];
|
||||||
if (!this.config.async) this.perf.gesture = Math.trunc(now() - timeStamp);
|
if (!this.config.async) this.perf.gesture = Math.trunc(now() - timeStamp);
|
||||||
else if (this.perf.gesture) delete this.perf.gesture;
|
else if (this.perf.gesture) delete this.perf.gesture;
|
||||||
|
@ -507,8 +506,8 @@ export class Human {
|
||||||
#warmupNode = async () => {
|
#warmupNode = async () => {
|
||||||
const atob = (str) => Buffer.from(str, 'base64');
|
const atob = (str) => Buffer.from(str, 'base64');
|
||||||
const img = this.config.warmup === 'face' ? atob(sample.face) : atob(sample.body);
|
const img = this.config.warmup === 'face' ? atob(sample.face) : atob(sample.body);
|
||||||
// @ts-ignore
|
// @ts-ignore // tf.node is only defined when compiling for nodejs
|
||||||
const data = tf.node.decodeJpeg(img); // tf.node is only defined when compiling for nodejs
|
const data = tf.node?.decodeJpeg(img);
|
||||||
const expanded = data.expandDims(0);
|
const expanded = data.expandDims(0);
|
||||||
this.tf.dispose(data);
|
this.tf.dispose(data);
|
||||||
// log('Input:', expanded);
|
// log('Input:', expanded);
|
||||||
|
|
|
@ -1,19 +1,17 @@
|
||||||
// @ts-nocheck
|
|
||||||
|
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as fxImage from './imagefx';
|
import * as fxImage from './imagefx';
|
||||||
|
|
||||||
const maxSize = 2048;
|
const maxSize = 2048;
|
||||||
// internal temp canvases
|
// internal temp canvases
|
||||||
let inCanvas = null;
|
let inCanvas;
|
||||||
let outCanvas = null;
|
let outCanvas;
|
||||||
// instance of fximage
|
// instance of fximage
|
||||||
let fx = null;
|
let fx;
|
||||||
|
|
||||||
// process input image and return tensor
|
// process input image and return tensor
|
||||||
// input can be tensor, imagedata, htmlimageelement, htmlvideoelement
|
// input can be tensor, imagedata, htmlimageelement, htmlvideoelement
|
||||||
// input is resized and run through imagefx filter
|
// input is resized and run through imagefx filter
|
||||||
export function process(input, config): { tensor: tf.Tensor, canvas: OffscreenCanvas | HTMLCanvasElement } {
|
export function process(input, config): { tensor: typeof tf.Tensor | null, canvas: OffscreenCanvas | HTMLCanvasElement } {
|
||||||
let tensor;
|
let tensor;
|
||||||
if (!input) throw new Error('Human: Input is missing');
|
if (!input) throw new Error('Human: Input is missing');
|
||||||
if (
|
if (
|
||||||
|
@ -32,8 +30,8 @@ export function process(input, config): { tensor: tf.Tensor, canvas: OffscreenCa
|
||||||
if (input instanceof tf.Tensor) {
|
if (input instanceof tf.Tensor) {
|
||||||
tensor = tf.clone(input);
|
tensor = tf.clone(input);
|
||||||
} else {
|
} else {
|
||||||
const originalWidth = input.naturalWidth || input.videoWidth || input.width || (input.shape && (input.shape[1] > 0));
|
const originalWidth = input['naturalWidth'] || input['videoWidth'] || input['width'] || (input['shape'] && (input['shape'][1] > 0));
|
||||||
const originalHeight = input.naturalHeight || input.videoHeight || input.height || (input.shape && (input.shape[2] > 0));
|
const originalHeight = input['naturalHeight'] || input['videoHeight'] || input['height'] || (input['shape'] && (input['shape'][2] > 0));
|
||||||
let targetWidth = originalWidth;
|
let targetWidth = originalWidth;
|
||||||
let targetHeight = originalHeight;
|
let targetHeight = originalHeight;
|
||||||
if (targetWidth > maxSize) {
|
if (targetWidth > maxSize) {
|
||||||
|
@ -49,19 +47,19 @@ export function process(input, config): { tensor: tf.Tensor, canvas: OffscreenCa
|
||||||
if (config.filter.height > 0) targetHeight = config.filter.height;
|
if (config.filter.height > 0) targetHeight = config.filter.height;
|
||||||
else if (config.filter.width > 0) targetHeight = originalHeight * (config.filter.width / originalWidth);
|
else if (config.filter.width > 0) targetHeight = originalHeight * (config.filter.width / originalWidth);
|
||||||
if (!targetWidth || !targetHeight) throw new Error('Human: Input cannot determine dimension');
|
if (!targetWidth || !targetHeight) throw new Error('Human: Input cannot determine dimension');
|
||||||
if (!inCanvas || (inCanvas.width !== targetWidth) || (inCanvas.height !== targetHeight)) {
|
if (!inCanvas || (inCanvas?.width !== targetWidth) || (inCanvas?.height !== targetHeight)) {
|
||||||
inCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas');
|
inCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas');
|
||||||
if (inCanvas.width !== targetWidth) inCanvas.width = targetWidth;
|
if (inCanvas?.width !== targetWidth) inCanvas.width = targetWidth;
|
||||||
if (inCanvas.height !== targetHeight) inCanvas.height = targetHeight;
|
if (inCanvas?.height !== targetHeight) inCanvas.height = targetHeight;
|
||||||
}
|
}
|
||||||
const ctx = inCanvas.getContext('2d');
|
const ctx = inCanvas.getContext('2d');
|
||||||
if (input instanceof ImageData) ctx.putImageData(input, 0, 0);
|
if (input instanceof ImageData) ctx.putImageData(input, 0, 0);
|
||||||
else ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas.width, inCanvas.height);
|
else ctx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas?.width, inCanvas?.height);
|
||||||
if (config.filter.enabled) {
|
if (config.filter.enabled) {
|
||||||
if (!fx || !outCanvas || (inCanvas.width !== outCanvas.width) || (inCanvas.height !== outCanvas.height)) {
|
if (!fx || !outCanvas || (inCanvas.width !== outCanvas.width) || (inCanvas?.height !== outCanvas?.height)) {
|
||||||
outCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(inCanvas.width, inCanvas.height) : document.createElement('canvas');
|
outCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(inCanvas?.width, inCanvas?.height) : document.createElement('canvas');
|
||||||
if (outCanvas.width !== inCanvas.width) outCanvas.width = inCanvas.width;
|
if (outCanvas?.width !== inCanvas?.width) outCanvas.width = inCanvas?.width;
|
||||||
if (outCanvas.height !== inCanvas.height) outCanvas.height = inCanvas.height;
|
if (outCanvas?.height !== inCanvas?.height) outCanvas.height = inCanvas?.height;
|
||||||
// log('created FX filter');
|
// log('created FX filter');
|
||||||
fx = tf.ENV.flags.IS_BROWSER ? new fxImage.GLImageFilter({ canvas: outCanvas }) : null; // && (typeof document !== 'undefined')
|
fx = tf.ENV.flags.IS_BROWSER ? new fxImage.GLImageFilter({ canvas: outCanvas }) : null; // && (typeof document !== 'undefined')
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,10 +17,7 @@ function GLProgram(gl, vertexSource, fragmentSource) {
|
||||||
const shader = gl.createShader(type);
|
const shader = gl.createShader(type);
|
||||||
gl.shaderSource(shader, source);
|
gl.shaderSource(shader, source);
|
||||||
gl.compileShader(shader);
|
gl.compileShader(shader);
|
||||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw new Error('Filter: GL compile failed', gl.getShaderInfoLog(shader));
|
||||||
// @ts-ignore
|
|
||||||
throw new Error('Filter: GL compile failed', gl.getShaderInfoLog(shader));
|
|
||||||
}
|
|
||||||
return shader;
|
return shader;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -33,10 +30,7 @@ function GLProgram(gl, vertexSource, fragmentSource) {
|
||||||
gl.attachShader(this.id, _fsh);
|
gl.attachShader(this.id, _fsh);
|
||||||
gl.linkProgram(this.id);
|
gl.linkProgram(this.id);
|
||||||
|
|
||||||
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) {
|
if (!gl.getProgramParameter(this.id, gl.LINK_STATUS)) throw new Error('Filter: GL link failed', gl.getProgramInfoLog(this.id));
|
||||||
// @ts-ignore
|
|
||||||
throw new Error('Filter: GL link failed', gl.getProgramInfoLog(this.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
gl.useProgram(this.id);
|
gl.useProgram(this.id);
|
||||||
// Collect attributes
|
// Collect attributes
|
||||||
|
@ -123,7 +117,6 @@ export function GLImageFilter(params) {
|
||||||
};
|
};
|
||||||
|
|
||||||
const _getTempFramebuffer = function (index) {
|
const _getTempFramebuffer = function (index) {
|
||||||
// @ts-ignore
|
|
||||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||||
return _tempFramebuffers[index];
|
return _tempFramebuffers[index];
|
||||||
};
|
};
|
||||||
|
@ -138,7 +131,6 @@ export function GLImageFilter(params) {
|
||||||
source = _sourceTexture;
|
source = _sourceTexture;
|
||||||
} else {
|
} else {
|
||||||
// All following draw calls use the temp buffer last drawn to
|
// All following draw calls use the temp buffer last drawn to
|
||||||
// @ts-ignore
|
|
||||||
source = _getTempFramebuffer(_currentFramebufferIndex)?.texture;
|
source = _getTempFramebuffer(_currentFramebufferIndex)?.texture;
|
||||||
}
|
}
|
||||||
_drawCount++;
|
_drawCount++;
|
||||||
|
@ -151,7 +143,6 @@ export function GLImageFilter(params) {
|
||||||
} else {
|
} else {
|
||||||
// Intermediate draw call - get a temp buffer to draw to
|
// Intermediate draw call - get a temp buffer to draw to
|
||||||
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
_currentFramebufferIndex = (_currentFramebufferIndex + 1) % 2;
|
||||||
// @ts-ignore
|
|
||||||
target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo;
|
target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo;
|
||||||
}
|
}
|
||||||
// Bind the source and target and draw the two triangles
|
// Bind the source and target and draw the two triangles
|
||||||
|
|
|
@ -12,8 +12,9 @@ const scaleBox = 2.5; // increase box size
|
||||||
export async function load(config) {
|
export async function load(config) {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath));
|
model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath));
|
||||||
// @ts-ignore
|
const inputs = Object.values(model.modelSignature['inputs']);
|
||||||
model.inputSize = parseInt(Object.values(model.modelSignature['inputs'])[0].tensorShape.dim[2].size);
|
model.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||||
|
if (!model.inputSize) throw new Error(`Human: Cannot determine model inputSize: ${config.object.modelPath}`);
|
||||||
if (!model || !model.modelUrl) log('load model failed:', config.object.modelPath);
|
if (!model || !model.modelUrl) log('load model failed:', config.object.modelPath);
|
||||||
else if (config.debug) log('load model:', model.modelUrl);
|
else if (config.debug) log('load model:', model.modelUrl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ export function info(): { platform: string, agent: string } {
|
||||||
if (typeof navigator !== 'undefined') {
|
if (typeof navigator !== 'undefined') {
|
||||||
const raw = navigator.userAgent.match(/\(([^()]+)\)/g);
|
const raw = navigator.userAgent.match(/\(([^()]+)\)/g);
|
||||||
if (raw && raw[0]) {
|
if (raw && raw[0]) {
|
||||||
// @ts-ignore
|
const platformMatch = raw[0].match(/\(([^()]+)\)/g);
|
||||||
platform = raw[0].match(/\(([^()]+)\)/g)[0].replace(/\(|\)/g, '');
|
platform = platformMatch ? platformMatch[0].replace(/\(|\)/g, '') : '';
|
||||||
agent = navigator.userAgent.replace(raw[0], '');
|
agent = navigator.userAgent.replace(raw[0], '');
|
||||||
if (platform[1]) agent = agent.replace(raw[1], '');
|
if (platform[1]) agent = agent.replace(raw[1], '');
|
||||||
agent = agent.replace(/ /g, ' ');
|
agent = agent.replace(/ /g, ' ');
|
||||||
|
|
|
@ -4,8 +4,8 @@ import * as tf from '../../dist/tfjs.esm.js';
|
||||||
export const config = {
|
export const config = {
|
||||||
name: 'humangl',
|
name: 'humangl',
|
||||||
priority: 99,
|
priority: 99,
|
||||||
canvas: null,
|
canvas: <null | OffscreenCanvas | HTMLCanvasElement>null,
|
||||||
gl: null,
|
gl: <any>null,
|
||||||
width: 1024,
|
width: 1024,
|
||||||
height: 1024,
|
height: 1024,
|
||||||
webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2
|
webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2
|
||||||
|
@ -24,14 +24,12 @@ export function register(): void {
|
||||||
if (!tf.findBackend(config.name)) {
|
if (!tf.findBackend(config.name)) {
|
||||||
log('backend registration:', config.name);
|
log('backend registration:', config.name);
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
|
||||||
config.canvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(config.width, config.height) : document.createElement('canvas');
|
config.canvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(config.width, config.height) : document.createElement('canvas');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log('error: cannot create canvas:', err);
|
log('error: cannot create canvas:', err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// @ts-ignore
|
|
||||||
config.gl = config.canvas.getContext('webgl2', config.webGLattr);
|
config.gl = config.canvas.getContext('webgl2', config.webGLattr);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
log('error: cannot get WebGL2 context:', err);
|
log('error: cannot get WebGL2 context:', err);
|
||||||
|
@ -62,7 +60,6 @@ export function register(): void {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
tf.ENV.set('WEBGL_VERSION', 2);
|
tf.ENV.set('WEBGL_VERSION', 2);
|
||||||
// @ts-ignore
|
|
||||||
// tf.ENV.set('WEBGL_MAX_TEXTURE_SIZE', config.gl.getParameter(config.gl.MAX_TEXTURE_SIZE));
|
// tf.ENV.set('WEBGL_MAX_TEXTURE_SIZE', config.gl.getParameter(config.gl.MAX_TEXTURE_SIZE));
|
||||||
// tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true);
|
// tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true);
|
||||||
// tf.ENV.set('WEBGL_PACK_DEPTHWISECONV', true);
|
// tf.ENV.set('WEBGL_PACK_DEPTHWISECONV', true);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
export declare function process(input: any, config: any): {
|
export declare function process(input: any, config: any): {
|
||||||
tensor: tf.Tensor;
|
tensor: typeof tf.Tensor | null;
|
||||||
canvas: OffscreenCanvas | HTMLCanvasElement;
|
canvas: OffscreenCanvas | HTMLCanvasElement;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
export declare const config: {
|
export declare const config: {
|
||||||
name: string;
|
name: string;
|
||||||
priority: number;
|
priority: number;
|
||||||
canvas: null;
|
canvas: OffscreenCanvas | HTMLCanvasElement | null;
|
||||||
gl: null;
|
gl: any;
|
||||||
width: number;
|
width: number;
|
||||||
height: number;
|
height: number;
|
||||||
webGLattr: {
|
webGLattr: {
|
||||||
|
|
2
wiki
2
wiki
|
@ -1 +1 @@
|
||||||
Subproject commit d09d36cf9de309728504402bf301ac3ab018de65
|
Subproject commit 652dee1013ae99789199cc229d6652b3323ae7de
|
Loading…
Reference in New Issue