UNPKG

@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,494 loc) 462 kB
/* 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_exports = {}; __reExport2(tf_node_exports, require("@tensorflow/tfjs-node")); module2.exports = __toCommonJS2(tf_node_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"); constants.tf127