@vladmandic/human
Version:
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
1,513 lines (1,493 loc) • 462 kB
JavaScript
/*
Human
homepage: <https://github.com/vladmandic/human>
author: <https://github.com/vladmandic>'
*/
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
var __commonJS = (cb, mod3) => function __require() {
return mod3 || (0, cb[__getOwnPropNames(cb)[0]])((mod3 = { exports: {} }).exports, mod3), mod3.exports;
};
var __export = (target, all2) => {
for (var name in all2)
__defProp(target, name, { get: all2[name], enumerable: true });
};
var __reExport = (target, module2, copyDefault, desc) => {
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
for (let key of __getOwnPropNames(module2))
if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
}
return target;
};
var __toESM = (module2, isNodeMode) => {
return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", !isNodeMode && module2 && module2.__esModule ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
};
var __toCommonJS = /* @__PURE__ */ ((cache7) => {
return (module2, temp) => {
return cache7 && cache7.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache7 && cache7.set(module2, temp), temp);
};
})(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
var __publicField = (obj, key, value) => {
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
return value;
};
var __accessCheck = (obj, member, msg) => {
if (!member.has(obj))
throw TypeError("Cannot " + msg);
};
var __privateGet = (obj, member, getter) => {
__accessCheck(obj, member, "read from private field");
return getter ? getter.call(obj) : member.get(obj);
};
var __privateAdd = (obj, member, value) => {
if (member.has(obj))
throw TypeError("Cannot add the same private member more than once");
member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
};
var __privateSet = (obj, member, value, setter) => {
__accessCheck(obj, member, "write to private field");
setter ? setter.call(obj, value) : member.set(obj, value);
return value;
};
// dist/tfjs.esm.js
var require_tfjs_esm = __commonJS({
"dist/tfjs.esm.js"(exports, module2) {
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc2 = Object.getOwnPropertyDescriptor;
var __getOwnPropNames2 = Object.getOwnPropertyNames;
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
var __markAsModule2 = (target) => __defProp2(target, "__esModule", { value: true });
var __reExport2 = (target, module22, copyDefault, desc) => {
if (module22 && typeof module22 === "object" || typeof module22 === "function") {
for (let key of __getOwnPropNames2(module22))
if (!__hasOwnProp2.call(target, key) && (copyDefault || key !== "default"))
__defProp2(target, key, { get: () => module22[key], enumerable: !(desc = __getOwnPropDesc2(module22, key)) || desc.enumerable });
}
return target;
};
var __toCommonJS2 = ((cache7) => {
return (module22, temp) => {
return cache7 && cache7.get(module22) || (temp = __reExport2(__markAsModule2({}), module22, 1), cache7 && cache7.set(module22, temp), temp);
};
})(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
var tf_node_gpu_exports = {};
__reExport2(tf_node_gpu_exports, require("@tensorflow/tfjs-node-gpu"));
module2.exports = __toCommonJS2(tf_node_gpu_exports);
}
});
// src/human.ts
var human_exports = {};
__export(human_exports, {
Human: () => Human,
default: () => Human,
defaults: () => config,
env: () => env
});
// src/util/util.ts
function log(...msg) {
const dt = new Date();
const ts = `${dt.getHours().toString().padStart(2, "0")}:${dt.getMinutes().toString().padStart(2, "0")}:${dt.getSeconds().toString().padStart(2, "0")}.${dt.getMilliseconds().toString().padStart(3, "0")}`;
if (msg)
console.log(ts, "Human:", ...msg);
}
function join(folder, file) {
const separator = folder.endsWith("/") ? "" : "/";
const skipJoin = file.startsWith(".") || file.startsWith("/") || file.startsWith("http:") || file.startsWith("https:") || file.startsWith("file:");
const path = skipJoin ? `${file}` : `${folder}${separator}${file}`;
if (!path.toLocaleLowerCase().includes(".json"))
throw new Error(`modelpath error: expecting json file: ${path}`);
return path;
}
var now = () => {
if (typeof performance !== "undefined")
return performance.now();
return parseInt((Number(process.hrtime.bigint()) / 1e3 / 1e3).toString());
};
function validate(defaults, config3, parent = "config", msgs = []) {
for (const key of Object.keys(config3)) {
if (typeof config3[key] === "object") {
validate(defaults[key], config3[key], key, msgs);
} else {
const defined = defaults && typeof defaults[key] !== "undefined";
if (!defined)
msgs.push({ reason: "unknown property", where: `${parent}.${key} = ${config3[key]}` });
const same = defaults && typeof defaults[key] === typeof config3[key];
if (defined && !same)
msgs.push({ reason: "property type mismatch", where: `${parent}.${key} = ${config3[key]}`, expected: typeof defaults[key] });
}
}
if (config3.debug && parent === "config" && msgs.length > 0)
log("invalid configuration", msgs);
return msgs;
}
function mergeDeep(...objects) {
const isObject = (obj) => obj && typeof obj === "object";
return objects.reduce((prev, obj) => {
Object.keys(obj || {}).forEach((key) => {
const pVal = prev[key];
const oVal = obj[key];
if (Array.isArray(pVal) && Array.isArray(oVal))
prev[key] = pVal.concat(...oVal);
else if (isObject(pVal) && isObject(oVal))
prev[key] = mergeDeep(pVal, oVal);
else
prev[key] = oVal;
});
return prev;
}, {});
}
// src/config.ts
var config = {
backend: "",
modelBasePath: "",
cacheModels: true,
wasmPath: "",
debug: true,
async: true,
warmup: "full",
cacheSensitivity: 0.7,
skipAllowed: false,
deallocate: false,
filter: {
enabled: true,
equalization: false,
width: 0,
height: 0,
flip: false,
return: true,
brightness: 0,
contrast: 0,
sharpness: 0,
blur: 0,
saturation: 0,
hue: 0,
negative: false,
sepia: false,
vintage: false,
kodachrome: false,
technicolor: false,
polaroid: false,
pixelate: 0
},
gesture: {
enabled: true
},
face: {
enabled: true,
detector: {
modelPath: "blazeface.json",
rotation: true,
maxDetected: 1,
skipFrames: 99,
skipTime: 2500,
minConfidence: 0.2,
iouThreshold: 0.1,
mask: false,
return: false
},
mesh: {
enabled: true,
modelPath: "facemesh.json"
},
iris: {
enabled: true,
modelPath: "iris.json"
},
emotion: {
enabled: true,
minConfidence: 0.1,
skipFrames: 99,
skipTime: 1500,
modelPath: "emotion.json"
},
description: {
enabled: true,
modelPath: "faceres.json",
skipFrames: 99,
skipTime: 3e3,
minConfidence: 0.1
},
antispoof: {
enabled: false,
skipFrames: 99,
skipTime: 4e3,
modelPath: "antispoof.json"
},
liveness: {
enabled: false,
skipFrames: 99,
skipTime: 4e3,
modelPath: "liveness.json"
}
},
body: {
enabled: true,
modelPath: "movenet-lightning.json",
maxDetected: -1,
minConfidence: 0.3,
skipFrames: 1,
skipTime: 200
},
hand: {
enabled: true,
rotation: true,
skipFrames: 99,
skipTime: 1e3,
minConfidence: 0.5,
iouThreshold: 0.2,
maxDetected: -1,
landmarks: true,
detector: {
modelPath: "handtrack.json"
},
skeleton: {
modelPath: "handlandmark-full.json"
}
},
object: {
enabled: false,
modelPath: "mb3-centernet.json",
minConfidence: 0.2,
iouThreshold: 0.4,
maxDetected: 10,
skipFrames: 99,
skipTime: 2e3
},
segmentation: {
enabled: false,
modelPath: "selfie.json",
blur: 8
}
};
// src/util/env.ts
var tf3 = __toESM(require_tfjs_esm());
// src/image/image.ts
var tf2 = __toESM(require_tfjs_esm());
// src/image/imagefxshaders.ts
var vertexIdentity = `
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.);
}
`;
var colorMatrixWithAlpha = `
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];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[8] * c.a + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[13] * c.a + m[14];
gl_FragColor.a = m[15] * c.r + m[16] * c.g + m[17] * c.b + m[18] * c.a + m[19];
}
`;
var colorMatrixWithoutAlpha = `
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[4];
gl_FragColor.g = m[5] * c.r + m[6] * c.g + m[7] * c.b + m[9];
gl_FragColor.b = m[10] * c.r + m[11] * c.g + m[12] * c.b + m[14];
gl_FragColor.a = c.a;
}
`;
var pixelate = `
precision highp float;
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);
}
`;
var blur = `
precision highp float;
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;
gl_FragColor += texture2D(texture, vUv + vec2(-6.0*px.x, -6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2(-5.0*px.x, -5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2(-4.0*px.x, -4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2(-3.0*px.x, -3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2(-2.0*px.x, -2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2(-1.0*px.x, -1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv )*0.159576912161;
gl_FragColor += texture2D(texture, vUv + vec2( 1.0*px.x, 1.0*px.y))*0.147308056121;
gl_FragColor += texture2D(texture, vUv + vec2( 2.0*px.x, 2.0*px.y))*0.115876621105;
gl_FragColor += texture2D(texture, vUv + vec2( 3.0*px.x, 3.0*px.y))*0.0776744219933;
gl_FragColor += texture2D(texture, vUv + vec2( 4.0*px.x, 4.0*px.y))*0.0443683338718;
gl_FragColor += texture2D(texture, vUv + vec2( 5.0*px.x, 5.0*px.y))*0.0215963866053;
gl_FragColor += texture2D(texture, vUv + vec2( 6.0*px.x, 6.0*px.y))*0.00895781211794;
gl_FragColor += texture2D(texture, vUv + vec2( 7.0*px.x, 7.0*px.y))*0.0044299121055113265;
}
`;
var convolution = `
precision highp float;
varying vec2 vUv;
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] +
c31 * m[6] + c32 * m[7] + c33 * m[8];
gl_FragColor.a = c22.a;
}
`;
// src/image/imagefx.ts
var collect = (source, prefix, collection) => {
const r = new RegExp("\\b" + prefix + " \\w+ (\\w+)", "ig");
source.replace(r, (match3, name) => {
collection[name] = 0;
return match3;
});
};
var GLProgram = class {
constructor(gl, vertexSource, fragmentSource) {
__publicField(this, "uniform", {});
__publicField(this, "attribute", {});
__publicField(this, "gl");
__publicField(this, "id");
__publicField(this, "compile", (source, type) => {
const shader = this.gl.createShader(type);
if (!shader) {
log("filter: could not create shader");
return null;
}
this.gl.shaderSource(shader, source);
this.gl.compileShader(shader);
if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) {
log(`filter: gl compile failed: ${this.gl.getShaderInfoLog(shader)}`);
return null;
}
return shader;
});
this.gl = gl;
const vertexShader = this.compile(vertexSource, this.gl.VERTEX_SHADER);
const fragmentShader = this.compile(fragmentSource, this.gl.FRAGMENT_SHADER);
this.id = this.gl.createProgram();
if (!vertexShader || !fragmentShader)
return;
if (!this.id) {
log("filter: could not create webgl program");
return;
}
this.gl.attachShader(this.id, vertexShader);
this.gl.attachShader(this.id, fragmentShader);
this.gl.linkProgram(this.id);
if (!this.gl.getProgramParameter(this.id, this.gl.LINK_STATUS)) {
log(`filter: gl link failed: ${this.gl.getProgramInfoLog(this.id)}`);
return;
}
this.gl.useProgram(this.id);
collect(vertexSource, "attribute", this.attribute);
for (const a in this.attribute)
this.attribute[a] = this.gl.getAttribLocation(this.id, a);
collect(vertexSource, "uniform", this.uniform);
collect(fragmentSource, "uniform", this.uniform);
for (const u in this.uniform)
this.uniform[u] = this.gl.getUniformLocation(this.id, u);
}
};
function GLImageFilter() {
let drawCount = 0;
let sourceTexture = null;
let lastInChain = false;
let currentFramebufferIndex = -1;
let tempFramebuffers = [null, null];
let filterChain = [];
let vertexBuffer = null;
let currentProgram = null;
const fxcanvas = canvas(100, 100);
const shaderProgramCache = {};
const DRAW = { INTERMEDIATE: 1 };
const gl = fxcanvas.getContext("webgl");
this.gl = gl;
if (!gl) {
log("filter: cannot get webgl context");
return;
}
function resize(width, height) {
if (width === fxcanvas.width && height === fxcanvas.height)
return;
fxcanvas.width = width;
fxcanvas.height = height;
if (!vertexBuffer) {
const vertices = new Float32Array([-1, -1, 0, 1, 1, -1, 1, 1, -1, 1, 0, 0, -1, 1, 0, 0, 1, -1, 1, 1, 1, 1, 1, 0]);
vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
}
gl.viewport(0, 0, fxcanvas.width, fxcanvas.height);
tempFramebuffers = [null, null];
}
function createFramebufferTexture(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 };
}
function getTempFramebuffer(index2) {
tempFramebuffers[index2] = tempFramebuffers[index2] || createFramebufferTexture(fxcanvas.width, fxcanvas.height);
return tempFramebuffers[index2];
}
function draw(flags = 0) {
if (!currentProgram)
return;
let source = null;
let target = null;
let flipY = false;
if (drawCount === 0)
source = sourceTexture;
else
source = getTempFramebuffer(currentFramebufferIndex).texture || null;
drawCount++;
if (lastInChain && !(flags & DRAW.INTERMEDIATE)) {
target = null;
flipY = drawCount % 2 === 0;
} else {
currentFramebufferIndex = (currentFramebufferIndex + 1) % 2;
target = getTempFramebuffer(currentFramebufferIndex).fbo || null;
}
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);
}
function compileShader(fragmentSource) {
if (shaderProgramCache[fragmentSource]) {
currentProgram = shaderProgramCache[fragmentSource];
gl.useProgram((currentProgram ? currentProgram.id : null) || null);
return currentProgram;
}
currentProgram = new GLProgram(gl, vertexIdentity, fragmentSource);
if (!currentProgram) {
log("filter: could not get webgl program");
return null;
}
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;
}
const filter = {
colorMatrix: (matrix) => {
const m = new Float32Array(matrix);
m[4] /= 255;
m[9] /= 255;
m[14] /= 255;
m[19] /= 255;
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 ? colorMatrixWithoutAlpha : colorMatrixWithAlpha;
const program = compileShader(shader);
if (!program)
return;
gl.uniform1fv(program.uniform["m"], m);
draw();
},
brightness: (brightness) => {
const b = (brightness || 0) + 1;
filter.colorMatrix([
b,
0,
0,
0,
0,
0,
b,
0,
0,
0,
0,
0,
b,
0,
0,
0,
0,
0,
1,
0
]);
},
saturation: (amount) => {
const x = (amount || 0) * 2 / 3 + 1;
const y = (x - 1) * -0.5;
filter.colorMatrix([
x,
y,
y,
0,
0,
y,
x,
y,
0,
0,
y,
y,
x,
0,
0,
0,
0,
0,
1,
0
]);
},
desaturate: () => {
filter.saturation(-1);
},
contrast: (amount) => {
const v = (amount || 0) + 1;
const o = -128 * (v - 1);
filter.colorMatrix([
v,
0,
0,
0,
o,
0,
v,
0,
0,
o,
0,
0,
v,
0,
o,
0,
0,
0,
1,
0
]);
},
negative: () => {
filter.contrast(-2);
},
hue: (rotation) => {
rotation = (rotation || 0) / 180 * Math.PI;
const cos = Math.cos(rotation);
const sin = Math.sin(rotation);
const lumR = 0.213;
const lumG = 0.715;
const lumB = 0.072;
filter.colorMatrix([
lumR + cos * (1 - lumR) + sin * -lumR,
lumG + cos * -lumG + sin * -lumG,
lumB + cos * -lumB + sin * (1 - lumB),
0,
0,
lumR + cos * -lumR + sin * 0.143,
lumG + cos * (1 - lumG) + sin * 0.14,
lumB + cos * -lumB + sin * -0.283,
0,
0,
lumR + cos * -lumR + sin * -(1 - lumR),
lumG + cos * -lumG + sin * lumG,
lumB + cos * (1 - lumB) + sin * lumB,
0,
0,
0,
0,
0,
1,
0
]);
},
desaturateLuminance: () => {
filter.colorMatrix([
0.2764723,
0.929708,
0.0938197,
0,
-37.1,
0.2764723,
0.929708,
0.0938197,
0,
-37.1,
0.2764723,
0.929708,
0.0938197,
0,
-37.1,
0,
0,
0,
1,
0
]);
},
sepia: () => {
filter.colorMatrix([
0.393,
0.7689999,
0.18899999,
0,
0,
0.349,
0.6859999,
0.16799999,
0,
0,
0.272,
0.5339999,
0.13099999,
0,
0,
0,
0,
0,
1,
0
]);
},
brownie: () => {
filter.colorMatrix([
0.5997023498159715,
0.34553243048391263,
-0.2708298674538042,
0,
47.43192855600873,
-0.037703249837783157,
0.8609577587992641,
0.15059552388459913,
0,
-36.96841498319127,
0.24113635128153335,
-0.07441037908422492,
0.44972182064877153,
0,
-7.562075277591283,
0,
0,
0,
1,
0
]);
},
vintagePinhole: () => {
filter.colorMatrix([
0.6279345635605994,
0.3202183420819367,
-0.03965408211312453,
0,
9.651285835294123,
0.02578397704808868,
0.6441188644374771,
0.03259127616149294,
0,
7.462829176470591,
0.0466055556782719,
-0.0851232987247891,
0.5241648018700465,
0,
5.159190588235296,
0,
0,
0,
1,
0
]);
},
kodachrome: () => {
filter.colorMatrix([
1.1285582396593525,
-0.3967382283601348,
-0.03992559172921793,
0,
63.72958762196502,
-0.16404339962244616,
1.0835251566291304,
-0.05498805115633132,
0,
24.732407896706203,
-0.16786010706155763,
-0.5603416277695248,
1.6014850761964943,
0,
35.62982807460946,
0,
0,
0,
1,
0
]);
},
technicolor: () => {
filter.colorMatrix([
1.9125277891456083,
-0.8545344976951645,
-0.09155508482755585,
0,
11.793603434377337,
-0.3087833385928097,
1.7658908555458428,
-0.10601743074722245,
0,
-70.35205161461398,
-0.231103377548616,
-0.7501899197440212,
1.847597816108189,
0,
30.950940869491138,
0,
0,
0,
1,
0
]);
},
polaroid: () => {
filter.colorMatrix([
1.438,
-0.062,
-0.062,
0,
0,
-0.122,
1.378,
-0.122,
0,
0,
-0.016,
-0.016,
1.483,
0,
0,
0,
0,
0,
1,
0
]);
},
shiftToBGR: () => {
filter.colorMatrix([
0,
0,
1,
0,
0,
0,
1,
0,
0,
0,
1,
0,
0,
0,
0,
0,
0,
0,
1,
0
]);
},
convolution: (matrix) => {
const m = new Float32Array(matrix);
const pixelSizeX = 1 / fxcanvas.width;
const pixelSizeY = 1 / fxcanvas.height;
const program = compileShader(convolution);
if (!program)
return;
gl.uniform1fv(program.uniform["m"], m);
gl.uniform2f(program.uniform["px"], pixelSizeX, pixelSizeY);
draw();
},
detectEdges: () => {
filter.convolution.call(this, [
0,
1,
0,
1,
-4,
1,
0,
1,
0
]);
},
sobelX: () => {
filter.convolution.call(this, [
-1,
0,
1,
-2,
0,
2,
-1,
0,
1
]);
},
sobelY: () => {
filter.convolution.call(this, [
-1,
-2,
-1,
0,
0,
0,
1,
2,
1
]);
},
sharpen: (amount) => {
const a = amount || 1;
filter.convolution.call(this, [
0,
-1 * a,
0,
-1 * a,
1 + 4 * a,
-1 * a,
0,
-1 * a,
0
]);
},
emboss: (size2) => {
const s = size2 || 1;
filter.convolution.call(this, [
-2 * s,
-1 * s,
0,
-1 * s,
1,
1 * s,
0,
1 * s,
2 * s
]);
},
blur: (size2) => {
const blurSizeX = size2 / 7 / fxcanvas.width;
const blurSizeY = size2 / 7 / fxcanvas.height;
const program = compileShader(blur);
if (!program)
return;
gl.uniform2f(program.uniform["px"], 0, blurSizeY);
draw(DRAW.INTERMEDIATE);
gl.uniform2f(program.uniform["px"], blurSizeX, 0);
draw();
},
pixelate: (size2) => {
const blurSizeX = size2 / fxcanvas.width;
const blurSizeY = size2 / fxcanvas.height;
const program = compileShader(pixelate);
if (!program)
return;
gl.uniform2f(program.uniform["size"], blurSizeX, blurSizeY);
draw();
}
};
this.add = function(name) {
const args = Array.prototype.slice.call(arguments, 1);
const func = filter[name];
filterChain.push({ func, args });
};
this.reset = function() {
filterChain = [];
};
this.get = function() {
return filterChain;
};
this.apply = function(image24) {
resize(image24.width, image24.height);
drawCount = 0;
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, image24);
for (let i = 0; i < filterChain.length; i++) {
lastInChain = i === filterChain.length - 1;
const f = filterChain[i];
f.func.apply(this, f.args || []);
}
return fxcanvas;
};
this.draw = function(image24) {
this.add("brightness", 0);
return this.apply(image24);
};
}
// src/image/enhance.ts
var tf = __toESM(require_tfjs_esm());
async function histogramEqualization(inputImage) {
const squeeze11 = inputImage.shape.length === 4 ? tf.squeeze(inputImage) : inputImage;
const channels = tf.split(squeeze11, 3, 2);
const min2 = [tf.min(channels[0]), tf.min(channels[1]), tf.min(channels[2])];
const max4 = [tf.max(channels[0]), tf.max(channels[1]), tf.max(channels[2])];
const absMax = await Promise.all(max4.map((channel) => channel.data()));
const maxValue = 0.99 * Math.max(absMax[0][0], absMax[1][0], absMax[2][0]);
const sub11 = [tf.sub(channels[0], min2[0]), tf.sub(channels[1], min2[1]), tf.sub(channels[2], min2[2])];
const range = [tf.sub(max4[0], min2[0]), tf.sub(max4[1], min2[1]), tf.sub(max4[2], min2[2])];
const fact = [tf.div(maxValue, range[0]), tf.div(maxValue, range[1]), tf.div(maxValue, range[2])];
const enh = [tf.mul(sub11[0], fact[0]), tf.mul(sub11[1], fact[1]), tf.mul(sub11[2], fact[2])];
const rgb2 = tf.stack([enh[0], enh[1], enh[2]], 2);
const reshape8 = tf.reshape(rgb2, [1, squeeze11.shape[0], squeeze11.shape[1], 3]);
tf.dispose([...channels, ...min2, ...max4, ...sub11, ...range, ...fact, ...enh, rgb2, squeeze11]);
return reshape8;
}
// src/image/image.ts
var maxSize = 2048;
var inCanvas = null;
var outCanvas = null;
var tmpCanvas = null;
var fx;
var last = {
inputSum: 0,
cacheDiff: 1,
sumMethod: 0,
inputTensor: void 0
};
function canvas(width, height) {
let c;
if (env.browser) {
if (env.worker) {
if (typeof OffscreenCanvas === "undefined")
throw new Error("canvas error: attempted to run in web worker but OffscreenCanvas is not supported");
c = new OffscreenCanvas(width, height);
} else {
if (typeof document === "undefined")
throw new Error("canvas error: attempted to run in browser but DOM is not defined");
c = document.createElement("canvas");
c.width = width;
c.height = height;
}
} else {
if (typeof env.Canvas !== "undefined")
c = new env.Canvas(width, height);
else if (typeof globalThis.Canvas !== "undefined")
c = new globalThis.Canvas(width, height);
}
return c;
}
function copy(input, output) {
const outputCanvas = output || canvas(input.width, input.height);
const ctx = outputCanvas.getContext("2d");
ctx.drawImage(input, 0, 0);
return outputCanvas;
}
async function process2(input, config3, getTensor = true) {
if (!input) {
if (config3.debug)
log("input error: input is missing");
return { tensor: null, canvas: null };
}
if (!(input instanceof tf2.Tensor) && !(typeof Image !== "undefined" && input instanceof Image) && !(typeof env.Canvas !== "undefined" && input instanceof env.Canvas) && !(typeof globalThis.Canvas !== "undefined" && input instanceof globalThis.Canvas) && !(typeof ImageData !== "undefined" && input instanceof ImageData) && !(typeof ImageBitmap !== "undefined" && input instanceof ImageBitmap) && !(typeof HTMLImageElement !== "undefined" && input instanceof HTMLImageElement) && !(typeof HTMLMediaElement !== "undefined" && input instanceof HTMLMediaElement) && !(typeof HTMLVideoElement !== "undefined" && input instanceof HTMLVideoElement) && !(typeof HTMLCanvasElement !== "undefined" && input instanceof HTMLCanvasElement) && !(typeof OffscreenCanvas !== "undefined" && input instanceof OffscreenCanvas)) {
throw new Error("input error: type is not recognized");
}
if (input instanceof tf2.Tensor) {
let tensor3 = null;
if (input["isDisposedInternal"])
throw new Error("input error: attempted to use tensor but it is disposed");
if (!input["shape"])
throw new Error("input error: attempted to use tensor without a shape");
if (input.shape.length === 3) {
if (input.shape[2] === 3) {
tensor3 = tf2.expandDims(input, 0);
} else if (input.shape[2] === 4) {
const rgb2 = tf2.slice3d(input, [0, 0, 0], [-1, -1, 3]);
tensor3 = tf2.expandDims(rgb2, 0);
tf2.dispose(rgb2);
}
} else if (input.shape.length === 4) {
if (input.shape[3] === 3) {
tensor3 = tf2.clone(input);
} else if (input.shape[3] === 4) {
tensor3 = tf2.slice4d(input, [0, 0, 0, 0], [-1, -1, -1, 3]);
}
}
if (tensor3 == null || tensor3.shape.length !== 4 || tensor3.shape[0] !== 1 || tensor3.shape[3] !== 3)
throw new Error(`input error: attempted to use tensor with unrecognized shape: ${input["shape"]}`);
if (tensor3.dtype === "int32") {
const cast5 = tf2.cast(tensor3, "float32");
tf2.dispose(tensor3);
tensor3 = cast5;
}
return { tensor: tensor3, canvas: config3.filter.return ? outCanvas : null };
} else {
if (typeof input["readyState"] !== "undefined" && input["readyState"] <= 2) {
if (config3.debug)
log("input stream is not ready");
return { tensor: null, canvas: inCanvas };
}
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;
if (!originalWidth || !originalHeight) {
if (config3.debug)
log("cannot determine input dimensions");
return { tensor: null, canvas: inCanvas };
}
let targetWidth = originalWidth;
let targetHeight = originalHeight;
if (targetWidth > maxSize) {
targetWidth = maxSize;
targetHeight = Math.trunc(targetWidth * originalHeight / originalWidth);
}
if (targetHeight > maxSize) {
targetHeight = maxSize;
targetWidth = Math.trunc(targetHeight * originalWidth / originalHeight);
}
if ((config3.filter.width || 0) > 0)
targetWidth = config3.filter.width;
else if ((config3.filter.height || 0) > 0)
targetWidth = originalWidth * ((config3.filter.height || 0) / originalHeight);
if ((config3.filter.height || 0) > 0)
targetHeight = config3.filter.height;
else if ((config3.filter.width || 0) > 0)
targetHeight = originalHeight * ((config3.filter.width || 0) / originalWidth);
if (!targetWidth || !targetHeight)
throw new Error("input error: cannot determine dimension");
if (!inCanvas || (inCanvas == null ? void 0 : inCanvas.width) !== targetWidth || (inCanvas == null ? void 0 : inCanvas.height) !== targetHeight)
inCanvas = canvas(targetWidth, targetHeight);
const inCtx = inCanvas.getContext("2d");
if (typeof ImageData !== "undefined" && input instanceof ImageData) {
inCtx.putImageData(input, 0, 0);
} else {
if (config3.filter.flip && typeof inCtx.translate !== "undefined") {
inCtx.translate(originalWidth, 0);
inCtx.scale(-1, 1);
inCtx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas == null ? void 0 : inCanvas.width, inCanvas == null ? void 0 : inCanvas.height);
inCtx.setTransform(1, 0, 0, 1, 0, 0);
} else {
inCtx.drawImage(input, 0, 0, originalWidth, originalHeight, 0, 0, inCanvas == null ? void 0 : inCanvas.width, inCanvas == null ? void 0 : inCanvas.height);
}
}
if (!outCanvas || inCanvas.width !== outCanvas.width || (inCanvas == null ? void 0 : inCanvas.height) !== (outCanvas == null ? void 0 : outCanvas.height))
outCanvas = canvas(inCanvas.width, inCanvas.height);
if (config3.filter.enabled && env.webgl.supported) {
if (!fx)
fx = env.browser ? new GLImageFilter() : null;
env.filter = !!fx;
if (!fx || !fx.add) {
if (config3.debug)
log("input process error: cannot initialize filters");
return { tensor: null, canvas: inCanvas };
}
fx.reset();
if (config3.filter.brightness !== 0)
fx.add("brightness", config3.filter.brightness);
if (config3.filter.contrast !== 0)
fx.add("contrast", config3.filter.contrast);
if (config3.filter.sharpness !== 0)
fx.add("sharpen", config3.filter.sharpness);
if (config3.filter.blur !== 0)
fx.add("blur", config3.filter.blur);
if (config3.filter.saturation !== 0)
fx.add("saturation", config3.filter.saturation);
if (config3.filter.hue !== 0)
fx.add("hue", config3.filter.hue);
if (config3.filter.negative)
fx.add("negative");
if (config3.filter.sepia)
fx.add("sepia");
if (config3.filter.vintage)
fx.add("brownie");
if (config3.filter.sepia)
fx.add("sepia");
if (config3.filter.kodachrome)
fx.add("kodachrome");
if (config3.filter.technicolor)
fx.add("technicolor");
if (config3.filter.polaroid)
fx.add("polaroid");
if (config3.filter.pixelate !== 0)
fx.add("pixelate", config3.filter.pixelate);
if (fx.get() > 0)
outCanvas = fx.apply(inCanvas);
else
outCanvas = fx.draw(inCanvas);
} else {
copy(inCanvas, outCanvas);
if (fx)
fx = null;
env.filter = !!fx;
}
if (!getTensor)
return { tensor: null, canvas: outCanvas };
if (!outCanvas)
throw new Error("canvas error: cannot create output");
let pixels;
let depth = 3;
if (typeof ImageData !== "undefined" && input instanceof ImageData || input["data"] && input["width"] && input["height"]) {
if (env.browser && tf2.browser) {
pixels = tf2.browser ? tf2.browser.fromPixels(input) : null;
} else {
depth = input["data"].length / input["height"] / input["width"];
const arr = new Uint8Array(input["data"]["buffer"]);
pixels = tf2.tensor(arr, [input["height"], input["width"], depth], "int32");
}
} else {
if (!tmpCanvas || outCanvas.width !== tmpCanvas.width || outCanvas.height !== tmpCanvas.height)
tmpCanvas = canvas(outCanvas.width, outCanvas.height);
if (tf2.browser && env.browser) {
if (config3.backend === "webgl" || config3.backend === "humangl" || config3.backend === "webgpu") {
pixels = tf2.browser.fromPixels(outCanvas);
} else {
tmpCanvas = copy(outCanvas);
pixels = tf2.browser.fromPixels(tmpCanvas);
}
} else {
const tempCanvas = copy(outCanvas);
const tempCtx = tempCanvas.getContext("2d");
const tempData = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
depth = tempData.data.length / targetWidth / targetHeight;
const arr = new Uint8Array(tempData.data.buffer);
pixels = tf2.tensor(arr, [targetWidth, targetHeight, depth]);
}
}
if (depth === 4) {
const rgb2 = tf2.slice3d(pixels, [0, 0, 0], [-1, -1, 3]);
tf2.dispose(pixels);
pixels = rgb2;
}
if (!pixels)
throw new Error("input error: cannot create tensor");
const casted = tf2.cast(pixels, "float32");
const tensor3 = config3.filter.equalization ? await histogramEqualization(casted) : tf2.expandDims(casted, 0);
tf2.dispose([pixels, casted]);
return { tensor: tensor3, canvas: config3.filter.return ? outCanvas : null };
}
}
async function skip(config3, input) {
let skipFrame = false;
if (config3.cacheSensitivity === 0 || !input.shape || input.shape.length !== 4 || input.shape[1] > 2048 || input.shape[2] > 2048)
return skipFrame;
if (!last.inputTensor) {
last.inputTensor = tf2.clone(input);
} else if (last.inputTensor.shape[1] !== input.shape[1] || last.inputTensor.shape[2] !== input.shape[2]) {
tf2.dispose(last.inputTensor);
last.inputTensor = tf2.clone(input);
} else {
const t = {};
t.diff = tf2.sub(input, last.inputTensor);
t.squared = tf2.mul(t.diff, t.diff);
t.sum = tf2.sum(t.squared);
const diffSum = await t.sum.data();
const diffRelative = diffSum[0] / (input.shape[1] || 1) / (input.shape[2] || 1) / 255 / 3;
tf2.dispose([last.inputTensor, t.diff, t.squared, t.sum]);
last.inputTensor = tf2.clone(input);
skipFrame = diffRelative <= (config3.cacheSensitivity || 0);
}
return skipFrame;
}
async function compare(config3, input1, input2) {
const t = {};
if (!input1 || !input2 || input1.shape.length !== 4 || input1.shape.length !== input2.shape.length) {
if (!config3.debug)
log("invalid input tensor or tensor shapes do not match:", input1.shape, input2.shape);
return 0;
}
if (input1.shape[0] !== 1 || input2.shape[0] !== 1 || input1.shape[3] !== 3 || input2.shape[3] !== 3) {
if (!config3.debug)
log("input tensors must be of shape [1, height, width, 3]:", input1.shape, input2.shape);
return 0;
}
t.input1 = tf2.clone(input1);
t.input2 = input1.shape[1] !== input2.shape[1] || input1.shape[2] !== input2.shape[2] ? tf2.image.resizeBilinear(input2, [input1.shape[1], input1.shape[2]]) : tf2.clone(input2);
t.diff = tf2.sub(t.input1, t.input2);
t.squared = tf2.mul(t.diff, t.diff);
t.sum = tf2.sum(t.squared);
const diffSum = await t.sum.data();
const diffRelative = diffSum[0] / (input1.shape[1] || 1) / (input1.shape[2] || 1) / 255 / 3;
tf2.dispose([t.input1, t.input2, t.diff, t.squared, t.sum]);
return diffRelative;
}
// src/util/env.ts
var Env = class {
constructor() {
__publicField(this, "browser");
__publicField(this, "node");
__publicField(this, "worker");
__publicField(this, "platform", "");
__publicField(this, "agent", "");
__publicField(this, "backends", []);
__publicField(this, "initial");
__publicField(this, "filter");
__publicField(this, "tfjs");
__publicField(this, "offscreen");
__publicField(this, "perfadd", false);
__publicField(this, "wasm", {
supported: void 0,
backend: void 0,
simd: void 0,
multithread: void 0
});
__publicField(this, "webgl", {
supported: void 0,
backend: void 0,
version: void 0,
renderer: void 0
});
__publicField(this, "webgpu", {
supported: void 0,
backend: void 0,
adapter: void 0
});
__publicField(this, "cpu", {
model: void 0,
flags: []
});
__publicField(this, "kernels", []);
__publicField(this, "Canvas");
__publicField(this, "Image");
__publicField(this, "ImageData");
this.browser = typeof navigator !== "undefined";
this.node = typeof process !== "undefined" && typeof process.versions !== "undefined" && typeof process.versions.node !== "undefined";
this.tfjs = { version: tf3.version["tfjs-core"] };
this.offscreen = typeof OffscreenCanvas !== "undefined";
this.initial = true;
this.worker = this.browser && this.offscreen ? typeof WorkerGlobalScope !== "undefined" : void 0;
if (typeof navigator !== "undefined") {
const raw = navigator.userAgent.match(/\(([^()]+)\)/g);
if (raw && raw[0]) {
const platformMatch = raw[0].match(/\(([^()]+)\)/g);
this.platform = platformMatch && platformMatch[0] ? platformMatch[0].replace(/\(|\)/g, "") : "";
this.agent = navigator.userAgent.replace(raw[0], "");
if (this.platform[1])
this.agent = this.agent.replace(raw[1], "");
this.agent = this.agent.replace(/ /g, " ");
}
} else if (typeof process !== "undefined") {
this.platform = `${process.platform} ${process.arch}`;
this.agent = `NodeJS ${process.version}`;
}
}
async updateBackend() {
this.backends = Object.keys(tf3.engine().registryFactory);
this.wasm.supported = typeof WebAssembly !== "undefined";
this.wasm.backend = this.backends.includes("wasm");
if (this.wasm.supported && this.wasm.backend && tf3.getBackend() === "wasm") {
this.wasm.simd = await tf3.env().getAsync("WASM_HAS_SIMD_SUPPORT");
this.wasm.multithread = await tf3.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");
}
const c = canvas(100, 100);
const ctx = c ? c.getContext("webgl2") : void 0;
this.webgl.supported = typeof ctx !== "undefined";
this.webgl.backend = this.backends.includes("webgl");
if (this.webgl.supported && this.webgl.backend && (tf3.getBackend() === "webgl" || tf3.getBackend() === "humangl")) {
const gl = tf3.backend().gpgpu !== "undefined" ? await tf3.backend().getGPGPUContext().gl : null;
if (gl) {
this.webgl.version = gl.getParameter(gl.VERSION);
this.webgl.renderer = gl.getParameter(gl.RENDERER);
}
}
this.webgpu.supported = this.browser && typeof navigator["gpu"] !== "undefined";
this.webgpu.backend = this.backends.includes("webgpu");
try {
if (this.webgpu.supported)
this.webgpu.adapter = (await navigator["gpu"].requestAdapter()).name;
} catch (e) {
this.webgpu.supported = false;
}
try {
this.kernels = tf3.getKernelsForBackend(tf3.getBackend()).map((kernel) => kernel.kernelName.toLowerCase());
} catch (e) {
}
}
async updateCPU() {
const cpu = { model: "", flags: [] };
if (this.node && this.platform.startsWith("linux")) {
}
if (!this["cpu"])
Object.defineProperty(this, "cpu", { value: cpu });
else
this["cpu"] = cpu;
}
};
var env = new Env();
// src/tfjs/load.ts
var tf4 = __toESM(require_tfjs_esm());
var options = {
cacheModels: false,
verbose: true,
debug: false,
modelBasePath: ""
};
async function httpHandler(url, init2) {
if (options.debug)
log("load model fetch:", url, init2);
return fetch(url, init2);
}
function setModelLoadOptions(config3) {
options.cacheModels = config3.cacheModels;
options.verbose = config3.debug;
options.modelBasePath = config3.modelBasePath;
}
async function loadModel(modelPath) {
const modelUrl = join(options.modelBasePath, modelPath || "");
const modelPathSegments = modelUrl.split("/");
const cachedModelName = "indexeddb://" + modelPathSegments[modelPathSegments.length - 1].replace(".json", "");
const cachedModels = await tf4.io.listModels();
const modelCached = options.cacheModels && Object.keys(cachedModels).includes(cachedModelName);
const tfLoadOptions = typeof fetch === "undefined" ? {} : { fetchFunc: (url, init2) => httpHandler(url, init2) };
const model18 = new tf4.GraphModel(modelCached ? cachedModelName : modelUrl, tfLoadOptions);
try {
model18.findIOHandler();
if (options.debug)
log("model load handler:", model18.handler);
const artifacts = await model18.handler.load();
model18.loadSync(artifacts);
if (options.verbose)
log("load model:", model18["modelUrl"]);
} catch (err) {
log("error loading model:", modelUrl, err);
}
if (options.cacheModels && !modelCached) {
try {
const saveResult = await model18.save(cachedModelName);
log("model saved:", cachedModelName, saveResult);
} catch (err) {
log("error saving model:", modelUrl, err);
}
}
return model18;
}
// src/human.ts
var tf36 = __toESM(require_tfjs_esm());
// package.json
var version2 = "2.6.1";
// src/tfjs/humangl.ts
var tf31 = __toESM(require_tfjs_esm());
// src/gear/gear.ts
var tf5 = __toESM(require_tfjs_esm());
var model;
var last2 = [];
var raceNames = ["white", "black", "asian", "indian", "other"];
var ageWeights = [15, 23, 28, 35.5, 45.5, 55.5, 65];
var lastCount = 0;
var lastTime = 0;
var skipped = Number.MAX_SAFE_INTEGER;
async function load(config3) {
if (env.initial)
model = null;
if (!model)
model = await loadModel(config3.face["gear"]);
else if (config3.debug)
log("cached model:", model["modelUrl"]);
return model;
}
async function predict(image24, config3, idx, count2) {
var _a, _b;
if (!model)
return { age: 0, gender: "unknown", genderScore: 0, race: [] };
const skipFrame = skipped < (((_a = config3.face["gear"]) == null ? void 0 : _a.skipFrames) || 0);
const skipTime = (((_b = config3.face["gear"]) == null ? void 0 : _b.skipTime) || 0) > now() - lastTime;
if (config3.skipAllowed && skipTime && skipFrame && lastCount === count2 && last2[idx]) {
skipped++;
return last2[idx];
}
skipped = 0;
return new Promise(async (resolve) => {
var _a2, _b2;
if (!(model == null ? void 0 : model.inputs[0].shape))
return;
const t = {};
const box = [[0, 0.1, 0.9, 0.9]];
t.resize = tf5.image.cropAndResize(image24, box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
const obj = { age: 0, gender: "unknown", genderScore: 0, race: [] };
if ((_a2 = config3.face["gear"]) == null ? void 0 : _a2.enabled)
[t.age, t.gender, t.race] = model.execute(t.resize, ["age_output", "gender_output", "race_output"]);
const gender = await t.gender.data();
obj.gender = gender[0] > gender[1] ? "male" : "female";
obj.genderScore = Math.round(100 * (gender[0] > gender[1] ? gender[0] : gender[1])) / 100;
const race = await t.race.data();
for (let i = 0; i < race.length; i++) {
if (race[i] > (((_b2 = config3.face["gear"]) == null ? void 0 : _b2.minConfidence) || 0.2))
obj.race.push({ score: Math.round(100 * race[i]) / 100, race: raceNames[i] });
}
obj.race.sort((a, b) => b.score - a.score);
const ageDistribution = Array.from(await t.age.data());
const ageSorted = ageDistribution.map((a, i) => [ageWeights[i], a]).sort((a, b) => b[1] - a[1]);
let age = ageSorted[0][0];
for (let i = 1; i < ageSorted.length; i++)
age += ageSorted[i][1] * (ageSorted[i][0] - age);
obj.age = Math.round(10 * age) / 10;
Object.keys(t).forEach((tensor3) => tf5.dispose(t[tensor3]));
last2[idx] = obj;
lastCount = count2;
lastTime = now();
resolve(obj);
});
}
// src/gear/ssrnet-age.ts
var tf7 = __toESM(require_tfjs_esm());
// src/tfjs/constants.ts
var tf6 = __toESM(require_tfjs_esm());
var constants = {
tf255: 255,
tf1: 1,
tf2: 2,
tf05: 0.5,
tf127: 127.5,
rgb: [0.2989, 0.587, 0.114]
};
function init() {
constants.tf255 = tf6.scalar(255, "float32");
constants.tf1 = tf6.scalar(1, "float32");
constants.tf2 = tf6.scalar(2, "float32");
constants.tf05 = tf6.scalar(0.5, "float32");