mirror of https://github.com/vladmandic/human
update imagefx
parent
9d4a9b66a0
commit
cd16dcce49
28
README.md
28
README.md
|
@ -1,6 +1,16 @@
|
|||
# Human Library
|
||||
|
||||
## 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition
|
||||
### 3D Face Detection, Face Embedding & Recognition,
|
||||
### Body Pose Tracking, Hand & Finger Tracking,
|
||||
### Iris Analysis, Age & Gender & Emotion Prediction
|
||||
### & Gesture Recognition
|
||||
|
||||
<br>
|
||||
|
||||
Native JavaScript module using TensorFlow/JS Machine Learning library
|
||||
Compatible with *Browser*, *WebWorker* and *NodeJS* execution on both Windows and Linux
|
||||
- Browser/WebWorker: Compatible with *CPU*, *WebGL*, *WASM* and *WebGPU* backends
|
||||
- NodeJS: Compatible with software *tfjs-node* and CUDA accelerated backends *tfjs-node-gpu*
|
||||
|
||||
<br>
|
||||
|
||||
|
@ -39,28 +49,17 @@
|
|||
|
||||
<br>
|
||||
|
||||
Compatible with *Browser*, *WebWorker* and *NodeJS* execution on both Windows and Linux
|
||||
- Browser/WebWorker: Compatible with *CPU*, *WebGL*, *WASM* and *WebGPU* backends
|
||||
- NodeJS: Compatible with software *tfjs-node* and CUDA accelerated backends *tfjs-node-gpu*
|
||||
- (and maybe with React-Native as it doesn't use any DOM objects)
|
||||
|
||||
<br>
|
||||
|
||||
*See [issues](https://github.com/vladmandic/human/issues?q=) and [discussions](https://github.com/vladmandic/human/discussions) for list of known limitations and planned enhancements*
|
||||
|
||||
*Suggestions are welcome!*
|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
<br><hr><br>
|
||||
|
||||
## Options ##
|
||||
|
||||

|
||||
|
||||
<br>
|
||||
<hr>
|
||||
<br>
|
||||
<br><hr><br>
|
||||
|
||||
## Examples
|
||||
|
||||
|
@ -75,4 +74,3 @@ Compatible with *Browser*, *WebWorker* and *NodeJS* execution on both Windows an
|
|||
**Using webcam:**
|
||||
|
||||

|
||||
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import Human from '../dist/human.esm.js';
|
||||
// eslint-disable-next-line no-unused-vars, @typescript-eslint/no-unused-vars
|
||||
// import * as tf from '@tensorflow/tfjs';
|
||||
// import Human from '../dist/human.esm-nobundle.js';
|
||||
|
||||
import Human from '../dist/human.esm.js'; // equivalent of @vladmandic/human
|
||||
|
||||
import draw from './draw.js';
|
||||
import Menu from './menu.js';
|
||||
import GLBench from './gl-bench.js';
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"inputs": {
|
||||
"dist/human.esm.js": {
|
||||
"bytes": 1347254,
|
||||
"bytes": 1347469,
|
||||
"imports": []
|
||||
},
|
||||
"demo/draw.js": {
|
||||
|
@ -17,7 +17,7 @@
|
|||
"imports": []
|
||||
},
|
||||
"demo/browser.js": {
|
||||
"bytes": 26540,
|
||||
"bytes": 26752,
|
||||
"imports": [
|
||||
{
|
||||
"path": "dist/human.esm.js",
|
||||
|
@ -43,14 +43,14 @@
|
|||
"imports": [],
|
||||
"exports": [],
|
||||
"inputs": {},
|
||||
"bytes": 2021929
|
||||
"bytes": 2022314
|
||||
},
|
||||
"dist/demo-browser-index.js": {
|
||||
"imports": [],
|
||||
"exports": [],
|
||||
"inputs": {
|
||||
"dist/human.esm.js": {
|
||||
"bytesInOutput": 1339760
|
||||
"bytesInOutput": 1339993
|
||||
},
|
||||
"demo/draw.js": {
|
||||
"bytesInOutput": 6204
|
||||
|
@ -65,7 +65,7 @@
|
|||
"bytesInOutput": 17340
|
||||
}
|
||||
},
|
||||
"bytes": 1388144
|
||||
"bytes": 1388377
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
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
|
@ -5,7 +5,7 @@
|
|||
"imports": []
|
||||
},
|
||||
"dist/tfjs.esm.js": {
|
||||
"bytes": 1073705,
|
||||
"bytes": 1073613,
|
||||
"imports": []
|
||||
},
|
||||
"src/tfjs/backend.ts": {
|
||||
|
@ -388,11 +388,11 @@
|
|||
"imports": []
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytes": 19447,
|
||||
"bytes": 19372,
|
||||
"imports": []
|
||||
},
|
||||
"src/image.ts": {
|
||||
"bytes": 5867,
|
||||
"bytes": 5902,
|
||||
"imports": [
|
||||
{
|
||||
"path": "src/log.ts",
|
||||
|
@ -417,11 +417,11 @@
|
|||
"imports": []
|
||||
},
|
||||
"package.json": {
|
||||
"bytes": 2529,
|
||||
"bytes": 2560,
|
||||
"imports": []
|
||||
},
|
||||
"src/human.ts": {
|
||||
"bytes": 19583,
|
||||
"bytes": 19703,
|
||||
"imports": [
|
||||
{
|
||||
"path": "src/log.ts",
|
||||
|
@ -499,7 +499,7 @@
|
|||
"imports": [],
|
||||
"exports": [],
|
||||
"inputs": {},
|
||||
"bytes": 1924959
|
||||
"bytes": 1925031
|
||||
},
|
||||
"dist/human.esm.js": {
|
||||
"imports": [],
|
||||
|
@ -513,14 +513,11 @@
|
|||
"src/posenet/keypoints.ts": {
|
||||
"bytesInOutput": 1690
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytesInOutput": 11016
|
||||
},
|
||||
"src/log.ts": {
|
||||
"bytesInOutput": 252
|
||||
},
|
||||
"dist/tfjs.esm.js": {
|
||||
"bytesInOutput": 1064700
|
||||
"bytesInOutput": 1064608
|
||||
},
|
||||
"src/tfjs/backend.ts": {
|
||||
"bytesInOutput": 1205
|
||||
|
@ -541,7 +538,7 @@
|
|||
"bytesInOutput": 5040
|
||||
},
|
||||
"src/human.ts": {
|
||||
"bytesInOutput": 10311
|
||||
"bytesInOutput": 10617
|
||||
},
|
||||
"src/faceboxes/faceboxes.ts": {
|
||||
"bytesInOutput": 1549
|
||||
|
@ -609,8 +606,11 @@
|
|||
"src/gesture/gesture.ts": {
|
||||
"bytesInOutput": 2391
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytesInOutput": 10975
|
||||
},
|
||||
"src/image.ts": {
|
||||
"bytesInOutput": 2454
|
||||
"bytesInOutput": 2452
|
||||
},
|
||||
"config.js": {
|
||||
"bytesInOutput": 1426
|
||||
|
@ -619,10 +619,10 @@
|
|||
"bytesInOutput": 55295
|
||||
},
|
||||
"package.json": {
|
||||
"bytesInOutput": 2528
|
||||
"bytesInOutput": 2572
|
||||
}
|
||||
},
|
||||
"bytes": 1347254
|
||||
"bytes": 1347469
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
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
|
@ -388,11 +388,11 @@
|
|||
"imports": []
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytes": 19447,
|
||||
"bytes": 19372,
|
||||
"imports": []
|
||||
},
|
||||
"src/image.ts": {
|
||||
"bytes": 5867,
|
||||
"bytes": 5902,
|
||||
"imports": [
|
||||
{
|
||||
"path": "src/log.ts",
|
||||
|
@ -417,11 +417,11 @@
|
|||
"imports": []
|
||||
},
|
||||
"package.json": {
|
||||
"bytes": 2529,
|
||||
"bytes": 2560,
|
||||
"imports": []
|
||||
},
|
||||
"src/human.ts": {
|
||||
"bytes": 19583,
|
||||
"bytes": 19703,
|
||||
"imports": [
|
||||
{
|
||||
"path": "src/log.ts",
|
||||
|
@ -499,7 +499,7 @@
|
|||
"imports": [],
|
||||
"exports": [],
|
||||
"inputs": {},
|
||||
"bytes": 705489
|
||||
"bytes": 705616
|
||||
},
|
||||
"dist/human.node-gpu.js": {
|
||||
"imports": [],
|
||||
|
@ -514,11 +514,8 @@
|
|||
"src/posenet/keypoints.ts": {
|
||||
"bytesInOutput": 1677
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytesInOutput": 11012
|
||||
},
|
||||
"src/human.ts": {
|
||||
"bytesInOutput": 10478
|
||||
"bytesInOutput": 10625
|
||||
},
|
||||
"src/log.ts": {
|
||||
"bytesInOutput": 251
|
||||
|
@ -542,7 +539,7 @@
|
|||
"bytesInOutput": 28973
|
||||
},
|
||||
"src/faceboxes/faceboxes.ts": {
|
||||
"bytesInOutput": 1591
|
||||
"bytesInOutput": 1586
|
||||
},
|
||||
"src/profile.ts": {
|
||||
"bytesInOutput": 604
|
||||
|
@ -551,7 +548,7 @@
|
|||
"bytesInOutput": 822
|
||||
},
|
||||
"src/gender/gender.ts": {
|
||||
"bytesInOutput": 1310
|
||||
"bytesInOutput": 1302
|
||||
},
|
||||
"src/emotion/emotion.ts": {
|
||||
"bytesInOutput": 1247
|
||||
|
@ -608,7 +605,10 @@
|
|||
"bytesInOutput": 2391
|
||||
},
|
||||
"src/image.ts": {
|
||||
"bytesInOutput": 2455
|
||||
"bytesInOutput": 2458
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytesInOutput": 10973
|
||||
},
|
||||
"config.js": {
|
||||
"bytesInOutput": 1426
|
||||
|
@ -617,10 +617,10 @@
|
|||
"bytesInOutput": 55295
|
||||
},
|
||||
"package.json": {
|
||||
"bytesInOutput": 2525
|
||||
"bytesInOutput": 2569
|
||||
}
|
||||
},
|
||||
"bytes": 276897
|
||||
"bytes": 277039
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -5,7 +5,7 @@
|
|||
"imports": []
|
||||
},
|
||||
"dist/tfjs.esm.js": {
|
||||
"bytes": 1073705,
|
||||
"bytes": 1073613,
|
||||
"imports": []
|
||||
},
|
||||
"src/tfjs/backend.ts": {
|
||||
|
@ -388,11 +388,11 @@
|
|||
"imports": []
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytes": 19447,
|
||||
"bytes": 19372,
|
||||
"imports": []
|
||||
},
|
||||
"src/image.ts": {
|
||||
"bytes": 5867,
|
||||
"bytes": 5902,
|
||||
"imports": [
|
||||
{
|
||||
"path": "src/log.ts",
|
||||
|
@ -417,11 +417,11 @@
|
|||
"imports": []
|
||||
},
|
||||
"package.json": {
|
||||
"bytes": 2529,
|
||||
"bytes": 2560,
|
||||
"imports": []
|
||||
},
|
||||
"src/human.ts": {
|
||||
"bytes": 19583,
|
||||
"bytes": 19703,
|
||||
"imports": [
|
||||
{
|
||||
"path": "src/log.ts",
|
||||
|
@ -499,7 +499,7 @@
|
|||
"imports": [],
|
||||
"exports": [],
|
||||
"inputs": {},
|
||||
"bytes": 1924970
|
||||
"bytes": 1925042
|
||||
},
|
||||
"dist/human.ts": {
|
||||
"imports": [],
|
||||
|
@ -511,17 +511,14 @@
|
|||
"src/posenet/keypoints.ts": {
|
||||
"bytesInOutput": 1690
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytesInOutput": 11016
|
||||
},
|
||||
"src/human.ts": {
|
||||
"bytesInOutput": 10347
|
||||
"bytesInOutput": 10653
|
||||
},
|
||||
"src/log.ts": {
|
||||
"bytesInOutput": 252
|
||||
},
|
||||
"dist/tfjs.esm.js": {
|
||||
"bytesInOutput": 1064700
|
||||
"bytesInOutput": 1064608
|
||||
},
|
||||
"src/tfjs/backend.ts": {
|
||||
"bytesInOutput": 1205
|
||||
|
@ -607,8 +604,11 @@
|
|||
"src/gesture/gesture.ts": {
|
||||
"bytesInOutput": 2391
|
||||
},
|
||||
"src/imagefx.js": {
|
||||
"bytesInOutput": 10975
|
||||
},
|
||||
"src/image.ts": {
|
||||
"bytesInOutput": 2454
|
||||
"bytesInOutput": 2452
|
||||
},
|
||||
"config.js": {
|
||||
"bytesInOutput": 1426
|
||||
|
@ -617,10 +617,10 @@
|
|||
"bytesInOutput": 55295
|
||||
},
|
||||
"package.json": {
|
||||
"bytesInOutput": 2528
|
||||
"bytesInOutput": 2572
|
||||
}
|
||||
},
|
||||
"bytes": 1347296
|
||||
"bytes": 1347511
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -366,9 +366,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.14.28",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.28.tgz",
|
||||
"integrity": "sha512-lg55ArB+ZiHHbBBttLpzD07akz0QPrZgUODNakeC09i62dnrywr9mFErHuaPlB6I7z+sEbK+IYmplahvplCj2g==",
|
||||
"version": "14.14.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.30.tgz",
|
||||
"integrity": "sha512-gUWhy8s45fQp4PqqKecsnOkdW0kt1IaKjgOIR3HPokkzTmQj9ji2wWFID5THu1MKrtO+d4s2lVrlEhXUsPXSvg==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
|
@ -1026,9 +1026,9 @@
|
|||
}
|
||||
},
|
||||
"esbuild": {
|
||||
"version": "0.8.46",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.46.tgz",
|
||||
"integrity": "sha512-xck9sXNCNmjDHCCfxTCyhKTiFuEBweh+IDAhMLOJI990v1Fzii6MyIkT1LbkvjgoVgPX2SK1kpi5eZVGNrl8yg==",
|
||||
"version": "0.8.49",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.8.49.tgz",
|
||||
"integrity": "sha512-itiFVYv5UZz4NooO7/Y0bRGVDGz/M/cxKbl6zyNI5pnKaz1mZjvZXAFhhDVz6rGCmcdTKj5oag6rh8DaaSSmfQ==",
|
||||
"dev": true
|
||||
},
|
||||
"escalade": {
|
||||
|
@ -2572,9 +2572,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"simple-git": {
|
||||
"version": "2.35.0",
|
||||
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.35.0.tgz",
|
||||
"integrity": "sha512-VuXs2/HyZmZm43Z5IjvU+ahTmURh/Hmb/egmgNdFZuu8OEnW2emCalnL/4jRQkXeJvfzCTnev6wo5jtDmWw0Dw==",
|
||||
"version": "2.35.1",
|
||||
"resolved": "https://registry.npmjs.org/simple-git/-/simple-git-2.35.1.tgz",
|
||||
"integrity": "sha512-Y5/hXf5ivfMziWRNGhVsbiG+1h4CkTW2qVC3dRidLuSZYAPFbLCPP1d7rgiL40lgRPhPTBuhVzNJAV9glWstEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@kwsites/file-exists": "^1.1.1",
|
||||
|
@ -2837,9 +2837,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.3.0-dev.20210217",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.0-dev.20210217.tgz",
|
||||
"integrity": "sha512-gjh5m/gbj9hVmoTzb3yePdhCfw96aAXhiV4MqyYMyvlZzaw+IkIOGvQBc8Q9Vu72jdVE3mClIzrIg3o/Xw/vVw==",
|
||||
"version": "4.3.0-dev.20210219",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.0-dev.20210219.tgz",
|
||||
"integrity": "sha512-9ttM1StIx+z2L4NnLGaYkOKIJWWFwzL4KuvhQXfulqjl4PnNjAsrl5QKAbI07oEvS2wn4rUdGHYQnCxh3/biWQ==",
|
||||
"dev": true
|
||||
},
|
||||
"uri-js": {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
"main": "dist/human.node.js",
|
||||
"module": "dist/human.esm.js",
|
||||
"browser": "dist/human.esm.js",
|
||||
"types": "types/human.d.ts",
|
||||
"author": "Vladimir Mandic <mandic00@live.com>",
|
||||
"bugs": {
|
||||
"url": "https://github.com/vladmandic/human/issues"
|
||||
|
@ -32,13 +33,13 @@
|
|||
"@tensorflow/tfjs-layers": "^3.1.0",
|
||||
"@tensorflow/tfjs-node": "^3.1.0",
|
||||
"@tensorflow/tfjs-node-gpu": "^3.1.0",
|
||||
"@types/node": "^14.14.28",
|
||||
"@types/node": "^14.14.30",
|
||||
"@typescript-eslint/eslint-plugin": "^4.15.1",
|
||||
"@typescript-eslint/parser": "^4.15.1",
|
||||
"@vladmandic/pilogger": "^0.2.14",
|
||||
"chokidar": "^3.5.1",
|
||||
"dayjs": "^1.10.4",
|
||||
"esbuild": "^0.8.46",
|
||||
"esbuild": "^0.8.49",
|
||||
"eslint": "^7.20.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
|
@ -47,9 +48,9 @@
|
|||
"eslint-plugin-promise": "^4.3.1",
|
||||
"rimraf": "^3.0.2",
|
||||
"seedrandom": "^3.0.5",
|
||||
"simple-git": "^2.35.0",
|
||||
"simple-git": "^2.35.1",
|
||||
"tslib": "^2.1.0",
|
||||
"typescript": "^4.3.0-dev.20210217"
|
||||
"typescript": "^4.3.0-dev.20210219"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",
|
||||
|
|
|
@ -209,7 +209,7 @@ async function build(f, msg) {
|
|||
for (const [targetGroupName, targetGroup] of Object.entries(targets)) {
|
||||
for (const [targetName, targetOptions] of Object.entries(targetGroup)) {
|
||||
// if triggered from watch mode, rebuild only browser bundle
|
||||
if ((require.main !== module) && (targetGroupName !== 'browserBundle')) continue;
|
||||
// if ((require.main !== module) && (targetGroupName !== 'browserBundle')) continue;
|
||||
await es.build({ ...common, ...targetOptions });
|
||||
const stats = await getStats(targetOptions.metafile);
|
||||
log.state(`Build for: ${targetGroupName} type: ${targetName}:`, stats);
|
||||
|
|
44
src/human.ts
44
src/human.ts
|
@ -101,7 +101,7 @@ class Human {
|
|||
// helper function: measure tensor leak
|
||||
analyze(...msg) {
|
||||
if (!this.analyzeMemoryLeaks) return;
|
||||
const current = tf.engine().state.numTensors;
|
||||
const current = this.tf.engine().state.numTensors;
|
||||
const previous = this.numTensors;
|
||||
this.numTensors = current;
|
||||
const leaked = current - previous;
|
||||
|
@ -112,11 +112,11 @@ class Human {
|
|||
sanity(input) {
|
||||
if (!this.checkSanity) return null;
|
||||
if (!input) return 'input is not defined';
|
||||
if (tf.ENV.flags.IS_NODE && !(input instanceof tf.Tensor)) {
|
||||
if (this.tf.ENV.flags.IS_NODE && !(input instanceof this.tf.Tensor)) {
|
||||
return 'input must be a tensor';
|
||||
}
|
||||
try {
|
||||
tf.getBackend();
|
||||
this.tf.getBackend();
|
||||
} catch {
|
||||
return 'backend not loaded';
|
||||
}
|
||||
|
@ -135,11 +135,11 @@ class Human {
|
|||
if (userConfig) this.config = mergeDeep(this.config, userConfig);
|
||||
|
||||
if (this.firstRun) {
|
||||
log(`version: ${this.version} TensorFlow/JS version: ${tf.version_core}`);
|
||||
log(`version: ${this.version} TensorFlow/JS version: ${this.tf.version_core}`);
|
||||
await this.checkBackend(true);
|
||||
if (tf.ENV.flags.IS_BROWSER) {
|
||||
if (this.tf.ENV.flags.IS_BROWSER) {
|
||||
log('configuration:', this.config);
|
||||
log('tf flags:', tf.ENV.flags);
|
||||
log('tf flags:', this.tf.ENV.flags);
|
||||
}
|
||||
}
|
||||
const face = this.config.face.detector.modelPath.includes('faceboxes') ? faceboxes : facemesh;
|
||||
|
@ -172,7 +172,7 @@ class Human {
|
|||
}
|
||||
|
||||
if (this.firstRun) {
|
||||
log('tf engine state:', tf.engine().state.numBytes, 'bytes', tf.engine().state.numTensors, 'tensors');
|
||||
log('tf engine state:', this.tf.engine().state.numBytes, 'bytes', this.tf.engine().state.numTensors, 'tensors');
|
||||
this.firstRun = false;
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ class Human {
|
|||
|
||||
// check if backend needs initialization if it changed
|
||||
async checkBackend(force = false) {
|
||||
if (this.config.backend && (this.config.backend !== '') && force || (tf.getBackend() !== this.config.backend)) {
|
||||
if (this.config.backend && (this.config.backend !== '') && force || (this.tf.getBackend() !== this.config.backend)) {
|
||||
const timeStamp = now();
|
||||
this.state = 'backend';
|
||||
/* force backend reload
|
||||
|
@ -199,32 +199,32 @@ class Human {
|
|||
|
||||
if (this.config.backend === 'wasm') {
|
||||
log('settings wasm path:', this.config.wasmPath);
|
||||
tf.setWasmPaths(this.config.wasmPath);
|
||||
const simd = await tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
|
||||
this.tf.setWasmPaths(this.config.wasmPath);
|
||||
const simd = await this.tf.env().getAsync('WASM_HAS_SIMD_SUPPORT');
|
||||
if (!simd) log('warning: wasm simd support is not enabled');
|
||||
}
|
||||
|
||||
if (this.config.backend === 'humangl') backend.register();
|
||||
try {
|
||||
await tf.setBackend(this.config.backend);
|
||||
await this.tf.setBackend(this.config.backend);
|
||||
} catch (err) {
|
||||
log('error: cannot set backend:', this.config.backend, err);
|
||||
}
|
||||
tf.enableProdMode();
|
||||
this.tf.enableProdMode();
|
||||
/* debug mode is really too mcuh
|
||||
tf.enableDebugMode();
|
||||
*/
|
||||
if (tf.getBackend() === 'webgl') {
|
||||
if (this.tf.getBackend() === 'webgl') {
|
||||
if (this.config.deallocate) {
|
||||
log('changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:', this.config.deallocate);
|
||||
tf.ENV.set('WEBGL_DELETE_TEXTURE_THRESHOLD', this.config.deallocate ? 0 : -1);
|
||||
this.tf.ENV.set('WEBGL_DELETE_TEXTURE_THRESHOLD', this.config.deallocate ? 0 : -1);
|
||||
}
|
||||
tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true);
|
||||
tf.ENV.set('WEBGL_PACK_DEPTHWISECONV', true);
|
||||
const gl = await tf.backend().getGPGPUContext().gl;
|
||||
this.tf.ENV.set('WEBGL_FORCE_F16_TEXTURES', true);
|
||||
this.tf.ENV.set('WEBGL_PACK_DEPTHWISECONV', true);
|
||||
const gl = await this.tf.backend().getGPGPUContext().gl;
|
||||
log(`gl version:${gl.getParameter(gl.VERSION)} renderer:${gl.getParameter(gl.RENDERER)}`);
|
||||
}
|
||||
await tf.ready();
|
||||
await this.tf.ready();
|
||||
this.perf.backend = Math.trunc(now() - timeStamp);
|
||||
}
|
||||
}
|
||||
|
@ -384,7 +384,7 @@ class Human {
|
|||
// load models if enabled
|
||||
await this.load();
|
||||
|
||||
if (this.config.scoped) tf.engine().startScope();
|
||||
if (this.config.scoped) this.tf.engine().startScope();
|
||||
this.analyze('Start Scope:');
|
||||
|
||||
timeStamp = now();
|
||||
|
@ -440,7 +440,7 @@ class Human {
|
|||
}
|
||||
process.tensor.dispose();
|
||||
|
||||
if (this.config.scoped) tf.engine().endScope();
|
||||
if (this.config.scoped) this.tf.engine().endScope();
|
||||
this.analyze('End Scope:');
|
||||
|
||||
let gestureRes = [];
|
||||
|
@ -512,10 +512,10 @@ class Human {
|
|||
// @ts-ignore
|
||||
const data = tf.node.decodeJpeg(img); // tf.node is only defined when compiling for nodejs
|
||||
const expanded = data.expandDims(0);
|
||||
tf.dispose(data);
|
||||
this.tf.dispose(data);
|
||||
// log('Input:', expanded);
|
||||
const res = await this.detect(expanded, this.config);
|
||||
tf.dispose(expanded);
|
||||
this.tf.dispose(expanded);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,6 +83,7 @@ export function process(input, config) {
|
|||
*/
|
||||
} else {
|
||||
outCanvas = inCanvas;
|
||||
if (this.fx) this.fx = null;
|
||||
}
|
||||
let pixels;
|
||||
if (outCanvas.data) {
|
||||
|
|
190
src/imagefx.js
190
src/imagefx.js
|
@ -1,11 +1,10 @@
|
|||
/* eslint-disable no-use-before-define */
|
||||
/*
|
||||
WebGLImageFilter - MIT Licensed
|
||||
2013, Dominic Szablewski - phoboslab.org
|
||||
<https://github.com/phoboslab/WebGLImageFilter>
|
||||
*/
|
||||
|
||||
const GLProgram = function (gl, vertexSource, fragmentSource) {
|
||||
function GLProgram(gl, vertexSource, fragmentSource) {
|
||||
const _collect = function (source, prefix, collection) {
|
||||
const r = new RegExp('\\b' + prefix + ' \\w+ (\\w+)', 'ig');
|
||||
source.replace(r, (match, name) => {
|
||||
|
@ -18,7 +17,6 @@ const GLProgram = function (gl, vertexSource, fragmentSource) {
|
|||
const shader = gl.createShader(type);
|
||||
gl.shaderSource(shader, source);
|
||||
gl.compileShader(shader);
|
||||
|
||||
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
||||
// @ts-ignore
|
||||
throw new Error('Filter: GL compile failed', gl.getShaderInfoLog(shader));
|
||||
|
@ -28,10 +26,8 @@ const GLProgram = function (gl, vertexSource, fragmentSource) {
|
|||
|
||||
this.uniform = {};
|
||||
this.attribute = {};
|
||||
|
||||
const _vsh = _compile(vertexSource, gl.VERTEX_SHADER);
|
||||
const _fsh = _compile(fragmentSource, gl.FRAGMENT_SHADER);
|
||||
|
||||
this.id = gl.createProgram();
|
||||
gl.attachShader(this.id, _vsh);
|
||||
gl.attachShader(this.id, _fsh);
|
||||
|
@ -43,22 +39,17 @@ const GLProgram = function (gl, vertexSource, fragmentSource) {
|
|||
}
|
||||
|
||||
gl.useProgram(this.id);
|
||||
|
||||
// Collect attributes
|
||||
_collect(vertexSource, 'attribute', this.attribute);
|
||||
for (const a in this.attribute) {
|
||||
this.attribute[a] = gl.getAttribLocation(this.id, a);
|
||||
}
|
||||
|
||||
for (const a in this.attribute) this.attribute[a] = gl.getAttribLocation(this.id, a);
|
||||
// Collect uniforms
|
||||
_collect(vertexSource, 'uniform', this.uniform);
|
||||
_collect(fragmentSource, 'uniform', this.uniform);
|
||||
for (const u in this.uniform) {
|
||||
this.uniform[u] = gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
};
|
||||
for (const u in this.uniform) this.uniform[u] = gl.getUniformLocation(this.id, u);
|
||||
}
|
||||
|
||||
const GLImageFilter = function (params) {
|
||||
// export const GLImageFilter = function (params) {
|
||||
export function GLImageFilter(params) {
|
||||
if (!params) params = { };
|
||||
let _drawCount = 0;
|
||||
let _sourceTexture = null;
|
||||
|
@ -70,11 +61,11 @@ const GLImageFilter = function (params) {
|
|||
let _height = -1;
|
||||
let _vertexBuffer = null;
|
||||
let _currentProgram = null;
|
||||
const _filter = {};
|
||||
const _canvas = params.canvas || document.createElement('canvas');
|
||||
|
||||
// key is the shader program source, value is the compiled program
|
||||
const _shaderProgramCache = { };
|
||||
|
||||
const DRAW = { INTERMEDIATE: 1 };
|
||||
const gl = _canvas.getContext('webgl');
|
||||
if (!gl) throw new Error('Filter: getContext() failed');
|
||||
|
||||
|
@ -82,7 +73,6 @@ const GLImageFilter = function (params) {
|
|||
// eslint-disable-next-line prefer-rest-params
|
||||
const args = Array.prototype.slice.call(arguments, 1);
|
||||
const filter = _filter[name];
|
||||
|
||||
_filterChain.push({ func: filter, args });
|
||||
};
|
||||
|
||||
|
@ -90,44 +80,13 @@ const GLImageFilter = function (params) {
|
|||
_filterChain = [];
|
||||
};
|
||||
|
||||
this.apply = function (image) {
|
||||
_resize(image.width, image.height);
|
||||
_drawCount = 0;
|
||||
|
||||
// Create the texture for the input image if we haven't yet
|
||||
if (!_sourceTexture) _sourceTexture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, _sourceTexture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
|
||||
// No filters? Just draw
|
||||
if (_filterChain.length === 0) {
|
||||
// const program = _compileShader(SHADER.FRAGMENT_IDENTITY);
|
||||
_draw();
|
||||
return _canvas;
|
||||
}
|
||||
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = (i === _filterChain.length - 1);
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
|
||||
return _canvas;
|
||||
};
|
||||
|
||||
const _resize = function (width, height) {
|
||||
// Same width/height? Nothing to do here
|
||||
if (width === _width && height === _height) { return; }
|
||||
|
||||
_canvas.width = width;
|
||||
_width = width;
|
||||
_canvas.height = height;
|
||||
_height = height;
|
||||
|
||||
// Create the context if we don't have it yet
|
||||
if (!_vertexBuffer) {
|
||||
// Create the vertex buffer for the two triangles [x, y, u, v] * 6
|
||||
|
@ -138,53 +97,43 @@ const GLImageFilter = function (params) {
|
|||
// eslint-disable-next-line no-unused-expressions
|
||||
(_vertexBuffer = gl.createBuffer(), gl.bindBuffer(gl.ARRAY_BUFFER, _vertexBuffer));
|
||||
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
||||
|
||||
// Note sure if this is a good idea; at least it makes texture loading
|
||||
// in Ejecta instant.
|
||||
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
||||
}
|
||||
|
||||
gl.viewport(0, 0, _width, _height);
|
||||
|
||||
// Delete old temp framebuffers
|
||||
_tempFramebuffers = [null, null];
|
||||
};
|
||||
|
||||
const _createFramebufferTexture = function (width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
|
||||
const texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
return { fbo, texture };
|
||||
};
|
||||
|
||||
const _getTempFramebuffer = function (index) {
|
||||
// @ts-ignore
|
||||
_tempFramebuffers[index] = _tempFramebuffers[index] || _createFramebufferTexture(_width, _height);
|
||||
return _tempFramebuffers[index];
|
||||
};
|
||||
|
||||
const _createFramebufferTexture = function (width, height) {
|
||||
const fbo = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
|
||||
|
||||
const renderbuffer = gl.createRenderbuffer();
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, renderbuffer);
|
||||
|
||||
const texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
||||
|
||||
gl.bindTexture(gl.TEXTURE_2D, null);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||
|
||||
return { fbo, texture };
|
||||
};
|
||||
|
||||
const _draw = function (flags = null) {
|
||||
let source = null;
|
||||
let target = null;
|
||||
let flipY = false;
|
||||
|
||||
// Set up the source
|
||||
if (_drawCount === 0) {
|
||||
// First draw call - use the source texture
|
||||
|
@ -195,7 +144,6 @@ const GLImageFilter = function (params) {
|
|||
source = _getTempFramebuffer(_currentFramebufferIndex)?.texture;
|
||||
}
|
||||
_drawCount++;
|
||||
|
||||
// Set up the target
|
||||
if (_lastInChain && !(flags & DRAW.INTERMEDIATE)) {
|
||||
// Last filter in our chain - draw directly to the WebGL Canvas. We may
|
||||
|
@ -208,67 +156,78 @@ const GLImageFilter = function (params) {
|
|||
// @ts-ignore
|
||||
target = _getTempFramebuffer(_currentFramebufferIndex)?.fbo;
|
||||
}
|
||||
|
||||
// Bind the source and target and draw the two triangles
|
||||
gl.bindTexture(gl.TEXTURE_2D, source);
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, target);
|
||||
|
||||
gl.uniform1f(_currentProgram.uniform.flipY, (flipY ? -1 : 1));
|
||||
gl.drawArrays(gl.TRIANGLES, 0, 6);
|
||||
};
|
||||
|
||||
this.apply = function (image) {
|
||||
_resize(image.width, image.height);
|
||||
_drawCount = 0;
|
||||
// Create the texture for the input image if we haven't yet
|
||||
if (!_sourceTexture) _sourceTexture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, _sourceTexture);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
|
||||
// No filters? Just draw
|
||||
if (_filterChain.length === 0) {
|
||||
// const program = _compileShader(SHADER.FRAGMENT_IDENTITY);
|
||||
_draw();
|
||||
return _canvas;
|
||||
}
|
||||
for (let i = 0; i < _filterChain.length; i++) {
|
||||
_lastInChain = (i === _filterChain.length - 1);
|
||||
const f = _filterChain[i];
|
||||
f.func.apply(this, f.args || []);
|
||||
}
|
||||
return _canvas;
|
||||
};
|
||||
|
||||
const _compileShader = function (fragmentSource) {
|
||||
if (_shaderProgramCache[fragmentSource]) {
|
||||
_currentProgram = _shaderProgramCache[fragmentSource];
|
||||
gl.useProgram(_currentProgram.id);
|
||||
return _currentProgram;
|
||||
}
|
||||
|
||||
// Compile shaders
|
||||
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
|
||||
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.pos);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
|
||||
let DRAW = { INTERMEDIATE: 1 };
|
||||
|
||||
let SHADER = {};
|
||||
const SHADER = {};
|
||||
SHADER.VERTEX_IDENTITY = [
|
||||
'precision highp float;',
|
||||
'attribute vec2 pos;',
|
||||
'attribute vec2 uv;',
|
||||
'varying vec2 vUv;',
|
||||
'uniform float flipY;',
|
||||
|
||||
'void main(void) {',
|
||||
'vUv = uv;',
|
||||
'gl_Position = vec4(pos.x, pos.y*flipY, 0.0, 1.);',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
SHADER.FRAGMENT_IDENTITY = [
|
||||
'precision highp float;',
|
||||
'varying vec2 vUv;',
|
||||
'uniform sampler2D texture;',
|
||||
|
||||
'void main(void) {',
|
||||
'gl_FragColor = texture2D(texture, vUv);',
|
||||
'}',
|
||||
].join('\n');
|
||||
|
||||
let _filter = {};
|
||||
_currentProgram = new GLProgram(gl, SHADER.VERTEX_IDENTITY, fragmentSource);
|
||||
const floatSize = Float32Array.BYTES_PER_ELEMENT;
|
||||
const vertSize = 4 * floatSize;
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.pos);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute.pos, 2, gl.FLOAT, false, vertSize, 0 * floatSize);
|
||||
gl.enableVertexAttribArray(_currentProgram.attribute.uv);
|
||||
gl.vertexAttribPointer(_currentProgram.attribute.uv, 2, gl.FLOAT, false, vertSize, 2 * floatSize);
|
||||
_shaderProgramCache[fragmentSource] = _currentProgram;
|
||||
return _currentProgram;
|
||||
};
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Color Matrix Filter
|
||||
|
||||
_filter.colorMatrix = function (matrix) {
|
||||
// Create a Float32 Array and normalize the offset component to 0-1
|
||||
const m = new Float32Array(matrix);
|
||||
|
@ -276,24 +235,20 @@ const GLImageFilter = function (params) {
|
|||
m[9] /= 255;
|
||||
m[14] /= 255;
|
||||
m[19] /= 255;
|
||||
|
||||
// Can we ignore the alpha value? Makes things a bit faster.
|
||||
const shader = (m[18] === 1 && m[3] === 0 && m[8] === 0 && m[13] === 0 && m[15] === 0 && m[16] === 0 && m[17] === 0 && m[19] === 0)
|
||||
? _filter.colorMatrix.SHADER.WITHOUT_ALPHA
|
||||
: _filter.colorMatrix.SHADER.WITH_ALPHA;
|
||||
|
||||
const program = _compileShader(shader);
|
||||
gl.uniform1fv(program.uniform.m, m);
|
||||
_draw();
|
||||
};
|
||||
|
||||
_filter.colorMatrix.SHADER = {};
|
||||
_filter.colorMatrix.SHADER.WITH_ALPHA = [
|
||||
'precision highp float;',
|
||||
'varying vec2 vUv;',
|
||||
'uniform sampler2D texture;',
|
||||
'uniform float m[20];',
|
||||
|
||||
'void main(void) {',
|
||||
'vec4 c = texture2D(texture, vUv);',
|
||||
'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[3] * c.a + m[4];',
|
||||
|
@ -307,7 +262,6 @@ const GLImageFilter = function (params) {
|
|||
'varying vec2 vUv;',
|
||||
'uniform sampler2D texture;',
|
||||
'uniform float m[20];',
|
||||
|
||||
'void main(void) {',
|
||||
'vec4 c = texture2D(texture, vUv);',
|
||||
'gl_FragColor.r = m[0] * c.r + m[1] * c.g + m[2] * c.b + m[4];',
|
||||
|
@ -448,12 +402,10 @@ const GLImageFilter = function (params) {
|
|||
|
||||
// -------------------------------------------------------------------------
|
||||
// Convolution Filter
|
||||
|
||||
_filter.convolution = function (matrix) {
|
||||
const m = new Float32Array(matrix);
|
||||
const pixelSizeX = 1 / _width;
|
||||
const pixelSizeY = 1 / _height;
|
||||
|
||||
const program = _compileShader(_filter.convolution.SHADER);
|
||||
gl.uniform1fv(program.uniform.m, m);
|
||||
gl.uniform2f(program.uniform.px, pixelSizeX, pixelSizeY);
|
||||
|
@ -466,20 +418,16 @@ const GLImageFilter = function (params) {
|
|||
'uniform sampler2D texture;',
|
||||
'uniform vec2 px;',
|
||||
'uniform float m[9];',
|
||||
|
||||
'void main(void) {',
|
||||
'vec4 c11 = texture2D(texture, vUv - px);', // top left
|
||||
'vec4 c12 = texture2D(texture, vec2(vUv.x, vUv.y - px.y));', // top center
|
||||
'vec4 c13 = texture2D(texture, vec2(vUv.x + px.x, vUv.y - px.y));', // top right
|
||||
|
||||
'vec4 c21 = texture2D(texture, vec2(vUv.x - px.x, vUv.y) );', // mid left
|
||||
'vec4 c22 = texture2D(texture, vUv);', // mid center
|
||||
'vec4 c23 = texture2D(texture, vec2(vUv.x + px.x, vUv.y) );', // mid right
|
||||
|
||||
'vec4 c31 = texture2D(texture, vec2(vUv.x - px.x, vUv.y + px.y) );', // bottom left
|
||||
'vec4 c32 = texture2D(texture, vec2(vUv.x, vUv.y + px.y) );', // bottom center
|
||||
'vec4 c33 = texture2D(texture, vUv + px );', // bottom right
|
||||
|
||||
'gl_FragColor = ',
|
||||
'c11 * m[0] + c12 * m[1] + c22 * m[2] +',
|
||||
'c21 * m[3] + c22 * m[4] + c23 * m[5] +',
|
||||
|
@ -532,17 +480,13 @@ const GLImageFilter = function (params) {
|
|||
|
||||
// -------------------------------------------------------------------------
|
||||
// Blur Filter
|
||||
|
||||
_filter.blur = function (size) {
|
||||
const blurSizeX = (size / 7) / _width;
|
||||
const blurSizeY = (size / 7) / _height;
|
||||
|
||||
const program = _compileShader(_filter.blur.SHADER);
|
||||
|
||||
// Vertical
|
||||
gl.uniform2f(program.uniform.px, 0, blurSizeY);
|
||||
_draw(DRAW.INTERMEDIATE);
|
||||
|
||||
// Horizontal
|
||||
gl.uniform2f(program.uniform.px, blurSizeX, 0);
|
||||
_draw();
|
||||
|
@ -553,7 +497,6 @@ const GLImageFilter = function (params) {
|
|||
'varying vec2 vUv;',
|
||||
'uniform sampler2D texture;',
|
||||
'uniform vec2 px;',
|
||||
|
||||
'void main(void) {',
|
||||
'gl_FragColor = vec4(0.0);',
|
||||
'gl_FragColor += texture2D(texture, vUv + vec2(-7.0*px.x, -7.0*px.y))*0.0044299121055113265;',
|
||||
|
@ -576,13 +519,10 @@ const GLImageFilter = function (params) {
|
|||
|
||||
// -------------------------------------------------------------------------
|
||||
// Pixelate Filter
|
||||
|
||||
_filter.pixelate = function (size) {
|
||||
const blurSizeX = (size) / _width;
|
||||
const blurSizeY = (size) / _height;
|
||||
|
||||
const program = _compileShader(_filter.pixelate.SHADER);
|
||||
|
||||
// Horizontal
|
||||
gl.uniform2f(program.uniform.size, blurSizeX, blurSizeY);
|
||||
_draw();
|
||||
|
@ -593,17 +533,13 @@ const GLImageFilter = function (params) {
|
|||
'varying vec2 vUv;',
|
||||
'uniform vec2 size;',
|
||||
'uniform sampler2D texture;',
|
||||
|
||||
'vec2 pixelate(vec2 coord, vec2 size) {',
|
||||
'return floor( coord / size ) * size;',
|
||||
'}',
|
||||
|
||||
'void main(void) {',
|
||||
'gl_FragColor = vec4(0.0);',
|
||||
'vec2 coord = pixelate(vUv, size);',
|
||||
'gl_FragColor += texture2D(texture, coord);',
|
||||
'}',
|
||||
].join('\n');
|
||||
};
|
||||
|
||||
exports.GLImageFilter = GLImageFilter;
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export declare function GLImageFilter(params: any): void;
|
Loading…
Reference in New Issue