mirror of https://github.com/vladmandic/human
experimental webgl status monitoring
parent
7d77137a08
commit
e733377bfb
|
@ -9,27 +9,16 @@ let busy = false;
|
|||
// eslint-disable-next-line no-undef, new-cap
|
||||
const human = new Human.default();
|
||||
|
||||
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')}`;
|
||||
// eslint-disable-next-line no-console
|
||||
if (msg) console.log(ts, 'Human:', ...msg);
|
||||
}
|
||||
|
||||
onmessage = async (msg) => {
|
||||
onmessage = async (msg) => { // receive message from main thread
|
||||
if (busy) return;
|
||||
busy = true;
|
||||
// received from index.js using:
|
||||
// worker.postMessage({ image: image.data.buffer, width: canvas.width, height: canvas.height, config }, [image.data.buffer]);
|
||||
const image = new ImageData(new Uint8ClampedArray(msg.data.image), msg.data.width, msg.data.height);
|
||||
let result = {};
|
||||
try {
|
||||
result = await human.detect(image, msg.data.userConfig);
|
||||
} catch (err) {
|
||||
result.error = err.message;
|
||||
log('worker thread error:', err.message);
|
||||
}
|
||||
|
||||
result = await human.detect(image, msg.data.userConfig);
|
||||
result.tensors = human.tf.engine().state.numTensors; // append to result object so main thread get info
|
||||
result.backend = human.tf.getBackend(); // append to result object so main thread get info
|
||||
if (result.canvas) { // convert canvas to imageData and send it by reference
|
||||
const canvas = new OffscreenCanvas(result.canvas.width, result.canvas.height);
|
||||
const ctx = canvas.getContext('2d');
|
||||
|
@ -37,9 +26,9 @@ onmessage = async (msg) => {
|
|||
const img = ctx ? ctx.getImageData(0, 0, result.canvas.width, result.canvas.height) : null;
|
||||
result.canvas = null; // must strip original canvas from return value as it cannot be transfered from worker thread
|
||||
if (img) postMessage({ result, image: img.data.buffer, width: msg.data.width, height: msg.data.height }, [img.data.buffer]);
|
||||
else postMessage({ result });
|
||||
else postMessage({ result }); // send message back to main thread with canvas
|
||||
} else {
|
||||
postMessage({ result });
|
||||
postMessage({ result }); // send message back to main thread without canvas
|
||||
}
|
||||
busy = false;
|
||||
};
|
||||
|
|
|
@ -33,6 +33,7 @@ let human;
|
|||
let userConfig = {
|
||||
warmup: 'none',
|
||||
backend: 'humangl',
|
||||
debug: true,
|
||||
/*
|
||||
wasmPath: 'https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-wasm@3.9.0/dist/',
|
||||
async: false,
|
||||
|
@ -176,6 +177,20 @@ function status(msg) {
|
|||
}
|
||||
}
|
||||
|
||||
async function videoPlay() {
|
||||
document.getElementById('btnStartText').innerHTML = 'pause video';
|
||||
await document.getElementById('video').play();
|
||||
status();
|
||||
}
|
||||
|
||||
async function videoPause() {
|
||||
document.getElementById('btnStartText').innerHTML = 'start video';
|
||||
await document.getElementById('video').pause();
|
||||
status('paused');
|
||||
document.getElementById('play').style.display = 'block';
|
||||
document.getElementById('loader').style.display = 'none';
|
||||
}
|
||||
|
||||
const compare = { enabled: false, original: null };
|
||||
async function calcSimmilarity(result) {
|
||||
document.getElementById('compare-container').style.display = compare.enabled ? 'block' : 'none';
|
||||
|
@ -280,7 +295,7 @@ async function drawResults(input) {
|
|||
const avgDraw = ui.drawFPS.length > 0 ? Math.trunc(10 * ui.drawFPS.reduce((a, b) => a + b, 0) / ui.drawFPS.length) / 10 : 0;
|
||||
const warning = (ui.detectFPS.length > 5) && (avgDetect < 2) ? '<font color="lightcoral">warning: your performance is low: try switching to higher performance backend, lowering resolution or disabling some models</font>' : '';
|
||||
const fps = avgDetect > 0 ? `FPS process:${avgDetect} refresh:${avgDraw}` : '';
|
||||
const backend = engine.state.numTensors > 0 ? `backend: ${human.tf.getBackend()} | ${memory}` : 'running in web worker';
|
||||
const backend = engine.state.numTensors > 0 ? `${human.tf.getBackend()} | ${memory}` : `${result.backend} | tensors: ${result.tensors} in worker`;
|
||||
document.getElementById('log').innerHTML = `
|
||||
video: ${ui.camera.name} | facing: ${ui.camera.facing} | screen: ${window.innerWidth} x ${window.innerHeight} camera: ${ui.camera.width} x ${ui.camera.height} ${processing}<br>
|
||||
backend: ${backend}<br>
|
||||
|
@ -387,7 +402,7 @@ async function setupCamera() {
|
|||
canvas.height = video.videoHeight;
|
||||
ui.menuWidth.input.setAttribute('value', video.videoWidth);
|
||||
ui.menuHeight.input.setAttribute('value', video.videoHeight);
|
||||
if (live || ui.autoPlay) video.play();
|
||||
if (live || ui.autoPlay) videoPlay();
|
||||
// eslint-disable-next-line no-use-before-define
|
||||
if ((live || ui.autoPlay) && !ui.detectThread) runHumanDetect(video, canvas);
|
||||
ui.busy = false;
|
||||
|
@ -485,8 +500,20 @@ function runHumanDetect(input, canvas, timestamp) {
|
|||
// perform detection in worker
|
||||
webWorker(input, data, canvas, timestamp);
|
||||
} else {
|
||||
if (human.env.initial) status('starting detection');
|
||||
else status();
|
||||
human.detect(input, userConfig).then((result) => {
|
||||
status();
|
||||
/*
|
||||
setTimeout(async () => { // simulate gl context lost 2sec after initial detection
|
||||
const ext = human.gl && human.gl.gl ? human.gl.gl.getExtension('WEBGL_lose_context') : {};
|
||||
if (ext && ext.loseContext) {
|
||||
log('simulate context lost:', human.env.webgl, human.gl, ext);
|
||||
human.gl.gl.getExtension('WEBGL_lose_context').loseContext();
|
||||
await videoPause();
|
||||
status('Exception: WebGL');
|
||||
}
|
||||
}, 2000);
|
||||
*/
|
||||
if (result.performance && result.performance.total) ui.detectFPS.push(1000 / result.performance.total);
|
||||
if (ui.detectFPS.length > ui.maxFPSframes) ui.detectFPS.shift();
|
||||
if (ui.bench) {
|
||||
|
@ -588,10 +615,8 @@ async function processVideo(input, title) {
|
|||
video.addEventListener('canplay', async () => {
|
||||
for (const m of Object.values(menu)) m.hide();
|
||||
document.getElementById('samples-container').style.display = 'none';
|
||||
document.getElementById('play').style.display = 'none';
|
||||
canvas.style.display = 'block';
|
||||
document.getElementById('btnStartText').innerHTML = 'pause video';
|
||||
await video.play();
|
||||
await videoPlay();
|
||||
if (!ui.detectThread) runHumanDetect(video, canvas);
|
||||
});
|
||||
video.src = input;
|
||||
|
@ -605,17 +630,14 @@ async function detectVideo() {
|
|||
canvas.style.display = 'block';
|
||||
cancelAnimationFrame(ui.detectThread);
|
||||
if ((video.srcObject !== null) && !video.paused) {
|
||||
document.getElementById('btnStartText').innerHTML = 'start video';
|
||||
status('paused');
|
||||
await video.pause();
|
||||
await videoPause();
|
||||
// if (ui.drawThread) cancelAnimationFrame(ui.drawThread);
|
||||
} else {
|
||||
const cameraError = await setupCamera();
|
||||
if (!cameraError) {
|
||||
status('starting detection');
|
||||
for (const m of Object.values(menu)) m.hide();
|
||||
document.getElementById('btnStartText').innerHTML = 'pause video';
|
||||
await video.play();
|
||||
await videoPlay();
|
||||
runHumanDetect(video, canvas);
|
||||
} else {
|
||||
status(cameraError);
|
||||
|
@ -904,6 +926,7 @@ async function pwaRegister() {
|
|||
}
|
||||
|
||||
async function main() {
|
||||
/*
|
||||
window.addEventListener('unhandledrejection', (evt) => {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(evt.reason || evt);
|
||||
|
@ -911,6 +934,7 @@ async function main() {
|
|||
status('exception error');
|
||||
evt.preventDefault();
|
||||
});
|
||||
*/
|
||||
|
||||
log('demo starting ...');
|
||||
|
||||
|
@ -1028,6 +1052,7 @@ async function main() {
|
|||
}
|
||||
|
||||
if (human.config.debug) log('environment:', human.env);
|
||||
if (human.config.backend === 'humangl' && human.config.debug) log('backend:', human.gl);
|
||||
}
|
||||
|
||||
window.onload = main;
|
||||
|
|
|
@ -340,13 +340,13 @@ function rotatePoint(homogeneousCoordinate, rotationMatrix) {
|
|||
dot(homogeneousCoordinate, rotationMatrix[1])
|
||||
];
|
||||
}
|
||||
function generateAnchors(inputSize) {
|
||||
const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };
|
||||
function generateAnchors(inputSize2) {
|
||||
const spec = { strides: [inputSize2 / 16, inputSize2 / 8], anchors: [2, 6] };
|
||||
const anchors3 = [];
|
||||
for (let i = 0; i < spec.strides.length; i++) {
|
||||
const stride = spec.strides[i];
|
||||
const gridRows = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridRows = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const anchorsNum = spec.anchors[i];
|
||||
for (let gridY = 0; gridY < gridRows; gridY++) {
|
||||
const anchorY = stride * (gridY + 0.5);
|
||||
|
@ -363,17 +363,17 @@ function generateAnchors(inputSize) {
|
|||
|
||||
// src/blazeface/blazeface.ts
|
||||
var keypointsCount = 6;
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize) {
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize2) {
|
||||
const boxStarts = tfjs_esm_exports.slice(boxOutputs, [0, 1], [-1, 2]);
|
||||
const centers = tfjs_esm_exports.add(boxStarts, anchors3);
|
||||
const boxSizes = tfjs_esm_exports.slice(boxOutputs, [0, 3], [-1, 2]);
|
||||
const boxSizesNormalized = tfjs_esm_exports.div(boxSizes, inputSize);
|
||||
const centersNormalized = tfjs_esm_exports.div(centers, inputSize);
|
||||
const boxSizesNormalized = tfjs_esm_exports.div(boxSizes, inputSize2);
|
||||
const centersNormalized = tfjs_esm_exports.div(centers, inputSize2);
|
||||
const halfBoxSize = tfjs_esm_exports.div(boxSizesNormalized, 2);
|
||||
const starts = tfjs_esm_exports.sub(centersNormalized, halfBoxSize);
|
||||
const ends = tfjs_esm_exports.add(centersNormalized, halfBoxSize);
|
||||
const startNormalized = tfjs_esm_exports.mul(starts, inputSize);
|
||||
const endNormalized = tfjs_esm_exports.mul(ends, inputSize);
|
||||
const startNormalized = tfjs_esm_exports.mul(starts, inputSize2);
|
||||
const endNormalized = tfjs_esm_exports.mul(ends, inputSize2);
|
||||
const concatAxis = 1;
|
||||
return tfjs_esm_exports.concat2d([startNormalized, endNormalized], concatAxis);
|
||||
}
|
||||
|
@ -4562,9 +4562,13 @@ function process2(input, config3) {
|
|||
pixels = tfjs_esm_exports.browser && env.browser ? tfjs_esm_exports.browser.fromPixels(tempCanvas) : null;
|
||||
} else {
|
||||
const tempCanvas = canvas(targetWidth, targetHeight);
|
||||
if (!tempCanvas)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
if (!tempCtx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCtx.drawImage(outCanvas, 0, 0);
|
||||
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
if (tfjs_esm_exports.browser && env.browser) {
|
||||
|
@ -4620,6 +4624,7 @@ var env = {
|
|||
worker: void 0,
|
||||
platform: void 0,
|
||||
agent: void 0,
|
||||
initial: true,
|
||||
backends: [],
|
||||
tfjs: {
|
||||
version: void 0
|
||||
|
@ -5024,7 +5029,9 @@ async function predict(input, config3) {
|
|||
return results;
|
||||
}
|
||||
async function load2(config3) {
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled) {
|
||||
if (env.initial)
|
||||
faceModels = [null, null, null];
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled || env.initial) {
|
||||
faceModels = await Promise.all([
|
||||
!faceModels[0] && config3.face.enabled ? load(config3) : null,
|
||||
!faceModels[1] && config3.face.mesh.enabled ? tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.face.mesh.modelPath), { fromTFHub: config3.face.mesh.modelPath.includes("tfhub.dev") }) : null,
|
||||
|
@ -5064,6 +5071,8 @@ var skipped = Number.MAX_SAFE_INTEGER;
|
|||
async function load3(config3) {
|
||||
var _a, _b;
|
||||
const modelUrl = join(config3.modelBasePath, ((_a = config3.face.description) == null ? void 0 : _a.modelPath) || "");
|
||||
if (env.initial)
|
||||
model = null;
|
||||
if (!model) {
|
||||
model = await tfjs_esm_exports.loadGraphModel(modelUrl);
|
||||
if (!model)
|
||||
|
@ -5104,7 +5113,7 @@ function enhance(input) {
|
|||
if (!(tensor3 instanceof tfjs_esm_exports.Tensor))
|
||||
return null;
|
||||
const box6 = [[0.05, 0.15, 0.85, 0.85]];
|
||||
if (!model.inputs[0].shape)
|
||||
if (!(model == null ? void 0 : model.inputs[0].shape))
|
||||
return null;
|
||||
const crop = tensor3.shape.length === 3 ? tfjs_esm_exports.image.cropAndResize(tfjs_esm_exports.expandDims(tensor3, 0), box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) : tfjs_esm_exports.image.cropAndResize(tensor3, box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
|
||||
const norm = tfjs_esm_exports.mul(crop, 255);
|
||||
|
@ -5132,7 +5141,7 @@ async function predict2(image22, config3, idx, count2) {
|
|||
descriptor: []
|
||||
};
|
||||
if ((_a2 = config3.face.description) == null ? void 0 : _a2.enabled)
|
||||
resT = await model.predict(enhanced);
|
||||
resT = await (model == null ? void 0 : model.predict(enhanced));
|
||||
tfjs_esm_exports.dispose(enhanced);
|
||||
if (resT) {
|
||||
const gender = await resT.find((t) => t.shape[1] === 1).data();
|
||||
|
@ -5165,15 +5174,17 @@ var lastCount2 = 0;
|
|||
var skipped2 = Number.MAX_SAFE_INTEGER;
|
||||
var rgb = [0.2989, 0.587, 0.114];
|
||||
async function load4(config3) {
|
||||
var _a, _b;
|
||||
var _a;
|
||||
if (env.initial)
|
||||
model2 = null;
|
||||
if (!model2) {
|
||||
model2 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, ((_a = config3.face.emotion) == null ? void 0 : _a.modelPath) || ""));
|
||||
if (!model2 || !model2.modelUrl)
|
||||
log("load model failed:", ((_b = config3.face.emotion) == null ? void 0 : _b.modelPath) || "");
|
||||
if (!model2 || !model2["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model2.modelUrl);
|
||||
log("load model:", model2["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model2.modelUrl);
|
||||
log("cached model:", model2["modelUrl"]);
|
||||
return model2;
|
||||
}
|
||||
async function predict3(image22, config3, idx, count2) {
|
||||
|
@ -5187,7 +5198,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
skipped2 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
var _a2, _b;
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(image22, [model2.inputs[0].shape[2], model2.inputs[0].shape[1]], false);
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(image22, [(model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[2] : 0, (model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[1] : 0], false);
|
||||
const [red, green, blue] = tfjs_esm_exports.split(resize, 3, 3);
|
||||
tfjs_esm_exports.dispose(resize);
|
||||
const redNorm = tfjs_esm_exports.mul(red, rgb[0]);
|
||||
|
@ -5204,7 +5215,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
tfjs_esm_exports.dispose(grayscale);
|
||||
const obj = [];
|
||||
if ((_a2 = config3.face.emotion) == null ? void 0 : _a2.enabled) {
|
||||
const emotionT = await model2.predict(normalize);
|
||||
const emotionT = await (model2 == null ? void 0 : model2.predict(normalize));
|
||||
const data = await emotionT.data();
|
||||
tfjs_esm_exports.dispose(emotionT);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
@ -5553,7 +5564,7 @@ async function predict4(input, config3) {
|
|||
return scaled;
|
||||
}
|
||||
async function load5(config3) {
|
||||
if (!model3) {
|
||||
if (!model3 || env.initial) {
|
||||
model3 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model3 || !model3["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
|
@ -9283,6 +9294,10 @@ async function predict5(input, config3) {
|
|||
}
|
||||
async function load6(config3) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
if (env.initial) {
|
||||
handDetectorModel = null;
|
||||
handPoseModel = null;
|
||||
}
|
||||
if (!handDetectorModel || !handPoseModel) {
|
||||
[handDetectorModel, handPoseModel] = await Promise.all([
|
||||
config3.hand.enabled ? tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, ((_a = config3.hand.detector) == null ? void 0 : _a.modelPath) || ""), { fromTFHub: (((_b = config3.hand.detector) == null ? void 0 : _b.modelPath) || "").includes("tfhub.dev") }) : null,
|
||||
|
@ -9388,6 +9403,8 @@ var upper = [
|
|||
// src/blazepose/blazepose.ts
|
||||
var model4;
|
||||
async function load7(config3) {
|
||||
if (env.initial)
|
||||
model4 = null;
|
||||
if (!model4) {
|
||||
model4 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
model4["width"] = parseInt(model4["signature"].inputs["input_1:0"].tensorShape.dim[2].size);
|
||||
|
@ -9457,6 +9474,8 @@ var score = 0;
|
|||
var skipped3 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts = ["head", "neck", "rightShoulder", "rightElbow", "rightWrist", "chest", "leftShoulder", "leftElbow", "leftWrist", "pelvis", "rightHip", "rightKnee", "rightAnkle", "leftHip", "leftKnee", "leftAnkle"];
|
||||
async function load8(config3) {
|
||||
if (env.initial)
|
||||
model5 = null;
|
||||
if (!model5) {
|
||||
model5 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model5 || !model5["modelUrl"])
|
||||
|
@ -9492,7 +9511,7 @@ async function predict7(image22, config3) {
|
|||
return new Promise(async (resolve) => {
|
||||
var _a2;
|
||||
const tensor3 = tfjs_esm_exports.tidy(() => {
|
||||
if (!model5.inputs[0].shape)
|
||||
if (!(model5 == null ? void 0 : model5.inputs[0].shape))
|
||||
return null;
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(image22, [model5.inputs[0].shape[2], model5.inputs[0].shape[1]], false);
|
||||
const enhance2 = tfjs_esm_exports.mul(resize, 2);
|
||||
|
@ -9501,7 +9520,7 @@ async function predict7(image22, config3) {
|
|||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model5.predict(tensor3);
|
||||
resT = await (model5 == null ? void 0 : model5.predict(tensor3));
|
||||
tfjs_esm_exports.dispose(tensor3);
|
||||
if (resT) {
|
||||
keypoints.length = 0;
|
||||
|
@ -9558,6 +9577,8 @@ var score2 = 0;
|
|||
var skipped4 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts2 = ["nose", "leftEye", "rightEye", "leftEar", "rightEar", "leftShoulder", "rightShoulder", "leftElbow", "rightElbow", "leftWrist", "rightWrist", "leftHip", "rightHip", "leftKnee", "rightKnee", "leftAnkle", "rightAnkle"];
|
||||
async function load9(config3) {
|
||||
if (env.initial)
|
||||
model6 = null;
|
||||
if (!model6) {
|
||||
model6 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model6 || !model6["modelUrl"])
|
||||
|
@ -9658,18 +9679,18 @@ async function predict8(image22, config3) {
|
|||
skipped4 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor3 = tfjs_esm_exports.tidy(() => {
|
||||
if (!model6.inputs[0].shape)
|
||||
if (!(model6 == null ? void 0 : model6.inputs[0].shape))
|
||||
return null;
|
||||
let inputSize = model6.inputs[0].shape[2];
|
||||
if (inputSize === -1)
|
||||
inputSize = 256;
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(image22, [inputSize, inputSize], false);
|
||||
let inputSize2 = model6.inputs[0].shape[2];
|
||||
if (inputSize2 === -1)
|
||||
inputSize2 = 256;
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(image22, [inputSize2, inputSize2], false);
|
||||
const cast4 = tfjs_esm_exports.cast(resize, "int32");
|
||||
return cast4;
|
||||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model6.predict(tensor3);
|
||||
resT = await (model6 == null ? void 0 : model6.predict(tensor3));
|
||||
tfjs_esm_exports.dispose(tensor3);
|
||||
if (!resT)
|
||||
resolve([]);
|
||||
|
@ -9774,7 +9795,7 @@ var last3 = [];
|
|||
var skipped5 = Number.MAX_SAFE_INTEGER;
|
||||
var scaleBox = 2.5;
|
||||
async function load10(config3) {
|
||||
if (!model7) {
|
||||
if (!model7 || env.initial) {
|
||||
model7 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model7.modelSignature["inputs"]);
|
||||
model7.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
|
@ -9788,7 +9809,7 @@ async function load10(config3) {
|
|||
log("cached model:", model7.modelUrl);
|
||||
return model7;
|
||||
}
|
||||
async function process3(res, inputSize, outputShape, config3) {
|
||||
async function process3(res, inputSize2, outputShape, config3) {
|
||||
let id = 0;
|
||||
let results = [];
|
||||
for (const strideSize of [1, 2, 4]) {
|
||||
|
@ -9806,7 +9827,7 @@ async function process3(res, inputSize, outputShape, config3) {
|
|||
if (score3 > config3.object.minConfidence && j !== 61) {
|
||||
const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize;
|
||||
const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize;
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize));
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize2));
|
||||
const [x, y] = [
|
||||
cx - scaleBox / strideSize * boxOffset[0],
|
||||
cy - scaleBox / strideSize * boxOffset[1]
|
||||
|
@ -9876,24 +9897,25 @@ async function predict9(image22, config3) {
|
|||
|
||||
// src/object/centernet.ts
|
||||
var model8;
|
||||
var inputSize = 0;
|
||||
var last4 = [];
|
||||
var skipped6 = Number.MAX_SAFE_INTEGER;
|
||||
async function load11(config3) {
|
||||
if (env.initial)
|
||||
model8 = null;
|
||||
if (!model8) {
|
||||
model8 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model8.modelSignature["inputs"]);
|
||||
model8.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
if (!model8.inputSize)
|
||||
throw new Error(`Human: Cannot determine model inputSize: ${config3.object.modelPath}`);
|
||||
if (!model8 || !model8.modelUrl)
|
||||
inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
|
||||
if (!model8 || !model8["modelUrl"])
|
||||
log("load model failed:", config3.object.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model8.modelUrl);
|
||||
log("load model:", model8["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model8.modelUrl);
|
||||
log("cached model:", model8["modelUrl"]);
|
||||
return model8;
|
||||
}
|
||||
async function process4(res, inputSize, outputShape, config3) {
|
||||
async function process4(res, outputShape, config3) {
|
||||
if (!res)
|
||||
return [];
|
||||
const results = [];
|
||||
|
@ -9949,10 +9971,10 @@ async function predict10(input, config3) {
|
|||
return last4;
|
||||
return new Promise(async (resolve) => {
|
||||
const outputSize = [input.shape[2], input.shape[1]];
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(input, [model8.inputSize, model8.inputSize]);
|
||||
const objectT = config3.object.enabled ? model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
const resize = tfjs_esm_exports.image.resizeBilinear(input, [inputSize, inputSize]);
|
||||
const objectT = config3.object.enabled ? model8 == null ? void 0 : model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
tfjs_esm_exports.dispose(resize);
|
||||
const obj = await process4(objectT, model8.inputSize, outputSize, config3);
|
||||
const obj = await process4(objectT, outputSize, config3);
|
||||
last4 = obj;
|
||||
resolve(obj);
|
||||
});
|
||||
|
@ -9962,7 +9984,7 @@ async function predict10(input, config3) {
|
|||
var model9;
|
||||
var busy = false;
|
||||
async function load12(config3) {
|
||||
if (!model9) {
|
||||
if (!model9 || env.initial) {
|
||||
model9 = await tfjs_esm_exports.loadGraphModel(join(config3.modelBasePath, config3.segmentation.modelPath || ""));
|
||||
if (!model9 || !model9["modelUrl"])
|
||||
log("load model failed:", config3.segmentation.modelPath);
|
||||
|
@ -10074,7 +10096,27 @@ async function process5(input, background, config3) {
|
|||
}
|
||||
|
||||
// src/models.ts
|
||||
function reset(instance) {
|
||||
instance.models = {
|
||||
face: null,
|
||||
handpose: null,
|
||||
posenet: null,
|
||||
blazepose: null,
|
||||
efficientpose: null,
|
||||
movenet: null,
|
||||
age: null,
|
||||
gender: null,
|
||||
emotion: null,
|
||||
embedding: null,
|
||||
nanodet: null,
|
||||
centernet: null,
|
||||
faceres: null,
|
||||
segmentation: null
|
||||
};
|
||||
}
|
||||
async function load13(instance) {
|
||||
if (env.initial)
|
||||
reset(instance);
|
||||
if (instance.config.async) {
|
||||
[
|
||||
instance.models.face,
|
||||
|
@ -10130,20 +10172,28 @@ async function validate(instance) {
|
|||
const simpleOps = ["const", "placeholder", "noop", "pad", "squeeze", "add", "sub", "mul", "div"];
|
||||
for (const defined of Object.keys(instance.models)) {
|
||||
if (instance.models[defined]) {
|
||||
let models2 = [];
|
||||
let models3 = [];
|
||||
if (Array.isArray(instance.models[defined]))
|
||||
models2 = instance.models[defined].map((model10) => model10.executor ? model10 : model10.model);
|
||||
models3 = instance.models[defined].map((model10) => model10 && model10.executor ? model10 : model10.model);
|
||||
else
|
||||
models2 = [instance.models[defined]];
|
||||
for (const model10 of models2) {
|
||||
models3 = [instance.models[defined]];
|
||||
for (const model10 of models3) {
|
||||
if (!model10) {
|
||||
if (instance.config.debug)
|
||||
log("model marked as loaded but not defined:", defined);
|
||||
continue;
|
||||
}
|
||||
const ops = [];
|
||||
const executor = model10 == null ? void 0 : model10.executor;
|
||||
if (executor) {
|
||||
if (executor && executor.graph.nodes) {
|
||||
for (const kernel of Object.values(executor.graph.nodes)) {
|
||||
const op = kernel.op.toLowerCase();
|
||||
if (!ops.includes(op))
|
||||
ops.push(op);
|
||||
}
|
||||
} else {
|
||||
if (!executor && instance.config.debug)
|
||||
log("model signature not determined:", defined);
|
||||
}
|
||||
const missing = [];
|
||||
for (const op of ops) {
|
||||
|
@ -10151,8 +10201,6 @@ async function validate(instance) {
|
|||
missing.push(op);
|
||||
}
|
||||
}
|
||||
if (!executor && instance.config.debug)
|
||||
log("model executor not found:", defined);
|
||||
if (missing.length > 0 && instance.config.debug)
|
||||
log("model validation:", defined, missing);
|
||||
}
|
||||
|
@ -11103,11 +11151,9 @@ function calc(newResult) {
|
|||
// src/tfjs/humangl.ts
|
||||
var config2 = {
|
||||
name: "humangl",
|
||||
priority: 99,
|
||||
priority: 999,
|
||||
canvas: null,
|
||||
gl: null,
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
extensions: [],
|
||||
webGLattr: {
|
||||
alpha: false,
|
||||
|
@ -11126,27 +11172,58 @@ function extensions() {
|
|||
return;
|
||||
config2.extensions = gl.getSupportedExtensions();
|
||||
}
|
||||
function register() {
|
||||
async function register(instance) {
|
||||
var _a;
|
||||
if (config2.name in tfjs_esm_exports.engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) {
|
||||
log("error: humangl backend invalid context");
|
||||
log("resetting humangl backend");
|
||||
reset(instance);
|
||||
await tfjs_esm_exports.removeBackend(config2.name);
|
||||
await register(instance);
|
||||
}
|
||||
if (!tfjs_esm_exports.findBackend(config2.name)) {
|
||||
try {
|
||||
config2.canvas = canvas(100, 100);
|
||||
config2.canvas = await canvas(100, 100);
|
||||
} catch (err) {
|
||||
log("error: cannot create canvas:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config2.gl = (_a = config2.canvas) == null ? void 0 : _a.getContext("webgl2", config2.webGLattr);
|
||||
if (config2.canvas) {
|
||||
config2.canvas.addEventListener("webglcontextlost", async (e) => {
|
||||
var _a2;
|
||||
const err = (_a2 = config2.gl) == null ? void 0 : _a2.getError();
|
||||
log("error: humangl context lost:", err, e);
|
||||
log("gpu memory usage:", instance.tf.engine().backendInstance.numBytesInGPU);
|
||||
log("resetting humangl backend");
|
||||
env.initial = true;
|
||||
reset(instance);
|
||||
await tfjs_esm_exports.removeBackend(config2.name);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextrestored", (e) => {
|
||||
log("error: humangl context restored:", e);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextcreationerror", (e) => {
|
||||
log("error: humangl context create:", e);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
log("error: cannot get WebGL2 context:", err);
|
||||
log("error: cannot get WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
tfjs_esm_exports.setWebGLContext(2, config2.gl);
|
||||
} catch (err) {
|
||||
log("error: cannot set WebGL2 context:", err);
|
||||
log("error: cannot set WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
const current = tfjs_esm_exports.backend().getGPGPUContext().gl;
|
||||
if (current) {
|
||||
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);
|
||||
} else {
|
||||
log("error: no current context:", current, config2.gl);
|
||||
}
|
||||
try {
|
||||
const ctx = new tfjs_esm_exports.GPGPUContext(config2.gl);
|
||||
tfjs_esm_exports.registerBackend(config2.name, () => new tfjs_esm_exports.MathBackendWebGL(ctx), config2.priority);
|
||||
|
@ -11177,19 +11254,22 @@ function register() {
|
|||
|
||||
// src/tfjs/backend.ts
|
||||
async function check(instance) {
|
||||
if (instance.initial || instance.config.backend && instance.config.backend.length > 0 && tfjs_esm_exports.getBackend() !== instance.config.backend) {
|
||||
if (env.initial || instance.config.backend && instance.config.backend.length > 0 && tfjs_esm_exports.getBackend() !== instance.config.backend) {
|
||||
const timeStamp = now();
|
||||
instance.state = "backend";
|
||||
if (instance.config.backend && instance.config.backend.length > 0) {
|
||||
if (typeof window === "undefined" && typeof WorkerGlobalScope !== "undefined" && instance.config.debug) {
|
||||
log("running inside web worker");
|
||||
if (instance.config.debug)
|
||||
log("running inside web worker");
|
||||
}
|
||||
if (env.browser && instance.config.backend === "tensorflow") {
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
if (instance.config.debug)
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
instance.config.backend = "humangl";
|
||||
}
|
||||
if (env.node && (instance.config.backend === "webgl" || instance.config.backend === "humangl")) {
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
if (instance.config.debug)
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
instance.config.backend = "tensorflow";
|
||||
}
|
||||
if (env.browser && instance.config.backend === "webgpu") {
|
||||
|
@ -11203,14 +11283,15 @@ async function check(instance) {
|
|||
}
|
||||
}
|
||||
if (instance.config.backend === "humangl")
|
||||
register();
|
||||
await register(instance);
|
||||
const available = Object.keys(tfjs_esm_exports.engine().registryFactory);
|
||||
if (instance.config.debug)
|
||||
log("available backends:", available);
|
||||
if (!available.includes(instance.config.backend)) {
|
||||
log(`error: backend ${instance.config.backend} not found in registry`);
|
||||
instance.config.backend = env.node ? "tensorflow" : "humangl";
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
if (instance.config.debug)
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
}
|
||||
if (instance.config.debug)
|
||||
log("setting backend:", instance.config.backend);
|
||||
|
@ -11236,6 +11317,7 @@ async function check(instance) {
|
|||
log("error: cannot set backend:", instance.config.backend, err);
|
||||
}
|
||||
}
|
||||
tfjs_esm_exports.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 0);
|
||||
if (tfjs_esm_exports.getBackend() === "humangl") {
|
||||
tfjs_esm_exports.ENV.set("CHECK_COMPUTATION_FOR_ERRORS", false);
|
||||
tfjs_esm_exports.ENV.set("WEBGL_CPU_FORWARD", true);
|
||||
|
@ -12106,7 +12188,7 @@ var Human = class {
|
|||
__privateAdd(this, _numTensors, void 0);
|
||||
__privateAdd(this, _analyzeMemoryLeaks, void 0);
|
||||
__privateAdd(this, _checkSanity, void 0);
|
||||
__publicField(this, "initial");
|
||||
__publicField(this, "gl");
|
||||
__publicField(this, "analyze", (...msg) => {
|
||||
if (!__privateGet(this, _analyzeMemoryLeaks))
|
||||
return;
|
||||
|
@ -12149,7 +12231,6 @@ var Human = class {
|
|||
__privateSet(this, _numTensors, 0);
|
||||
__privateSet(this, _analyzeMemoryLeaks, false);
|
||||
__privateSet(this, _checkSanity, false);
|
||||
this.initial = true;
|
||||
this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };
|
||||
this.events = new EventTarget();
|
||||
this.models = {
|
||||
|
@ -12183,6 +12264,7 @@ var Human = class {
|
|||
this.process = { tensor: null, canvas: null };
|
||||
this.faceTriangulation = triangulation;
|
||||
this.faceUVMap = uvmap;
|
||||
this.gl = config2;
|
||||
this.emit("create");
|
||||
}
|
||||
similarity(embedding1, embedding2) {
|
||||
|
@ -12203,7 +12285,7 @@ var Human = class {
|
|||
const count2 = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (userConfig)
|
||||
this.config = mergeDeep(this.config, userConfig);
|
||||
if (this.initial) {
|
||||
if (env.initial) {
|
||||
if (this.config.debug)
|
||||
log(`version: ${this.version}`);
|
||||
if (this.config.debug)
|
||||
|
@ -12218,9 +12300,9 @@ var Human = class {
|
|||
}
|
||||
}
|
||||
await load13(this);
|
||||
if (this.initial && this.config.debug)
|
||||
if (env.initial && this.config.debug)
|
||||
log("tf engine state:", this.tf.engine().state.numBytes, "bytes", this.tf.engine().state.numTensors, "tensors");
|
||||
this.initial = false;
|
||||
env.initial = false;
|
||||
const loaded = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (loaded !== count2) {
|
||||
await validate(this);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -41160,17 +41160,17 @@ function fftBatch(input2, inverse, cpuBackend) {
|
|||
return result;
|
||||
}
|
||||
function fftImpl(input2, inverse, cpuBackend) {
|
||||
const inputSize = util_exports.sizeFromShape(input2.shape);
|
||||
const inputSize2 = util_exports.sizeFromShape(input2.shape);
|
||||
const inputVals = cpuBackend.data.get(input2.dataId);
|
||||
const realVals = cpuBackend.data.get(inputVals.complexTensorInfos.real.dataId).values;
|
||||
const imagVals = cpuBackend.data.get(inputVals.complexTensorInfos.imag.dataId).values;
|
||||
if (isExponentOf2(inputSize)) {
|
||||
const result = fftRadix2(realVals, imagVals, inputSize, inverse, cpuBackend);
|
||||
if (isExponentOf2(inputSize2)) {
|
||||
const result = fftRadix2(realVals, imagVals, inputSize2, inverse, cpuBackend);
|
||||
const resultShape = [input2.shape[0], input2.shape[1]];
|
||||
if (inverse) {
|
||||
const realInfo = cpuBackend.makeTensorInfo(resultShape, "float32", result.real);
|
||||
const imagInfo = cpuBackend.makeTensorInfo(resultShape, "float32", result.imag);
|
||||
const sizeInfo = cpuBackend.makeTensorInfo([], "float32", util_exports.createScalarValue(inputSize, "float32"));
|
||||
const sizeInfo = cpuBackend.makeTensorInfo([], "float32", util_exports.createScalarValue(inputSize2, "float32"));
|
||||
const sizeInfoCopy = identity2({ inputs: { x: sizeInfo }, backend: cpuBackend });
|
||||
const divRealInfo = realDivConfig.kernelFunc({ inputs: { a: realInfo, b: sizeInfo }, backend: cpuBackend });
|
||||
const divImagInfo = realDivConfig.kernelFunc({ inputs: { a: imagInfo, b: sizeInfoCopy }, backend: cpuBackend });
|
||||
|
@ -41187,7 +41187,7 @@ function fftImpl(input2, inverse, cpuBackend) {
|
|||
return result;
|
||||
} else {
|
||||
const data = backend_util_exports.mergeRealAndImagArrays(realVals, imagVals);
|
||||
const rawOutput = fourierTransformByMatmul(data, inputSize, inverse);
|
||||
const rawOutput = fourierTransformByMatmul(data, inputSize2, inverse);
|
||||
return backend_util_exports.splitRealAndImagArrays(rawOutput);
|
||||
}
|
||||
}
|
||||
|
@ -41309,9 +41309,9 @@ function fourierTransformByMatmul(data, size, inverse) {
|
|||
function fft2(args) {
|
||||
const { inputs, backend: backend22 } = args;
|
||||
const { input: input2 } = inputs;
|
||||
const inputSize = util_exports.sizeFromShape(input2.shape);
|
||||
const inputSize2 = util_exports.sizeFromShape(input2.shape);
|
||||
const innerDimensionSize = input2.shape[input2.shape.length - 1];
|
||||
const batch = inputSize / innerDimensionSize;
|
||||
const batch = inputSize2 / innerDimensionSize;
|
||||
const input2D = reshape3({
|
||||
inputs: { x: input2 },
|
||||
backend: backend22,
|
||||
|
@ -41510,9 +41510,9 @@ var gatherV2Config = {
|
|||
function ifft2(args) {
|
||||
const { inputs, backend: backend22 } = args;
|
||||
const { input: input2 } = inputs;
|
||||
const inputSize = util_exports.sizeFromShape(input2.shape);
|
||||
const inputSize2 = util_exports.sizeFromShape(input2.shape);
|
||||
const innerDimensionSize = input2.shape[input2.shape.length - 1];
|
||||
const batch = inputSize / innerDimensionSize;
|
||||
const batch = inputSize2 / innerDimensionSize;
|
||||
const input2D = reshape3({
|
||||
inputs: { x: input2 },
|
||||
backend: backend22,
|
||||
|
@ -53014,9 +53014,9 @@ var FFTProgram = class {
|
|||
};
|
||||
function fftImpl2(x, inverse, backend22) {
|
||||
const xData = backend22.texData.get(x.dataId);
|
||||
const inputSize = util_exports.sizeFromShape(x.shape);
|
||||
const inputSize2 = util_exports.sizeFromShape(x.shape);
|
||||
const innerDimensionSize = x.shape[x.shape.length - 1];
|
||||
const batch = inputSize / innerDimensionSize;
|
||||
const batch = inputSize2 / innerDimensionSize;
|
||||
const input2D = reshape4({ inputs: { x }, backend: backend22, attrs: { shape: [batch, innerDimensionSize] } });
|
||||
const xShape = input2D.shape;
|
||||
const realProgram = new FFTProgram("real", xShape, inverse);
|
||||
|
@ -60397,13 +60397,13 @@ function rotatePoint(homogeneousCoordinate, rotationMatrix) {
|
|||
dot4(homogeneousCoordinate, rotationMatrix[1])
|
||||
];
|
||||
}
|
||||
function generateAnchors(inputSize) {
|
||||
const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };
|
||||
function generateAnchors(inputSize2) {
|
||||
const spec = { strides: [inputSize2 / 16, inputSize2 / 8], anchors: [2, 6] };
|
||||
const anchors3 = [];
|
||||
for (let i = 0; i < spec.strides.length; i++) {
|
||||
const stride = spec.strides[i];
|
||||
const gridRows = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridRows = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const anchorsNum = spec.anchors[i];
|
||||
for (let gridY = 0; gridY < gridRows; gridY++) {
|
||||
const anchorY = stride * (gridY + 0.5);
|
||||
|
@ -60420,17 +60420,17 @@ function generateAnchors(inputSize) {
|
|||
|
||||
// src/blazeface/blazeface.ts
|
||||
var keypointsCount = 6;
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize) {
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize2) {
|
||||
const boxStarts = slice(boxOutputs, [0, 1], [-1, 2]);
|
||||
const centers = add2(boxStarts, anchors3);
|
||||
const boxSizes = slice(boxOutputs, [0, 3], [-1, 2]);
|
||||
const boxSizesNormalized = div(boxSizes, inputSize);
|
||||
const centersNormalized = div(centers, inputSize);
|
||||
const boxSizesNormalized = div(boxSizes, inputSize2);
|
||||
const centersNormalized = div(centers, inputSize2);
|
||||
const halfBoxSize = div(boxSizesNormalized, 2);
|
||||
const starts = sub(centersNormalized, halfBoxSize);
|
||||
const ends = add2(centersNormalized, halfBoxSize);
|
||||
const startNormalized = mul(starts, inputSize);
|
||||
const endNormalized = mul(ends, inputSize);
|
||||
const startNormalized = mul(starts, inputSize2);
|
||||
const endNormalized = mul(ends, inputSize2);
|
||||
const concatAxis = 1;
|
||||
return concat2d([startNormalized, endNormalized], concatAxis);
|
||||
}
|
||||
|
@ -64619,9 +64619,13 @@ function process2(input2, config3) {
|
|||
pixels = browser_exports && env2.browser ? browser_exports.fromPixels(tempCanvas) : null;
|
||||
} else {
|
||||
const tempCanvas = canvas(targetWidth, targetHeight);
|
||||
if (!tempCanvas)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
if (!tempCtx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCtx.drawImage(outCanvas, 0, 0);
|
||||
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
if (browser_exports && env2.browser) {
|
||||
|
@ -64677,6 +64681,7 @@ var env2 = {
|
|||
worker: void 0,
|
||||
platform: void 0,
|
||||
agent: void 0,
|
||||
initial: true,
|
||||
backends: [],
|
||||
tfjs: {
|
||||
version: void 0
|
||||
|
@ -65081,7 +65086,9 @@ async function predict(input2, config3) {
|
|||
return results;
|
||||
}
|
||||
async function load2(config3) {
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled) {
|
||||
if (env2.initial)
|
||||
faceModels = [null, null, null];
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled || env2.initial) {
|
||||
faceModels = await Promise.all([
|
||||
!faceModels[0] && config3.face.enabled ? load(config3) : null,
|
||||
!faceModels[1] && config3.face.mesh.enabled ? loadGraphModel(join(config3.modelBasePath, config3.face.mesh.modelPath), { fromTFHub: config3.face.mesh.modelPath.includes("tfhub.dev") }) : null,
|
||||
|
@ -65121,6 +65128,8 @@ var skipped = Number.MAX_SAFE_INTEGER;
|
|||
async function load3(config3) {
|
||||
var _a, _b;
|
||||
const modelUrl = join(config3.modelBasePath, ((_a = config3.face.description) == null ? void 0 : _a.modelPath) || "");
|
||||
if (env2.initial)
|
||||
model2 = null;
|
||||
if (!model2) {
|
||||
model2 = await loadGraphModel(modelUrl);
|
||||
if (!model2)
|
||||
|
@ -65161,7 +65170,7 @@ function enhance(input2) {
|
|||
if (!(tensor2 instanceof Tensor))
|
||||
return null;
|
||||
const box6 = [[0.05, 0.15, 0.85, 0.85]];
|
||||
if (!model2.inputs[0].shape)
|
||||
if (!(model2 == null ? void 0 : model2.inputs[0].shape))
|
||||
return null;
|
||||
const crop = tensor2.shape.length === 3 ? image.cropAndResize(expandDims(tensor2, 0), box6, [0], [model2.inputs[0].shape[2], model2.inputs[0].shape[1]]) : image.cropAndResize(tensor2, box6, [0], [model2.inputs[0].shape[2], model2.inputs[0].shape[1]]);
|
||||
const norm2 = mul(crop, 255);
|
||||
|
@ -65189,7 +65198,7 @@ async function predict2(image7, config3, idx, count3) {
|
|||
descriptor: []
|
||||
};
|
||||
if ((_a2 = config3.face.description) == null ? void 0 : _a2.enabled)
|
||||
resT = await model2.predict(enhanced);
|
||||
resT = await (model2 == null ? void 0 : model2.predict(enhanced));
|
||||
dispose(enhanced);
|
||||
if (resT) {
|
||||
const gender = await resT.find((t) => t.shape[1] === 1).data();
|
||||
|
@ -65222,15 +65231,17 @@ var lastCount2 = 0;
|
|||
var skipped2 = Number.MAX_SAFE_INTEGER;
|
||||
var rgb = [0.2989, 0.587, 0.114];
|
||||
async function load4(config3) {
|
||||
var _a, _b;
|
||||
var _a;
|
||||
if (env2.initial)
|
||||
model3 = null;
|
||||
if (!model3) {
|
||||
model3 = await loadGraphModel(join(config3.modelBasePath, ((_a = config3.face.emotion) == null ? void 0 : _a.modelPath) || ""));
|
||||
if (!model3 || !model3.modelUrl)
|
||||
log("load model failed:", ((_b = config3.face.emotion) == null ? void 0 : _b.modelPath) || "");
|
||||
if (!model3 || !model3["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model3.modelUrl);
|
||||
log("load model:", model3["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model3.modelUrl);
|
||||
log("cached model:", model3["modelUrl"]);
|
||||
return model3;
|
||||
}
|
||||
async function predict3(image7, config3, idx, count3) {
|
||||
|
@ -65244,7 +65255,7 @@ async function predict3(image7, config3, idx, count3) {
|
|||
skipped2 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
var _a2, _b;
|
||||
const resize = image.resizeBilinear(image7, [model3.inputs[0].shape[2], model3.inputs[0].shape[1]], false);
|
||||
const resize = image.resizeBilinear(image7, [(model3 == null ? void 0 : model3.inputs[0].shape) ? model3.inputs[0].shape[2] : 0, (model3 == null ? void 0 : model3.inputs[0].shape) ? model3.inputs[0].shape[1] : 0], false);
|
||||
const [red, green, blue] = split(resize, 3, 3);
|
||||
dispose(resize);
|
||||
const redNorm = mul(red, rgb[0]);
|
||||
|
@ -65261,7 +65272,7 @@ async function predict3(image7, config3, idx, count3) {
|
|||
dispose(grayscale);
|
||||
const obj = [];
|
||||
if ((_a2 = config3.face.emotion) == null ? void 0 : _a2.enabled) {
|
||||
const emotionT = await model3.predict(normalize);
|
||||
const emotionT = await (model3 == null ? void 0 : model3.predict(normalize));
|
||||
const data = await emotionT.data();
|
||||
dispose(emotionT);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
@ -65610,7 +65621,7 @@ async function predict4(input2, config3) {
|
|||
return scaled;
|
||||
}
|
||||
async function load5(config3) {
|
||||
if (!model4) {
|
||||
if (!model4 || env2.initial) {
|
||||
model4 = await loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model4 || !model4["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
|
@ -69340,6 +69351,10 @@ async function predict5(input2, config3) {
|
|||
}
|
||||
async function load6(config3) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
if (env2.initial) {
|
||||
handDetectorModel = null;
|
||||
handPoseModel = null;
|
||||
}
|
||||
if (!handDetectorModel || !handPoseModel) {
|
||||
[handDetectorModel, handPoseModel] = await Promise.all([
|
||||
config3.hand.enabled ? loadGraphModel(join(config3.modelBasePath, ((_a = config3.hand.detector) == null ? void 0 : _a.modelPath) || ""), { fromTFHub: (((_b = config3.hand.detector) == null ? void 0 : _b.modelPath) || "").includes("tfhub.dev") }) : null,
|
||||
|
@ -69445,6 +69460,8 @@ var upper = [
|
|||
// src/blazepose/blazepose.ts
|
||||
var model5;
|
||||
async function load7(config3) {
|
||||
if (env2.initial)
|
||||
model5 = null;
|
||||
if (!model5) {
|
||||
model5 = await loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
model5["width"] = parseInt(model5["signature"].inputs["input_1:0"].tensorShape.dim[2].size);
|
||||
|
@ -69514,6 +69531,8 @@ var score = 0;
|
|||
var skipped3 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts = ["head", "neck", "rightShoulder", "rightElbow", "rightWrist", "chest", "leftShoulder", "leftElbow", "leftWrist", "pelvis", "rightHip", "rightKnee", "rightAnkle", "leftHip", "leftKnee", "leftAnkle"];
|
||||
async function load8(config3) {
|
||||
if (env2.initial)
|
||||
model6 = null;
|
||||
if (!model6) {
|
||||
model6 = await loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model6 || !model6["modelUrl"])
|
||||
|
@ -69549,7 +69568,7 @@ async function predict7(image7, config3) {
|
|||
return new Promise(async (resolve) => {
|
||||
var _a2;
|
||||
const tensor2 = tidy(() => {
|
||||
if (!model6.inputs[0].shape)
|
||||
if (!(model6 == null ? void 0 : model6.inputs[0].shape))
|
||||
return null;
|
||||
const resize = image.resizeBilinear(image7, [model6.inputs[0].shape[2], model6.inputs[0].shape[1]], false);
|
||||
const enhance2 = mul(resize, 2);
|
||||
|
@ -69558,7 +69577,7 @@ async function predict7(image7, config3) {
|
|||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model6.predict(tensor2);
|
||||
resT = await (model6 == null ? void 0 : model6.predict(tensor2));
|
||||
dispose(tensor2);
|
||||
if (resT) {
|
||||
keypoints.length = 0;
|
||||
|
@ -69615,6 +69634,8 @@ var score2 = 0;
|
|||
var skipped4 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts2 = ["nose", "leftEye", "rightEye", "leftEar", "rightEar", "leftShoulder", "rightShoulder", "leftElbow", "rightElbow", "leftWrist", "rightWrist", "leftHip", "rightHip", "leftKnee", "rightKnee", "leftAnkle", "rightAnkle"];
|
||||
async function load9(config3) {
|
||||
if (env2.initial)
|
||||
model7 = null;
|
||||
if (!model7) {
|
||||
model7 = await loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model7 || !model7["modelUrl"])
|
||||
|
@ -69715,18 +69736,18 @@ async function predict8(image7, config3) {
|
|||
skipped4 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor2 = tidy(() => {
|
||||
if (!model7.inputs[0].shape)
|
||||
if (!(model7 == null ? void 0 : model7.inputs[0].shape))
|
||||
return null;
|
||||
let inputSize = model7.inputs[0].shape[2];
|
||||
if (inputSize === -1)
|
||||
inputSize = 256;
|
||||
const resize = image.resizeBilinear(image7, [inputSize, inputSize], false);
|
||||
let inputSize2 = model7.inputs[0].shape[2];
|
||||
if (inputSize2 === -1)
|
||||
inputSize2 = 256;
|
||||
const resize = image.resizeBilinear(image7, [inputSize2, inputSize2], false);
|
||||
const cast6 = cast(resize, "int32");
|
||||
return cast6;
|
||||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model7.predict(tensor2);
|
||||
resT = await (model7 == null ? void 0 : model7.predict(tensor2));
|
||||
dispose(tensor2);
|
||||
if (!resT)
|
||||
resolve([]);
|
||||
|
@ -69831,7 +69852,7 @@ var last3 = [];
|
|||
var skipped5 = Number.MAX_SAFE_INTEGER;
|
||||
var scaleBox = 2.5;
|
||||
async function load10(config3) {
|
||||
if (!model8) {
|
||||
if (!model8 || env2.initial) {
|
||||
model8 = await loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model8.modelSignature["inputs"]);
|
||||
model8.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
|
@ -69845,7 +69866,7 @@ async function load10(config3) {
|
|||
log("cached model:", model8.modelUrl);
|
||||
return model8;
|
||||
}
|
||||
async function process3(res, inputSize, outputShape, config3) {
|
||||
async function process3(res, inputSize2, outputShape, config3) {
|
||||
let id = 0;
|
||||
let results = [];
|
||||
for (const strideSize of [1, 2, 4]) {
|
||||
|
@ -69863,7 +69884,7 @@ async function process3(res, inputSize, outputShape, config3) {
|
|||
if (score3 > config3.object.minConfidence && j !== 61) {
|
||||
const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize;
|
||||
const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize;
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize));
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize2));
|
||||
const [x, y] = [
|
||||
cx - scaleBox / strideSize * boxOffset[0],
|
||||
cy - scaleBox / strideSize * boxOffset[1]
|
||||
|
@ -69933,24 +69954,25 @@ async function predict9(image7, config3) {
|
|||
|
||||
// src/object/centernet.ts
|
||||
var model9;
|
||||
var inputSize = 0;
|
||||
var last4 = [];
|
||||
var skipped6 = Number.MAX_SAFE_INTEGER;
|
||||
async function load11(config3) {
|
||||
if (env2.initial)
|
||||
model9 = null;
|
||||
if (!model9) {
|
||||
model9 = await loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model9.modelSignature["inputs"]);
|
||||
model9.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
if (!model9.inputSize)
|
||||
throw new Error(`Human: Cannot determine model inputSize: ${config3.object.modelPath}`);
|
||||
if (!model9 || !model9.modelUrl)
|
||||
inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
|
||||
if (!model9 || !model9["modelUrl"])
|
||||
log("load model failed:", config3.object.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model9.modelUrl);
|
||||
log("load model:", model9["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model9.modelUrl);
|
||||
log("cached model:", model9["modelUrl"]);
|
||||
return model9;
|
||||
}
|
||||
async function process4(res, inputSize, outputShape, config3) {
|
||||
async function process4(res, outputShape, config3) {
|
||||
if (!res)
|
||||
return [];
|
||||
const results = [];
|
||||
|
@ -70006,10 +70028,10 @@ async function predict10(input2, config3) {
|
|||
return last4;
|
||||
return new Promise(async (resolve) => {
|
||||
const outputSize = [input2.shape[2], input2.shape[1]];
|
||||
const resize = image.resizeBilinear(input2, [model9.inputSize, model9.inputSize]);
|
||||
const objectT = config3.object.enabled ? model9.execute(resize, ["tower_0/detections"]) : null;
|
||||
const resize = image.resizeBilinear(input2, [inputSize, inputSize]);
|
||||
const objectT = config3.object.enabled ? model9 == null ? void 0 : model9.execute(resize, ["tower_0/detections"]) : null;
|
||||
dispose(resize);
|
||||
const obj = await process4(objectT, model9.inputSize, outputSize, config3);
|
||||
const obj = await process4(objectT, outputSize, config3);
|
||||
last4 = obj;
|
||||
resolve(obj);
|
||||
});
|
||||
|
@ -70019,7 +70041,7 @@ async function predict10(input2, config3) {
|
|||
var model10;
|
||||
var busy = false;
|
||||
async function load12(config3) {
|
||||
if (!model10) {
|
||||
if (!model10 || env2.initial) {
|
||||
model10 = await loadGraphModel(join(config3.modelBasePath, config3.segmentation.modelPath || ""));
|
||||
if (!model10 || !model10["modelUrl"])
|
||||
log("load model failed:", config3.segmentation.modelPath);
|
||||
|
@ -70131,7 +70153,27 @@ async function process5(input2, background, config3) {
|
|||
}
|
||||
|
||||
// src/models.ts
|
||||
function reset(instance) {
|
||||
instance.models = {
|
||||
face: null,
|
||||
handpose: null,
|
||||
posenet: null,
|
||||
blazepose: null,
|
||||
efficientpose: null,
|
||||
movenet: null,
|
||||
age: null,
|
||||
gender: null,
|
||||
emotion: null,
|
||||
embedding: null,
|
||||
nanodet: null,
|
||||
centernet: null,
|
||||
faceres: null,
|
||||
segmentation: null
|
||||
};
|
||||
}
|
||||
async function load13(instance) {
|
||||
if (env2.initial)
|
||||
reset(instance);
|
||||
if (instance.config.async) {
|
||||
[
|
||||
instance.models.face,
|
||||
|
@ -70187,20 +70229,28 @@ async function validate(instance) {
|
|||
const simpleOps = ["const", "placeholder", "noop", "pad", "squeeze", "add", "sub", "mul", "div"];
|
||||
for (const defined of Object.keys(instance.models)) {
|
||||
if (instance.models[defined]) {
|
||||
let models2 = [];
|
||||
let models3 = [];
|
||||
if (Array.isArray(instance.models[defined]))
|
||||
models2 = instance.models[defined].map((model11) => model11.executor ? model11 : model11.model);
|
||||
models3 = instance.models[defined].map((model11) => model11 && model11.executor ? model11 : model11.model);
|
||||
else
|
||||
models2 = [instance.models[defined]];
|
||||
for (const model11 of models2) {
|
||||
models3 = [instance.models[defined]];
|
||||
for (const model11 of models3) {
|
||||
if (!model11) {
|
||||
if (instance.config.debug)
|
||||
log("model marked as loaded but not defined:", defined);
|
||||
continue;
|
||||
}
|
||||
const ops = [];
|
||||
const executor = model11 == null ? void 0 : model11.executor;
|
||||
if (executor) {
|
||||
if (executor && executor.graph.nodes) {
|
||||
for (const kernel of Object.values(executor.graph.nodes)) {
|
||||
const op2 = kernel.op.toLowerCase();
|
||||
if (!ops.includes(op2))
|
||||
ops.push(op2);
|
||||
}
|
||||
} else {
|
||||
if (!executor && instance.config.debug)
|
||||
log("model signature not determined:", defined);
|
||||
}
|
||||
const missing = [];
|
||||
for (const op2 of ops) {
|
||||
|
@ -70208,8 +70258,6 @@ async function validate(instance) {
|
|||
missing.push(op2);
|
||||
}
|
||||
}
|
||||
if (!executor && instance.config.debug)
|
||||
log("model executor not found:", defined);
|
||||
if (missing.length > 0 && instance.config.debug)
|
||||
log("model validation:", defined, missing);
|
||||
}
|
||||
|
@ -71160,11 +71208,9 @@ function calc(newResult) {
|
|||
// src/tfjs/humangl.ts
|
||||
var config2 = {
|
||||
name: "humangl",
|
||||
priority: 99,
|
||||
priority: 999,
|
||||
canvas: null,
|
||||
gl: null,
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
extensions: [],
|
||||
webGLattr: {
|
||||
alpha: false,
|
||||
|
@ -71183,27 +71229,58 @@ function extensions() {
|
|||
return;
|
||||
config2.extensions = gl.getSupportedExtensions();
|
||||
}
|
||||
function register() {
|
||||
async function register(instance) {
|
||||
var _a;
|
||||
if (config2.name in engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) {
|
||||
log("error: humangl backend invalid context");
|
||||
log("resetting humangl backend");
|
||||
reset(instance);
|
||||
await removeBackend(config2.name);
|
||||
await register(instance);
|
||||
}
|
||||
if (!findBackend(config2.name)) {
|
||||
try {
|
||||
config2.canvas = canvas(100, 100);
|
||||
config2.canvas = await canvas(100, 100);
|
||||
} catch (err) {
|
||||
log("error: cannot create canvas:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config2.gl = (_a = config2.canvas) == null ? void 0 : _a.getContext("webgl2", config2.webGLattr);
|
||||
if (config2.canvas) {
|
||||
config2.canvas.addEventListener("webglcontextlost", async (e) => {
|
||||
var _a2;
|
||||
const err = (_a2 = config2.gl) == null ? void 0 : _a2.getError();
|
||||
log("error: humangl context lost:", err, e);
|
||||
log("gpu memory usage:", instance.tf.engine().backendInstance.numBytesInGPU);
|
||||
log("resetting humangl backend");
|
||||
env2.initial = true;
|
||||
reset(instance);
|
||||
await removeBackend(config2.name);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextrestored", (e) => {
|
||||
log("error: humangl context restored:", e);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextcreationerror", (e) => {
|
||||
log("error: humangl context create:", e);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
log("error: cannot get WebGL2 context:", err);
|
||||
log("error: cannot get WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
setWebGLContext(2, config2.gl);
|
||||
} catch (err) {
|
||||
log("error: cannot set WebGL2 context:", err);
|
||||
log("error: cannot set WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
const current = backend().getGPGPUContext().gl;
|
||||
if (current) {
|
||||
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);
|
||||
} else {
|
||||
log("error: no current context:", current, config2.gl);
|
||||
}
|
||||
try {
|
||||
const ctx = new GPGPUContext(config2.gl);
|
||||
registerBackend(config2.name, () => new MathBackendWebGL(ctx), config2.priority);
|
||||
|
@ -71234,19 +71311,22 @@ function register() {
|
|||
|
||||
// src/tfjs/backend.ts
|
||||
async function check(instance) {
|
||||
if (instance.initial || instance.config.backend && instance.config.backend.length > 0 && getBackend() !== instance.config.backend) {
|
||||
if (env2.initial || instance.config.backend && instance.config.backend.length > 0 && getBackend() !== instance.config.backend) {
|
||||
const timeStamp = now();
|
||||
instance.state = "backend";
|
||||
if (instance.config.backend && instance.config.backend.length > 0) {
|
||||
if (typeof window === "undefined" && typeof WorkerGlobalScope !== "undefined" && instance.config.debug) {
|
||||
log("running inside web worker");
|
||||
if (instance.config.debug)
|
||||
log("running inside web worker");
|
||||
}
|
||||
if (env2.browser && instance.config.backend === "tensorflow") {
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
if (instance.config.debug)
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
instance.config.backend = "humangl";
|
||||
}
|
||||
if (env2.node && (instance.config.backend === "webgl" || instance.config.backend === "humangl")) {
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
if (instance.config.debug)
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
instance.config.backend = "tensorflow";
|
||||
}
|
||||
if (env2.browser && instance.config.backend === "webgpu") {
|
||||
|
@ -71260,14 +71340,15 @@ async function check(instance) {
|
|||
}
|
||||
}
|
||||
if (instance.config.backend === "humangl")
|
||||
register();
|
||||
await register(instance);
|
||||
const available = Object.keys(engine().registryFactory);
|
||||
if (instance.config.debug)
|
||||
log("available backends:", available);
|
||||
if (!available.includes(instance.config.backend)) {
|
||||
log(`error: backend ${instance.config.backend} not found in registry`);
|
||||
instance.config.backend = env2.node ? "tensorflow" : "humangl";
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
if (instance.config.debug)
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
}
|
||||
if (instance.config.debug)
|
||||
log("setting backend:", instance.config.backend);
|
||||
|
@ -71293,6 +71374,7 @@ async function check(instance) {
|
|||
log("error: cannot set backend:", instance.config.backend, err);
|
||||
}
|
||||
}
|
||||
ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 0);
|
||||
if (getBackend() === "humangl") {
|
||||
ENV.set("CHECK_COMPUTATION_FOR_ERRORS", false);
|
||||
ENV.set("WEBGL_CPU_FORWARD", true);
|
||||
|
@ -72163,7 +72245,7 @@ var Human = class {
|
|||
__privateAdd(this, _numTensors, void 0);
|
||||
__privateAdd(this, _analyzeMemoryLeaks, void 0);
|
||||
__privateAdd(this, _checkSanity, void 0);
|
||||
__publicField(this, "initial");
|
||||
__publicField(this, "gl");
|
||||
__publicField(this, "analyze", (...msg) => {
|
||||
if (!__privateGet(this, _analyzeMemoryLeaks))
|
||||
return;
|
||||
|
@ -72206,7 +72288,6 @@ var Human = class {
|
|||
__privateSet(this, _numTensors, 0);
|
||||
__privateSet(this, _analyzeMemoryLeaks, false);
|
||||
__privateSet(this, _checkSanity, false);
|
||||
this.initial = true;
|
||||
this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };
|
||||
this.events = new EventTarget();
|
||||
this.models = {
|
||||
|
@ -72240,6 +72321,7 @@ var Human = class {
|
|||
this.process = { tensor: null, canvas: null };
|
||||
this.faceTriangulation = triangulation;
|
||||
this.faceUVMap = uvmap;
|
||||
this.gl = config2;
|
||||
this.emit("create");
|
||||
}
|
||||
similarity(embedding1, embedding2) {
|
||||
|
@ -72260,7 +72342,7 @@ var Human = class {
|
|||
const count3 = Object.values(this.models).filter((model11) => model11).length;
|
||||
if (userConfig)
|
||||
this.config = mergeDeep(this.config, userConfig);
|
||||
if (this.initial) {
|
||||
if (env2.initial) {
|
||||
if (this.config.debug)
|
||||
log(`version: ${this.version}`);
|
||||
if (this.config.debug)
|
||||
|
@ -72275,9 +72357,9 @@ var Human = class {
|
|||
}
|
||||
}
|
||||
await load13(this);
|
||||
if (this.initial && this.config.debug)
|
||||
if (env2.initial && this.config.debug)
|
||||
log("tf engine state:", this.tf.engine().state.numBytes, "bytes", this.tf.engine().state.numTensors, "tensors");
|
||||
this.initial = false;
|
||||
env2.initial = false;
|
||||
const loaded = Object.values(this.models).filter((model11) => model11).length;
|
||||
if (loaded !== count3) {
|
||||
await validate(this);
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -365,13 +365,13 @@ function rotatePoint(homogeneousCoordinate, rotationMatrix) {
|
|||
dot(homogeneousCoordinate, rotationMatrix[1])
|
||||
];
|
||||
}
|
||||
function generateAnchors(inputSize) {
|
||||
const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };
|
||||
function generateAnchors(inputSize2) {
|
||||
const spec = { strides: [inputSize2 / 16, inputSize2 / 8], anchors: [2, 6] };
|
||||
const anchors3 = [];
|
||||
for (let i = 0; i < spec.strides.length; i++) {
|
||||
const stride = spec.strides[i];
|
||||
const gridRows = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridRows = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const anchorsNum = spec.anchors[i];
|
||||
for (let gridY = 0; gridY < gridRows; gridY++) {
|
||||
const anchorY = stride * (gridY + 0.5);
|
||||
|
@ -388,17 +388,17 @@ function generateAnchors(inputSize) {
|
|||
|
||||
// src/blazeface/blazeface.ts
|
||||
var keypointsCount = 6;
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize) {
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize2) {
|
||||
const boxStarts = tf2.slice(boxOutputs, [0, 1], [-1, 2]);
|
||||
const centers = tf2.add(boxStarts, anchors3);
|
||||
const boxSizes = tf2.slice(boxOutputs, [0, 3], [-1, 2]);
|
||||
const boxSizesNormalized = tf2.div(boxSizes, inputSize);
|
||||
const centersNormalized = tf2.div(centers, inputSize);
|
||||
const boxSizesNormalized = tf2.div(boxSizes, inputSize2);
|
||||
const centersNormalized = tf2.div(centers, inputSize2);
|
||||
const halfBoxSize = tf2.div(boxSizesNormalized, 2);
|
||||
const starts = tf2.sub(centersNormalized, halfBoxSize);
|
||||
const ends = tf2.add(centersNormalized, halfBoxSize);
|
||||
const startNormalized = tf2.mul(starts, inputSize);
|
||||
const endNormalized = tf2.mul(ends, inputSize);
|
||||
const startNormalized = tf2.mul(starts, inputSize2);
|
||||
const endNormalized = tf2.mul(ends, inputSize2);
|
||||
const concatAxis = 1;
|
||||
return tf2.concat2d([startNormalized, endNormalized], concatAxis);
|
||||
}
|
||||
|
@ -4596,9 +4596,13 @@ function process2(input, config3) {
|
|||
pixels = tf3.browser && env.browser ? tf3.browser.fromPixels(tempCanvas) : null;
|
||||
} else {
|
||||
const tempCanvas = canvas(targetWidth, targetHeight);
|
||||
if (!tempCanvas)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
if (!tempCtx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCtx.drawImage(outCanvas, 0, 0);
|
||||
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
if (tf3.browser && env.browser) {
|
||||
|
@ -4654,6 +4658,7 @@ var env = {
|
|||
worker: void 0,
|
||||
platform: void 0,
|
||||
agent: void 0,
|
||||
initial: true,
|
||||
backends: [],
|
||||
tfjs: {
|
||||
version: void 0
|
||||
|
@ -5058,7 +5063,9 @@ async function predict(input, config3) {
|
|||
return results;
|
||||
}
|
||||
async function load2(config3) {
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled) {
|
||||
if (env.initial)
|
||||
faceModels = [null, null, null];
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled || env.initial) {
|
||||
faceModels = await Promise.all([
|
||||
!faceModels[0] && config3.face.enabled ? load(config3) : null,
|
||||
!faceModels[1] && config3.face.mesh.enabled ? tf6.loadGraphModel(join(config3.modelBasePath, config3.face.mesh.modelPath), { fromTFHub: config3.face.mesh.modelPath.includes("tfhub.dev") }) : null,
|
||||
|
@ -5099,6 +5106,8 @@ var skipped = Number.MAX_SAFE_INTEGER;
|
|||
async function load3(config3) {
|
||||
var _a, _b;
|
||||
const modelUrl = join(config3.modelBasePath, ((_a = config3.face.description) == null ? void 0 : _a.modelPath) || "");
|
||||
if (env.initial)
|
||||
model = null;
|
||||
if (!model) {
|
||||
model = await tf7.loadGraphModel(modelUrl);
|
||||
if (!model)
|
||||
|
@ -5139,7 +5148,7 @@ function enhance(input) {
|
|||
if (!(tensor3 instanceof tf7.Tensor))
|
||||
return null;
|
||||
const box6 = [[0.05, 0.15, 0.85, 0.85]];
|
||||
if (!model.inputs[0].shape)
|
||||
if (!(model == null ? void 0 : model.inputs[0].shape))
|
||||
return null;
|
||||
const crop = tensor3.shape.length === 3 ? tf7.image.cropAndResize(tf7.expandDims(tensor3, 0), box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) : tf7.image.cropAndResize(tensor3, box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
|
||||
const norm = tf7.mul(crop, 255);
|
||||
|
@ -5167,7 +5176,7 @@ async function predict2(image22, config3, idx, count2) {
|
|||
descriptor: []
|
||||
};
|
||||
if ((_a2 = config3.face.description) == null ? void 0 : _a2.enabled)
|
||||
resT = await model.predict(enhanced);
|
||||
resT = await (model == null ? void 0 : model.predict(enhanced));
|
||||
tf7.dispose(enhanced);
|
||||
if (resT) {
|
||||
const gender = await resT.find((t) => t.shape[1] === 1).data();
|
||||
|
@ -5201,15 +5210,17 @@ var lastCount2 = 0;
|
|||
var skipped2 = Number.MAX_SAFE_INTEGER;
|
||||
var rgb = [0.2989, 0.587, 0.114];
|
||||
async function load4(config3) {
|
||||
var _a, _b;
|
||||
var _a;
|
||||
if (env.initial)
|
||||
model2 = null;
|
||||
if (!model2) {
|
||||
model2 = await tf8.loadGraphModel(join(config3.modelBasePath, ((_a = config3.face.emotion) == null ? void 0 : _a.modelPath) || ""));
|
||||
if (!model2 || !model2.modelUrl)
|
||||
log("load model failed:", ((_b = config3.face.emotion) == null ? void 0 : _b.modelPath) || "");
|
||||
if (!model2 || !model2["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model2.modelUrl);
|
||||
log("load model:", model2["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model2.modelUrl);
|
||||
log("cached model:", model2["modelUrl"]);
|
||||
return model2;
|
||||
}
|
||||
async function predict3(image22, config3, idx, count2) {
|
||||
|
@ -5223,7 +5234,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
skipped2 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
var _a2, _b;
|
||||
const resize = tf8.image.resizeBilinear(image22, [model2.inputs[0].shape[2], model2.inputs[0].shape[1]], false);
|
||||
const resize = tf8.image.resizeBilinear(image22, [(model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[2] : 0, (model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[1] : 0], false);
|
||||
const [red, green, blue] = tf8.split(resize, 3, 3);
|
||||
tf8.dispose(resize);
|
||||
const redNorm = tf8.mul(red, rgb[0]);
|
||||
|
@ -5240,7 +5251,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
tf8.dispose(grayscale);
|
||||
const obj = [];
|
||||
if ((_a2 = config3.face.emotion) == null ? void 0 : _a2.enabled) {
|
||||
const emotionT = await model2.predict(normalize);
|
||||
const emotionT = await (model2 == null ? void 0 : model2.predict(normalize));
|
||||
const data = await emotionT.data();
|
||||
tf8.dispose(emotionT);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
@ -5592,7 +5603,7 @@ async function predict4(input, config3) {
|
|||
return scaled;
|
||||
}
|
||||
async function load5(config3) {
|
||||
if (!model3) {
|
||||
if (!model3 || env.initial) {
|
||||
model3 = await tf9.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model3 || !model3["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
|
@ -9332,6 +9343,10 @@ async function predict5(input, config3) {
|
|||
}
|
||||
async function load6(config3) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
if (env.initial) {
|
||||
handDetectorModel = null;
|
||||
handPoseModel = null;
|
||||
}
|
||||
if (!handDetectorModel || !handPoseModel) {
|
||||
[handDetectorModel, handPoseModel] = await Promise.all([
|
||||
config3.hand.enabled ? tf13.loadGraphModel(join(config3.modelBasePath, ((_a = config3.hand.detector) == null ? void 0 : _a.modelPath) || ""), { fromTFHub: (((_b = config3.hand.detector) == null ? void 0 : _b.modelPath) || "").includes("tfhub.dev") }) : null,
|
||||
|
@ -9440,6 +9455,8 @@ var upper = [
|
|||
// src/blazepose/blazepose.ts
|
||||
var model4;
|
||||
async function load7(config3) {
|
||||
if (env.initial)
|
||||
model4 = null;
|
||||
if (!model4) {
|
||||
model4 = await tf14.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
model4["width"] = parseInt(model4["signature"].inputs["input_1:0"].tensorShape.dim[2].size);
|
||||
|
@ -9510,6 +9527,8 @@ var score = 0;
|
|||
var skipped3 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts = ["head", "neck", "rightShoulder", "rightElbow", "rightWrist", "chest", "leftShoulder", "leftElbow", "leftWrist", "pelvis", "rightHip", "rightKnee", "rightAnkle", "leftHip", "leftKnee", "leftAnkle"];
|
||||
async function load8(config3) {
|
||||
if (env.initial)
|
||||
model5 = null;
|
||||
if (!model5) {
|
||||
model5 = await tf15.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model5 || !model5["modelUrl"])
|
||||
|
@ -9545,7 +9564,7 @@ async function predict7(image22, config3) {
|
|||
return new Promise(async (resolve) => {
|
||||
var _a2;
|
||||
const tensor3 = tf15.tidy(() => {
|
||||
if (!model5.inputs[0].shape)
|
||||
if (!(model5 == null ? void 0 : model5.inputs[0].shape))
|
||||
return null;
|
||||
const resize = tf15.image.resizeBilinear(image22, [model5.inputs[0].shape[2], model5.inputs[0].shape[1]], false);
|
||||
const enhance2 = tf15.mul(resize, 2);
|
||||
|
@ -9554,7 +9573,7 @@ async function predict7(image22, config3) {
|
|||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model5.predict(tensor3);
|
||||
resT = await (model5 == null ? void 0 : model5.predict(tensor3));
|
||||
tf15.dispose(tensor3);
|
||||
if (resT) {
|
||||
keypoints.length = 0;
|
||||
|
@ -9612,6 +9631,8 @@ var score2 = 0;
|
|||
var skipped4 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts2 = ["nose", "leftEye", "rightEye", "leftEar", "rightEar", "leftShoulder", "rightShoulder", "leftElbow", "rightElbow", "leftWrist", "rightWrist", "leftHip", "rightHip", "leftKnee", "rightKnee", "leftAnkle", "rightAnkle"];
|
||||
async function load9(config3) {
|
||||
if (env.initial)
|
||||
model6 = null;
|
||||
if (!model6) {
|
||||
model6 = await tf16.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model6 || !model6["modelUrl"])
|
||||
|
@ -9712,18 +9733,18 @@ async function predict8(image22, config3) {
|
|||
skipped4 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor3 = tf16.tidy(() => {
|
||||
if (!model6.inputs[0].shape)
|
||||
if (!(model6 == null ? void 0 : model6.inputs[0].shape))
|
||||
return null;
|
||||
let inputSize = model6.inputs[0].shape[2];
|
||||
if (inputSize === -1)
|
||||
inputSize = 256;
|
||||
const resize = tf16.image.resizeBilinear(image22, [inputSize, inputSize], false);
|
||||
let inputSize2 = model6.inputs[0].shape[2];
|
||||
if (inputSize2 === -1)
|
||||
inputSize2 = 256;
|
||||
const resize = tf16.image.resizeBilinear(image22, [inputSize2, inputSize2], false);
|
||||
const cast4 = tf16.cast(resize, "int32");
|
||||
return cast4;
|
||||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model6.predict(tensor3);
|
||||
resT = await (model6 == null ? void 0 : model6.predict(tensor3));
|
||||
tf16.dispose(tensor3);
|
||||
if (!resT)
|
||||
resolve([]);
|
||||
|
@ -9831,7 +9852,7 @@ var last3 = [];
|
|||
var skipped5 = Number.MAX_SAFE_INTEGER;
|
||||
var scaleBox = 2.5;
|
||||
async function load10(config3) {
|
||||
if (!model7) {
|
||||
if (!model7 || env.initial) {
|
||||
model7 = await tf17.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model7.modelSignature["inputs"]);
|
||||
model7.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
|
@ -9845,7 +9866,7 @@ async function load10(config3) {
|
|||
log("cached model:", model7.modelUrl);
|
||||
return model7;
|
||||
}
|
||||
async function process3(res, inputSize, outputShape, config3) {
|
||||
async function process3(res, inputSize2, outputShape, config3) {
|
||||
let id = 0;
|
||||
let results = [];
|
||||
for (const strideSize of [1, 2, 4]) {
|
||||
|
@ -9863,7 +9884,7 @@ async function process3(res, inputSize, outputShape, config3) {
|
|||
if (score3 > config3.object.minConfidence && j !== 61) {
|
||||
const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize;
|
||||
const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize;
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize));
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize2));
|
||||
const [x, y] = [
|
||||
cx - scaleBox / strideSize * boxOffset[0],
|
||||
cy - scaleBox / strideSize * boxOffset[1]
|
||||
|
@ -9934,24 +9955,25 @@ async function predict9(image22, config3) {
|
|||
// src/object/centernet.ts
|
||||
var tf18 = __toModule(require_tfjs_esm());
|
||||
var model8;
|
||||
var inputSize = 0;
|
||||
var last4 = [];
|
||||
var skipped6 = Number.MAX_SAFE_INTEGER;
|
||||
async function load11(config3) {
|
||||
if (env.initial)
|
||||
model8 = null;
|
||||
if (!model8) {
|
||||
model8 = await tf18.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model8.modelSignature["inputs"]);
|
||||
model8.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
if (!model8.inputSize)
|
||||
throw new Error(`Human: Cannot determine model inputSize: ${config3.object.modelPath}`);
|
||||
if (!model8 || !model8.modelUrl)
|
||||
inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
|
||||
if (!model8 || !model8["modelUrl"])
|
||||
log("load model failed:", config3.object.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model8.modelUrl);
|
||||
log("load model:", model8["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model8.modelUrl);
|
||||
log("cached model:", model8["modelUrl"]);
|
||||
return model8;
|
||||
}
|
||||
async function process4(res, inputSize, outputShape, config3) {
|
||||
async function process4(res, outputShape, config3) {
|
||||
if (!res)
|
||||
return [];
|
||||
const results = [];
|
||||
|
@ -10007,10 +10029,10 @@ async function predict10(input, config3) {
|
|||
return last4;
|
||||
return new Promise(async (resolve) => {
|
||||
const outputSize = [input.shape[2], input.shape[1]];
|
||||
const resize = tf18.image.resizeBilinear(input, [model8.inputSize, model8.inputSize]);
|
||||
const objectT = config3.object.enabled ? model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
const resize = tf18.image.resizeBilinear(input, [inputSize, inputSize]);
|
||||
const objectT = config3.object.enabled ? model8 == null ? void 0 : model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
tf18.dispose(resize);
|
||||
const obj = await process4(objectT, model8.inputSize, outputSize, config3);
|
||||
const obj = await process4(objectT, outputSize, config3);
|
||||
last4 = obj;
|
||||
resolve(obj);
|
||||
});
|
||||
|
@ -10021,7 +10043,7 @@ var tf19 = __toModule(require_tfjs_esm());
|
|||
var model9;
|
||||
var busy = false;
|
||||
async function load12(config3) {
|
||||
if (!model9) {
|
||||
if (!model9 || env.initial) {
|
||||
model9 = await tf19.loadGraphModel(join(config3.modelBasePath, config3.segmentation.modelPath || ""));
|
||||
if (!model9 || !model9["modelUrl"])
|
||||
log("load model failed:", config3.segmentation.modelPath);
|
||||
|
@ -10133,7 +10155,27 @@ async function process5(input, background, config3) {
|
|||
}
|
||||
|
||||
// src/models.ts
|
||||
function reset(instance) {
|
||||
instance.models = {
|
||||
face: null,
|
||||
handpose: null,
|
||||
posenet: null,
|
||||
blazepose: null,
|
||||
efficientpose: null,
|
||||
movenet: null,
|
||||
age: null,
|
||||
gender: null,
|
||||
emotion: null,
|
||||
embedding: null,
|
||||
nanodet: null,
|
||||
centernet: null,
|
||||
faceres: null,
|
||||
segmentation: null
|
||||
};
|
||||
}
|
||||
async function load13(instance) {
|
||||
if (env.initial)
|
||||
reset(instance);
|
||||
if (instance.config.async) {
|
||||
[
|
||||
instance.models.face,
|
||||
|
@ -10189,20 +10231,28 @@ async function validate(instance) {
|
|||
const simpleOps = ["const", "placeholder", "noop", "pad", "squeeze", "add", "sub", "mul", "div"];
|
||||
for (const defined of Object.keys(instance.models)) {
|
||||
if (instance.models[defined]) {
|
||||
let models2 = [];
|
||||
let models3 = [];
|
||||
if (Array.isArray(instance.models[defined]))
|
||||
models2 = instance.models[defined].map((model10) => model10.executor ? model10 : model10.model);
|
||||
models3 = instance.models[defined].map((model10) => model10 && model10.executor ? model10 : model10.model);
|
||||
else
|
||||
models2 = [instance.models[defined]];
|
||||
for (const model10 of models2) {
|
||||
models3 = [instance.models[defined]];
|
||||
for (const model10 of models3) {
|
||||
if (!model10) {
|
||||
if (instance.config.debug)
|
||||
log("model marked as loaded but not defined:", defined);
|
||||
continue;
|
||||
}
|
||||
const ops = [];
|
||||
const executor = model10 == null ? void 0 : model10.executor;
|
||||
if (executor) {
|
||||
if (executor && executor.graph.nodes) {
|
||||
for (const kernel of Object.values(executor.graph.nodes)) {
|
||||
const op = kernel.op.toLowerCase();
|
||||
if (!ops.includes(op))
|
||||
ops.push(op);
|
||||
}
|
||||
} else {
|
||||
if (!executor && instance.config.debug)
|
||||
log("model signature not determined:", defined);
|
||||
}
|
||||
const missing = [];
|
||||
for (const op of ops) {
|
||||
|
@ -10210,8 +10260,6 @@ async function validate(instance) {
|
|||
missing.push(op);
|
||||
}
|
||||
}
|
||||
if (!executor && instance.config.debug)
|
||||
log("model executor not found:", defined);
|
||||
if (missing.length > 0 && instance.config.debug)
|
||||
log("model validation:", defined, missing);
|
||||
}
|
||||
|
@ -11164,11 +11212,9 @@ function calc(newResult) {
|
|||
var tf21 = __toModule(require_tfjs_esm());
|
||||
var config2 = {
|
||||
name: "humangl",
|
||||
priority: 99,
|
||||
priority: 999,
|
||||
canvas: null,
|
||||
gl: null,
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
extensions: [],
|
||||
webGLattr: {
|
||||
alpha: false,
|
||||
|
@ -11187,27 +11233,58 @@ function extensions() {
|
|||
return;
|
||||
config2.extensions = gl.getSupportedExtensions();
|
||||
}
|
||||
function register() {
|
||||
async function register(instance) {
|
||||
var _a;
|
||||
if (config2.name in tf21.engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) {
|
||||
log("error: humangl backend invalid context");
|
||||
log("resetting humangl backend");
|
||||
reset(instance);
|
||||
await tf21.removeBackend(config2.name);
|
||||
await register(instance);
|
||||
}
|
||||
if (!tf21.findBackend(config2.name)) {
|
||||
try {
|
||||
config2.canvas = canvas(100, 100);
|
||||
config2.canvas = await canvas(100, 100);
|
||||
} catch (err) {
|
||||
log("error: cannot create canvas:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config2.gl = (_a = config2.canvas) == null ? void 0 : _a.getContext("webgl2", config2.webGLattr);
|
||||
if (config2.canvas) {
|
||||
config2.canvas.addEventListener("webglcontextlost", async (e) => {
|
||||
var _a2;
|
||||
const err = (_a2 = config2.gl) == null ? void 0 : _a2.getError();
|
||||
log("error: humangl context lost:", err, e);
|
||||
log("gpu memory usage:", instance.tf.engine().backendInstance.numBytesInGPU);
|
||||
log("resetting humangl backend");
|
||||
env.initial = true;
|
||||
reset(instance);
|
||||
await tf21.removeBackend(config2.name);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextrestored", (e) => {
|
||||
log("error: humangl context restored:", e);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextcreationerror", (e) => {
|
||||
log("error: humangl context create:", e);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
log("error: cannot get WebGL2 context:", err);
|
||||
log("error: cannot get WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
tf21.setWebGLContext(2, config2.gl);
|
||||
} catch (err) {
|
||||
log("error: cannot set WebGL2 context:", err);
|
||||
log("error: cannot set WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
const current = tf21.backend().getGPGPUContext().gl;
|
||||
if (current) {
|
||||
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);
|
||||
} else {
|
||||
log("error: no current context:", current, config2.gl);
|
||||
}
|
||||
try {
|
||||
const ctx = new tf21.GPGPUContext(config2.gl);
|
||||
tf21.registerBackend(config2.name, () => new tf21.MathBackendWebGL(ctx), config2.priority);
|
||||
|
@ -11239,19 +11316,22 @@ function register() {
|
|||
// src/tfjs/backend.ts
|
||||
var tf22 = __toModule(require_tfjs_esm());
|
||||
async function check(instance) {
|
||||
if (instance.initial || instance.config.backend && instance.config.backend.length > 0 && tf22.getBackend() !== instance.config.backend) {
|
||||
if (env.initial || instance.config.backend && instance.config.backend.length > 0 && tf22.getBackend() !== instance.config.backend) {
|
||||
const timeStamp = now();
|
||||
instance.state = "backend";
|
||||
if (instance.config.backend && instance.config.backend.length > 0) {
|
||||
if (typeof window === "undefined" && typeof WorkerGlobalScope !== "undefined" && instance.config.debug) {
|
||||
log("running inside web worker");
|
||||
if (instance.config.debug)
|
||||
log("running inside web worker");
|
||||
}
|
||||
if (env.browser && instance.config.backend === "tensorflow") {
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
if (instance.config.debug)
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
instance.config.backend = "humangl";
|
||||
}
|
||||
if (env.node && (instance.config.backend === "webgl" || instance.config.backend === "humangl")) {
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
if (instance.config.debug)
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
instance.config.backend = "tensorflow";
|
||||
}
|
||||
if (env.browser && instance.config.backend === "webgpu") {
|
||||
|
@ -11265,14 +11345,15 @@ async function check(instance) {
|
|||
}
|
||||
}
|
||||
if (instance.config.backend === "humangl")
|
||||
register();
|
||||
await register(instance);
|
||||
const available = Object.keys(tf22.engine().registryFactory);
|
||||
if (instance.config.debug)
|
||||
log("available backends:", available);
|
||||
if (!available.includes(instance.config.backend)) {
|
||||
log(`error: backend ${instance.config.backend} not found in registry`);
|
||||
instance.config.backend = env.node ? "tensorflow" : "humangl";
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
if (instance.config.debug)
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
}
|
||||
if (instance.config.debug)
|
||||
log("setting backend:", instance.config.backend);
|
||||
|
@ -11298,6 +11379,7 @@ async function check(instance) {
|
|||
log("error: cannot set backend:", instance.config.backend, err);
|
||||
}
|
||||
}
|
||||
tf22.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 0);
|
||||
if (tf22.getBackend() === "humangl") {
|
||||
tf22.ENV.set("CHECK_COMPUTATION_FOR_ERRORS", false);
|
||||
tf22.ENV.set("WEBGL_CPU_FORWARD", true);
|
||||
|
@ -12169,7 +12251,7 @@ var Human = class {
|
|||
__privateAdd(this, _numTensors, void 0);
|
||||
__privateAdd(this, _analyzeMemoryLeaks, void 0);
|
||||
__privateAdd(this, _checkSanity, void 0);
|
||||
__publicField(this, "initial");
|
||||
__publicField(this, "gl");
|
||||
__publicField(this, "analyze", (...msg) => {
|
||||
if (!__privateGet(this, _analyzeMemoryLeaks))
|
||||
return;
|
||||
|
@ -12212,7 +12294,6 @@ var Human = class {
|
|||
__privateSet(this, _numTensors, 0);
|
||||
__privateSet(this, _analyzeMemoryLeaks, false);
|
||||
__privateSet(this, _checkSanity, false);
|
||||
this.initial = true;
|
||||
this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };
|
||||
this.events = new EventTarget();
|
||||
this.models = {
|
||||
|
@ -12246,6 +12327,7 @@ var Human = class {
|
|||
this.process = { tensor: null, canvas: null };
|
||||
this.faceTriangulation = triangulation;
|
||||
this.faceUVMap = uvmap;
|
||||
this.gl = config2;
|
||||
this.emit("create");
|
||||
}
|
||||
similarity(embedding1, embedding2) {
|
||||
|
@ -12266,7 +12348,7 @@ var Human = class {
|
|||
const count2 = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (userConfig)
|
||||
this.config = mergeDeep(this.config, userConfig);
|
||||
if (this.initial) {
|
||||
if (env.initial) {
|
||||
if (this.config.debug)
|
||||
log(`version: ${this.version}`);
|
||||
if (this.config.debug)
|
||||
|
@ -12281,9 +12363,9 @@ var Human = class {
|
|||
}
|
||||
}
|
||||
await load13(this);
|
||||
if (this.initial && this.config.debug)
|
||||
if (env.initial && this.config.debug)
|
||||
log("tf engine state:", this.tf.engine().state.numBytes, "bytes", this.tf.engine().state.numTensors, "tensors");
|
||||
this.initial = false;
|
||||
env.initial = false;
|
||||
const loaded = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (loaded !== count2) {
|
||||
await validate(this);
|
||||
|
|
|
@ -366,13 +366,13 @@ function rotatePoint(homogeneousCoordinate, rotationMatrix) {
|
|||
dot(homogeneousCoordinate, rotationMatrix[1])
|
||||
];
|
||||
}
|
||||
function generateAnchors(inputSize) {
|
||||
const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };
|
||||
function generateAnchors(inputSize2) {
|
||||
const spec = { strides: [inputSize2 / 16, inputSize2 / 8], anchors: [2, 6] };
|
||||
const anchors3 = [];
|
||||
for (let i = 0; i < spec.strides.length; i++) {
|
||||
const stride = spec.strides[i];
|
||||
const gridRows = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridRows = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const anchorsNum = spec.anchors[i];
|
||||
for (let gridY = 0; gridY < gridRows; gridY++) {
|
||||
const anchorY = stride * (gridY + 0.5);
|
||||
|
@ -389,17 +389,17 @@ function generateAnchors(inputSize) {
|
|||
|
||||
// src/blazeface/blazeface.ts
|
||||
var keypointsCount = 6;
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize) {
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize2) {
|
||||
const boxStarts = tf2.slice(boxOutputs, [0, 1], [-1, 2]);
|
||||
const centers = tf2.add(boxStarts, anchors3);
|
||||
const boxSizes = tf2.slice(boxOutputs, [0, 3], [-1, 2]);
|
||||
const boxSizesNormalized = tf2.div(boxSizes, inputSize);
|
||||
const centersNormalized = tf2.div(centers, inputSize);
|
||||
const boxSizesNormalized = tf2.div(boxSizes, inputSize2);
|
||||
const centersNormalized = tf2.div(centers, inputSize2);
|
||||
const halfBoxSize = tf2.div(boxSizesNormalized, 2);
|
||||
const starts = tf2.sub(centersNormalized, halfBoxSize);
|
||||
const ends = tf2.add(centersNormalized, halfBoxSize);
|
||||
const startNormalized = tf2.mul(starts, inputSize);
|
||||
const endNormalized = tf2.mul(ends, inputSize);
|
||||
const startNormalized = tf2.mul(starts, inputSize2);
|
||||
const endNormalized = tf2.mul(ends, inputSize2);
|
||||
const concatAxis = 1;
|
||||
return tf2.concat2d([startNormalized, endNormalized], concatAxis);
|
||||
}
|
||||
|
@ -4597,9 +4597,13 @@ function process2(input, config3) {
|
|||
pixels = tf3.browser && env.browser ? tf3.browser.fromPixels(tempCanvas) : null;
|
||||
} else {
|
||||
const tempCanvas = canvas(targetWidth, targetHeight);
|
||||
if (!tempCanvas)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
if (!tempCtx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCtx.drawImage(outCanvas, 0, 0);
|
||||
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
if (tf3.browser && env.browser) {
|
||||
|
@ -4655,6 +4659,7 @@ var env = {
|
|||
worker: void 0,
|
||||
platform: void 0,
|
||||
agent: void 0,
|
||||
initial: true,
|
||||
backends: [],
|
||||
tfjs: {
|
||||
version: void 0
|
||||
|
@ -5059,7 +5064,9 @@ async function predict(input, config3) {
|
|||
return results;
|
||||
}
|
||||
async function load2(config3) {
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled) {
|
||||
if (env.initial)
|
||||
faceModels = [null, null, null];
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled || env.initial) {
|
||||
faceModels = await Promise.all([
|
||||
!faceModels[0] && config3.face.enabled ? load(config3) : null,
|
||||
!faceModels[1] && config3.face.mesh.enabled ? tf6.loadGraphModel(join(config3.modelBasePath, config3.face.mesh.modelPath), { fromTFHub: config3.face.mesh.modelPath.includes("tfhub.dev") }) : null,
|
||||
|
@ -5100,6 +5107,8 @@ var skipped = Number.MAX_SAFE_INTEGER;
|
|||
async function load3(config3) {
|
||||
var _a, _b;
|
||||
const modelUrl = join(config3.modelBasePath, ((_a = config3.face.description) == null ? void 0 : _a.modelPath) || "");
|
||||
if (env.initial)
|
||||
model = null;
|
||||
if (!model) {
|
||||
model = await tf7.loadGraphModel(modelUrl);
|
||||
if (!model)
|
||||
|
@ -5140,7 +5149,7 @@ function enhance(input) {
|
|||
if (!(tensor3 instanceof tf7.Tensor))
|
||||
return null;
|
||||
const box6 = [[0.05, 0.15, 0.85, 0.85]];
|
||||
if (!model.inputs[0].shape)
|
||||
if (!(model == null ? void 0 : model.inputs[0].shape))
|
||||
return null;
|
||||
const crop = tensor3.shape.length === 3 ? tf7.image.cropAndResize(tf7.expandDims(tensor3, 0), box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) : tf7.image.cropAndResize(tensor3, box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
|
||||
const norm = tf7.mul(crop, 255);
|
||||
|
@ -5168,7 +5177,7 @@ async function predict2(image22, config3, idx, count2) {
|
|||
descriptor: []
|
||||
};
|
||||
if ((_a2 = config3.face.description) == null ? void 0 : _a2.enabled)
|
||||
resT = await model.predict(enhanced);
|
||||
resT = await (model == null ? void 0 : model.predict(enhanced));
|
||||
tf7.dispose(enhanced);
|
||||
if (resT) {
|
||||
const gender = await resT.find((t) => t.shape[1] === 1).data();
|
||||
|
@ -5202,15 +5211,17 @@ var lastCount2 = 0;
|
|||
var skipped2 = Number.MAX_SAFE_INTEGER;
|
||||
var rgb = [0.2989, 0.587, 0.114];
|
||||
async function load4(config3) {
|
||||
var _a, _b;
|
||||
var _a;
|
||||
if (env.initial)
|
||||
model2 = null;
|
||||
if (!model2) {
|
||||
model2 = await tf8.loadGraphModel(join(config3.modelBasePath, ((_a = config3.face.emotion) == null ? void 0 : _a.modelPath) || ""));
|
||||
if (!model2 || !model2.modelUrl)
|
||||
log("load model failed:", ((_b = config3.face.emotion) == null ? void 0 : _b.modelPath) || "");
|
||||
if (!model2 || !model2["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model2.modelUrl);
|
||||
log("load model:", model2["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model2.modelUrl);
|
||||
log("cached model:", model2["modelUrl"]);
|
||||
return model2;
|
||||
}
|
||||
async function predict3(image22, config3, idx, count2) {
|
||||
|
@ -5224,7 +5235,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
skipped2 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
var _a2, _b;
|
||||
const resize = tf8.image.resizeBilinear(image22, [model2.inputs[0].shape[2], model2.inputs[0].shape[1]], false);
|
||||
const resize = tf8.image.resizeBilinear(image22, [(model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[2] : 0, (model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[1] : 0], false);
|
||||
const [red, green, blue] = tf8.split(resize, 3, 3);
|
||||
tf8.dispose(resize);
|
||||
const redNorm = tf8.mul(red, rgb[0]);
|
||||
|
@ -5241,7 +5252,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
tf8.dispose(grayscale);
|
||||
const obj = [];
|
||||
if ((_a2 = config3.face.emotion) == null ? void 0 : _a2.enabled) {
|
||||
const emotionT = await model2.predict(normalize);
|
||||
const emotionT = await (model2 == null ? void 0 : model2.predict(normalize));
|
||||
const data = await emotionT.data();
|
||||
tf8.dispose(emotionT);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
@ -5593,7 +5604,7 @@ async function predict4(input, config3) {
|
|||
return scaled;
|
||||
}
|
||||
async function load5(config3) {
|
||||
if (!model3) {
|
||||
if (!model3 || env.initial) {
|
||||
model3 = await tf9.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model3 || !model3["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
|
@ -9333,6 +9344,10 @@ async function predict5(input, config3) {
|
|||
}
|
||||
async function load6(config3) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
if (env.initial) {
|
||||
handDetectorModel = null;
|
||||
handPoseModel = null;
|
||||
}
|
||||
if (!handDetectorModel || !handPoseModel) {
|
||||
[handDetectorModel, handPoseModel] = await Promise.all([
|
||||
config3.hand.enabled ? tf13.loadGraphModel(join(config3.modelBasePath, ((_a = config3.hand.detector) == null ? void 0 : _a.modelPath) || ""), { fromTFHub: (((_b = config3.hand.detector) == null ? void 0 : _b.modelPath) || "").includes("tfhub.dev") }) : null,
|
||||
|
@ -9441,6 +9456,8 @@ var upper = [
|
|||
// src/blazepose/blazepose.ts
|
||||
var model4;
|
||||
async function load7(config3) {
|
||||
if (env.initial)
|
||||
model4 = null;
|
||||
if (!model4) {
|
||||
model4 = await tf14.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
model4["width"] = parseInt(model4["signature"].inputs["input_1:0"].tensorShape.dim[2].size);
|
||||
|
@ -9511,6 +9528,8 @@ var score = 0;
|
|||
var skipped3 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts = ["head", "neck", "rightShoulder", "rightElbow", "rightWrist", "chest", "leftShoulder", "leftElbow", "leftWrist", "pelvis", "rightHip", "rightKnee", "rightAnkle", "leftHip", "leftKnee", "leftAnkle"];
|
||||
async function load8(config3) {
|
||||
if (env.initial)
|
||||
model5 = null;
|
||||
if (!model5) {
|
||||
model5 = await tf15.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model5 || !model5["modelUrl"])
|
||||
|
@ -9546,7 +9565,7 @@ async function predict7(image22, config3) {
|
|||
return new Promise(async (resolve) => {
|
||||
var _a2;
|
||||
const tensor3 = tf15.tidy(() => {
|
||||
if (!model5.inputs[0].shape)
|
||||
if (!(model5 == null ? void 0 : model5.inputs[0].shape))
|
||||
return null;
|
||||
const resize = tf15.image.resizeBilinear(image22, [model5.inputs[0].shape[2], model5.inputs[0].shape[1]], false);
|
||||
const enhance2 = tf15.mul(resize, 2);
|
||||
|
@ -9555,7 +9574,7 @@ async function predict7(image22, config3) {
|
|||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model5.predict(tensor3);
|
||||
resT = await (model5 == null ? void 0 : model5.predict(tensor3));
|
||||
tf15.dispose(tensor3);
|
||||
if (resT) {
|
||||
keypoints.length = 0;
|
||||
|
@ -9613,6 +9632,8 @@ var score2 = 0;
|
|||
var skipped4 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts2 = ["nose", "leftEye", "rightEye", "leftEar", "rightEar", "leftShoulder", "rightShoulder", "leftElbow", "rightElbow", "leftWrist", "rightWrist", "leftHip", "rightHip", "leftKnee", "rightKnee", "leftAnkle", "rightAnkle"];
|
||||
async function load9(config3) {
|
||||
if (env.initial)
|
||||
model6 = null;
|
||||
if (!model6) {
|
||||
model6 = await tf16.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model6 || !model6["modelUrl"])
|
||||
|
@ -9713,18 +9734,18 @@ async function predict8(image22, config3) {
|
|||
skipped4 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor3 = tf16.tidy(() => {
|
||||
if (!model6.inputs[0].shape)
|
||||
if (!(model6 == null ? void 0 : model6.inputs[0].shape))
|
||||
return null;
|
||||
let inputSize = model6.inputs[0].shape[2];
|
||||
if (inputSize === -1)
|
||||
inputSize = 256;
|
||||
const resize = tf16.image.resizeBilinear(image22, [inputSize, inputSize], false);
|
||||
let inputSize2 = model6.inputs[0].shape[2];
|
||||
if (inputSize2 === -1)
|
||||
inputSize2 = 256;
|
||||
const resize = tf16.image.resizeBilinear(image22, [inputSize2, inputSize2], false);
|
||||
const cast4 = tf16.cast(resize, "int32");
|
||||
return cast4;
|
||||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model6.predict(tensor3);
|
||||
resT = await (model6 == null ? void 0 : model6.predict(tensor3));
|
||||
tf16.dispose(tensor3);
|
||||
if (!resT)
|
||||
resolve([]);
|
||||
|
@ -9832,7 +9853,7 @@ var last3 = [];
|
|||
var skipped5 = Number.MAX_SAFE_INTEGER;
|
||||
var scaleBox = 2.5;
|
||||
async function load10(config3) {
|
||||
if (!model7) {
|
||||
if (!model7 || env.initial) {
|
||||
model7 = await tf17.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model7.modelSignature["inputs"]);
|
||||
model7.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
|
@ -9846,7 +9867,7 @@ async function load10(config3) {
|
|||
log("cached model:", model7.modelUrl);
|
||||
return model7;
|
||||
}
|
||||
async function process3(res, inputSize, outputShape, config3) {
|
||||
async function process3(res, inputSize2, outputShape, config3) {
|
||||
let id = 0;
|
||||
let results = [];
|
||||
for (const strideSize of [1, 2, 4]) {
|
||||
|
@ -9864,7 +9885,7 @@ async function process3(res, inputSize, outputShape, config3) {
|
|||
if (score3 > config3.object.minConfidence && j !== 61) {
|
||||
const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize;
|
||||
const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize;
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize));
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize2));
|
||||
const [x, y] = [
|
||||
cx - scaleBox / strideSize * boxOffset[0],
|
||||
cy - scaleBox / strideSize * boxOffset[1]
|
||||
|
@ -9935,24 +9956,25 @@ async function predict9(image22, config3) {
|
|||
// src/object/centernet.ts
|
||||
var tf18 = __toModule(require_tfjs_esm());
|
||||
var model8;
|
||||
var inputSize = 0;
|
||||
var last4 = [];
|
||||
var skipped6 = Number.MAX_SAFE_INTEGER;
|
||||
async function load11(config3) {
|
||||
if (env.initial)
|
||||
model8 = null;
|
||||
if (!model8) {
|
||||
model8 = await tf18.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model8.modelSignature["inputs"]);
|
||||
model8.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
if (!model8.inputSize)
|
||||
throw new Error(`Human: Cannot determine model inputSize: ${config3.object.modelPath}`);
|
||||
if (!model8 || !model8.modelUrl)
|
||||
inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
|
||||
if (!model8 || !model8["modelUrl"])
|
||||
log("load model failed:", config3.object.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model8.modelUrl);
|
||||
log("load model:", model8["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model8.modelUrl);
|
||||
log("cached model:", model8["modelUrl"]);
|
||||
return model8;
|
||||
}
|
||||
async function process4(res, inputSize, outputShape, config3) {
|
||||
async function process4(res, outputShape, config3) {
|
||||
if (!res)
|
||||
return [];
|
||||
const results = [];
|
||||
|
@ -10008,10 +10030,10 @@ async function predict10(input, config3) {
|
|||
return last4;
|
||||
return new Promise(async (resolve) => {
|
||||
const outputSize = [input.shape[2], input.shape[1]];
|
||||
const resize = tf18.image.resizeBilinear(input, [model8.inputSize, model8.inputSize]);
|
||||
const objectT = config3.object.enabled ? model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
const resize = tf18.image.resizeBilinear(input, [inputSize, inputSize]);
|
||||
const objectT = config3.object.enabled ? model8 == null ? void 0 : model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
tf18.dispose(resize);
|
||||
const obj = await process4(objectT, model8.inputSize, outputSize, config3);
|
||||
const obj = await process4(objectT, outputSize, config3);
|
||||
last4 = obj;
|
||||
resolve(obj);
|
||||
});
|
||||
|
@ -10022,7 +10044,7 @@ var tf19 = __toModule(require_tfjs_esm());
|
|||
var model9;
|
||||
var busy = false;
|
||||
async function load12(config3) {
|
||||
if (!model9) {
|
||||
if (!model9 || env.initial) {
|
||||
model9 = await tf19.loadGraphModel(join(config3.modelBasePath, config3.segmentation.modelPath || ""));
|
||||
if (!model9 || !model9["modelUrl"])
|
||||
log("load model failed:", config3.segmentation.modelPath);
|
||||
|
@ -10134,7 +10156,27 @@ async function process5(input, background, config3) {
|
|||
}
|
||||
|
||||
// src/models.ts
|
||||
function reset(instance) {
|
||||
instance.models = {
|
||||
face: null,
|
||||
handpose: null,
|
||||
posenet: null,
|
||||
blazepose: null,
|
||||
efficientpose: null,
|
||||
movenet: null,
|
||||
age: null,
|
||||
gender: null,
|
||||
emotion: null,
|
||||
embedding: null,
|
||||
nanodet: null,
|
||||
centernet: null,
|
||||
faceres: null,
|
||||
segmentation: null
|
||||
};
|
||||
}
|
||||
async function load13(instance) {
|
||||
if (env.initial)
|
||||
reset(instance);
|
||||
if (instance.config.async) {
|
||||
[
|
||||
instance.models.face,
|
||||
|
@ -10190,20 +10232,28 @@ async function validate(instance) {
|
|||
const simpleOps = ["const", "placeholder", "noop", "pad", "squeeze", "add", "sub", "mul", "div"];
|
||||
for (const defined of Object.keys(instance.models)) {
|
||||
if (instance.models[defined]) {
|
||||
let models2 = [];
|
||||
let models3 = [];
|
||||
if (Array.isArray(instance.models[defined]))
|
||||
models2 = instance.models[defined].map((model10) => model10.executor ? model10 : model10.model);
|
||||
models3 = instance.models[defined].map((model10) => model10 && model10.executor ? model10 : model10.model);
|
||||
else
|
||||
models2 = [instance.models[defined]];
|
||||
for (const model10 of models2) {
|
||||
models3 = [instance.models[defined]];
|
||||
for (const model10 of models3) {
|
||||
if (!model10) {
|
||||
if (instance.config.debug)
|
||||
log("model marked as loaded but not defined:", defined);
|
||||
continue;
|
||||
}
|
||||
const ops = [];
|
||||
const executor = model10 == null ? void 0 : model10.executor;
|
||||
if (executor) {
|
||||
if (executor && executor.graph.nodes) {
|
||||
for (const kernel of Object.values(executor.graph.nodes)) {
|
||||
const op = kernel.op.toLowerCase();
|
||||
if (!ops.includes(op))
|
||||
ops.push(op);
|
||||
}
|
||||
} else {
|
||||
if (!executor && instance.config.debug)
|
||||
log("model signature not determined:", defined);
|
||||
}
|
||||
const missing = [];
|
||||
for (const op of ops) {
|
||||
|
@ -10211,8 +10261,6 @@ async function validate(instance) {
|
|||
missing.push(op);
|
||||
}
|
||||
}
|
||||
if (!executor && instance.config.debug)
|
||||
log("model executor not found:", defined);
|
||||
if (missing.length > 0 && instance.config.debug)
|
||||
log("model validation:", defined, missing);
|
||||
}
|
||||
|
@ -11165,11 +11213,9 @@ function calc(newResult) {
|
|||
var tf21 = __toModule(require_tfjs_esm());
|
||||
var config2 = {
|
||||
name: "humangl",
|
||||
priority: 99,
|
||||
priority: 999,
|
||||
canvas: null,
|
||||
gl: null,
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
extensions: [],
|
||||
webGLattr: {
|
||||
alpha: false,
|
||||
|
@ -11188,27 +11234,58 @@ function extensions() {
|
|||
return;
|
||||
config2.extensions = gl.getSupportedExtensions();
|
||||
}
|
||||
function register() {
|
||||
async function register(instance) {
|
||||
var _a;
|
||||
if (config2.name in tf21.engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) {
|
||||
log("error: humangl backend invalid context");
|
||||
log("resetting humangl backend");
|
||||
reset(instance);
|
||||
await tf21.removeBackend(config2.name);
|
||||
await register(instance);
|
||||
}
|
||||
if (!tf21.findBackend(config2.name)) {
|
||||
try {
|
||||
config2.canvas = canvas(100, 100);
|
||||
config2.canvas = await canvas(100, 100);
|
||||
} catch (err) {
|
||||
log("error: cannot create canvas:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config2.gl = (_a = config2.canvas) == null ? void 0 : _a.getContext("webgl2", config2.webGLattr);
|
||||
if (config2.canvas) {
|
||||
config2.canvas.addEventListener("webglcontextlost", async (e) => {
|
||||
var _a2;
|
||||
const err = (_a2 = config2.gl) == null ? void 0 : _a2.getError();
|
||||
log("error: humangl context lost:", err, e);
|
||||
log("gpu memory usage:", instance.tf.engine().backendInstance.numBytesInGPU);
|
||||
log("resetting humangl backend");
|
||||
env.initial = true;
|
||||
reset(instance);
|
||||
await tf21.removeBackend(config2.name);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextrestored", (e) => {
|
||||
log("error: humangl context restored:", e);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextcreationerror", (e) => {
|
||||
log("error: humangl context create:", e);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
log("error: cannot get WebGL2 context:", err);
|
||||
log("error: cannot get WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
tf21.setWebGLContext(2, config2.gl);
|
||||
} catch (err) {
|
||||
log("error: cannot set WebGL2 context:", err);
|
||||
log("error: cannot set WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
const current = tf21.backend().getGPGPUContext().gl;
|
||||
if (current) {
|
||||
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);
|
||||
} else {
|
||||
log("error: no current context:", current, config2.gl);
|
||||
}
|
||||
try {
|
||||
const ctx = new tf21.GPGPUContext(config2.gl);
|
||||
tf21.registerBackend(config2.name, () => new tf21.MathBackendWebGL(ctx), config2.priority);
|
||||
|
@ -11240,19 +11317,22 @@ function register() {
|
|||
// src/tfjs/backend.ts
|
||||
var tf22 = __toModule(require_tfjs_esm());
|
||||
async function check(instance) {
|
||||
if (instance.initial || instance.config.backend && instance.config.backend.length > 0 && tf22.getBackend() !== instance.config.backend) {
|
||||
if (env.initial || instance.config.backend && instance.config.backend.length > 0 && tf22.getBackend() !== instance.config.backend) {
|
||||
const timeStamp = now();
|
||||
instance.state = "backend";
|
||||
if (instance.config.backend && instance.config.backend.length > 0) {
|
||||
if (typeof window === "undefined" && typeof WorkerGlobalScope !== "undefined" && instance.config.debug) {
|
||||
log("running inside web worker");
|
||||
if (instance.config.debug)
|
||||
log("running inside web worker");
|
||||
}
|
||||
if (env.browser && instance.config.backend === "tensorflow") {
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
if (instance.config.debug)
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
instance.config.backend = "humangl";
|
||||
}
|
||||
if (env.node && (instance.config.backend === "webgl" || instance.config.backend === "humangl")) {
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
if (instance.config.debug)
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
instance.config.backend = "tensorflow";
|
||||
}
|
||||
if (env.browser && instance.config.backend === "webgpu") {
|
||||
|
@ -11266,14 +11346,15 @@ async function check(instance) {
|
|||
}
|
||||
}
|
||||
if (instance.config.backend === "humangl")
|
||||
register();
|
||||
await register(instance);
|
||||
const available = Object.keys(tf22.engine().registryFactory);
|
||||
if (instance.config.debug)
|
||||
log("available backends:", available);
|
||||
if (!available.includes(instance.config.backend)) {
|
||||
log(`error: backend ${instance.config.backend} not found in registry`);
|
||||
instance.config.backend = env.node ? "tensorflow" : "humangl";
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
if (instance.config.debug)
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
}
|
||||
if (instance.config.debug)
|
||||
log("setting backend:", instance.config.backend);
|
||||
|
@ -11299,6 +11380,7 @@ async function check(instance) {
|
|||
log("error: cannot set backend:", instance.config.backend, err);
|
||||
}
|
||||
}
|
||||
tf22.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 0);
|
||||
if (tf22.getBackend() === "humangl") {
|
||||
tf22.ENV.set("CHECK_COMPUTATION_FOR_ERRORS", false);
|
||||
tf22.ENV.set("WEBGL_CPU_FORWARD", true);
|
||||
|
@ -12170,7 +12252,7 @@ var Human = class {
|
|||
__privateAdd(this, _numTensors, void 0);
|
||||
__privateAdd(this, _analyzeMemoryLeaks, void 0);
|
||||
__privateAdd(this, _checkSanity, void 0);
|
||||
__publicField(this, "initial");
|
||||
__publicField(this, "gl");
|
||||
__publicField(this, "analyze", (...msg) => {
|
||||
if (!__privateGet(this, _analyzeMemoryLeaks))
|
||||
return;
|
||||
|
@ -12213,7 +12295,6 @@ var Human = class {
|
|||
__privateSet(this, _numTensors, 0);
|
||||
__privateSet(this, _analyzeMemoryLeaks, false);
|
||||
__privateSet(this, _checkSanity, false);
|
||||
this.initial = true;
|
||||
this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };
|
||||
this.events = new EventTarget();
|
||||
this.models = {
|
||||
|
@ -12247,6 +12328,7 @@ var Human = class {
|
|||
this.process = { tensor: null, canvas: null };
|
||||
this.faceTriangulation = triangulation;
|
||||
this.faceUVMap = uvmap;
|
||||
this.gl = config2;
|
||||
this.emit("create");
|
||||
}
|
||||
similarity(embedding1, embedding2) {
|
||||
|
@ -12267,7 +12349,7 @@ var Human = class {
|
|||
const count2 = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (userConfig)
|
||||
this.config = mergeDeep(this.config, userConfig);
|
||||
if (this.initial) {
|
||||
if (env.initial) {
|
||||
if (this.config.debug)
|
||||
log(`version: ${this.version}`);
|
||||
if (this.config.debug)
|
||||
|
@ -12282,9 +12364,9 @@ var Human = class {
|
|||
}
|
||||
}
|
||||
await load13(this);
|
||||
if (this.initial && this.config.debug)
|
||||
if (env.initial && this.config.debug)
|
||||
log("tf engine state:", this.tf.engine().state.numBytes, "bytes", this.tf.engine().state.numTensors, "tensors");
|
||||
this.initial = false;
|
||||
env.initial = false;
|
||||
const loaded = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (loaded !== count2) {
|
||||
await validate(this);
|
||||
|
|
|
@ -365,13 +365,13 @@ function rotatePoint(homogeneousCoordinate, rotationMatrix) {
|
|||
dot(homogeneousCoordinate, rotationMatrix[1])
|
||||
];
|
||||
}
|
||||
function generateAnchors(inputSize) {
|
||||
const spec = { strides: [inputSize / 16, inputSize / 8], anchors: [2, 6] };
|
||||
function generateAnchors(inputSize2) {
|
||||
const spec = { strides: [inputSize2 / 16, inputSize2 / 8], anchors: [2, 6] };
|
||||
const anchors3 = [];
|
||||
for (let i = 0; i < spec.strides.length; i++) {
|
||||
const stride = spec.strides[i];
|
||||
const gridRows = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize + stride - 1) / stride);
|
||||
const gridRows = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const gridCols = Math.floor((inputSize2 + stride - 1) / stride);
|
||||
const anchorsNum = spec.anchors[i];
|
||||
for (let gridY = 0; gridY < gridRows; gridY++) {
|
||||
const anchorY = stride * (gridY + 0.5);
|
||||
|
@ -388,17 +388,17 @@ function generateAnchors(inputSize) {
|
|||
|
||||
// src/blazeface/blazeface.ts
|
||||
var keypointsCount = 6;
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize) {
|
||||
function decodeBounds(boxOutputs, anchors3, inputSize2) {
|
||||
const boxStarts = tf2.slice(boxOutputs, [0, 1], [-1, 2]);
|
||||
const centers = tf2.add(boxStarts, anchors3);
|
||||
const boxSizes = tf2.slice(boxOutputs, [0, 3], [-1, 2]);
|
||||
const boxSizesNormalized = tf2.div(boxSizes, inputSize);
|
||||
const centersNormalized = tf2.div(centers, inputSize);
|
||||
const boxSizesNormalized = tf2.div(boxSizes, inputSize2);
|
||||
const centersNormalized = tf2.div(centers, inputSize2);
|
||||
const halfBoxSize = tf2.div(boxSizesNormalized, 2);
|
||||
const starts = tf2.sub(centersNormalized, halfBoxSize);
|
||||
const ends = tf2.add(centersNormalized, halfBoxSize);
|
||||
const startNormalized = tf2.mul(starts, inputSize);
|
||||
const endNormalized = tf2.mul(ends, inputSize);
|
||||
const startNormalized = tf2.mul(starts, inputSize2);
|
||||
const endNormalized = tf2.mul(ends, inputSize2);
|
||||
const concatAxis = 1;
|
||||
return tf2.concat2d([startNormalized, endNormalized], concatAxis);
|
||||
}
|
||||
|
@ -4596,9 +4596,13 @@ function process2(input, config3) {
|
|||
pixels = tf3.browser && env.browser ? tf3.browser.fromPixels(tempCanvas) : null;
|
||||
} else {
|
||||
const tempCanvas = canvas(targetWidth, targetHeight);
|
||||
if (!tempCanvas)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext("2d");
|
||||
if (!tempCtx)
|
||||
return { tensor: null, canvas: inCanvas };
|
||||
tempCtx.drawImage(outCanvas, 0, 0);
|
||||
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
if (tf3.browser && env.browser) {
|
||||
|
@ -4654,6 +4658,7 @@ var env = {
|
|||
worker: void 0,
|
||||
platform: void 0,
|
||||
agent: void 0,
|
||||
initial: true,
|
||||
backends: [],
|
||||
tfjs: {
|
||||
version: void 0
|
||||
|
@ -5058,7 +5063,9 @@ async function predict(input, config3) {
|
|||
return results;
|
||||
}
|
||||
async function load2(config3) {
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled) {
|
||||
if (env.initial)
|
||||
faceModels = [null, null, null];
|
||||
if (!faceModels[0] && config3.face.enabled || !faceModels[1] && config3.face.mesh.enabled || !faceModels[2] && config3.face.iris.enabled || env.initial) {
|
||||
faceModels = await Promise.all([
|
||||
!faceModels[0] && config3.face.enabled ? load(config3) : null,
|
||||
!faceModels[1] && config3.face.mesh.enabled ? tf6.loadGraphModel(join(config3.modelBasePath, config3.face.mesh.modelPath), { fromTFHub: config3.face.mesh.modelPath.includes("tfhub.dev") }) : null,
|
||||
|
@ -5099,6 +5106,8 @@ var skipped = Number.MAX_SAFE_INTEGER;
|
|||
async function load3(config3) {
|
||||
var _a, _b;
|
||||
const modelUrl = join(config3.modelBasePath, ((_a = config3.face.description) == null ? void 0 : _a.modelPath) || "");
|
||||
if (env.initial)
|
||||
model = null;
|
||||
if (!model) {
|
||||
model = await tf7.loadGraphModel(modelUrl);
|
||||
if (!model)
|
||||
|
@ -5139,7 +5148,7 @@ function enhance(input) {
|
|||
if (!(tensor3 instanceof tf7.Tensor))
|
||||
return null;
|
||||
const box6 = [[0.05, 0.15, 0.85, 0.85]];
|
||||
if (!model.inputs[0].shape)
|
||||
if (!(model == null ? void 0 : model.inputs[0].shape))
|
||||
return null;
|
||||
const crop = tensor3.shape.length === 3 ? tf7.image.cropAndResize(tf7.expandDims(tensor3, 0), box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) : tf7.image.cropAndResize(tensor3, box6, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
|
||||
const norm = tf7.mul(crop, 255);
|
||||
|
@ -5167,7 +5176,7 @@ async function predict2(image22, config3, idx, count2) {
|
|||
descriptor: []
|
||||
};
|
||||
if ((_a2 = config3.face.description) == null ? void 0 : _a2.enabled)
|
||||
resT = await model.predict(enhanced);
|
||||
resT = await (model == null ? void 0 : model.predict(enhanced));
|
||||
tf7.dispose(enhanced);
|
||||
if (resT) {
|
||||
const gender = await resT.find((t) => t.shape[1] === 1).data();
|
||||
|
@ -5201,15 +5210,17 @@ var lastCount2 = 0;
|
|||
var skipped2 = Number.MAX_SAFE_INTEGER;
|
||||
var rgb = [0.2989, 0.587, 0.114];
|
||||
async function load4(config3) {
|
||||
var _a, _b;
|
||||
var _a;
|
||||
if (env.initial)
|
||||
model2 = null;
|
||||
if (!model2) {
|
||||
model2 = await tf8.loadGraphModel(join(config3.modelBasePath, ((_a = config3.face.emotion) == null ? void 0 : _a.modelPath) || ""));
|
||||
if (!model2 || !model2.modelUrl)
|
||||
log("load model failed:", ((_b = config3.face.emotion) == null ? void 0 : _b.modelPath) || "");
|
||||
if (!model2 || !model2["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model2.modelUrl);
|
||||
log("load model:", model2["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model2.modelUrl);
|
||||
log("cached model:", model2["modelUrl"]);
|
||||
return model2;
|
||||
}
|
||||
async function predict3(image22, config3, idx, count2) {
|
||||
|
@ -5223,7 +5234,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
skipped2 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
var _a2, _b;
|
||||
const resize = tf8.image.resizeBilinear(image22, [model2.inputs[0].shape[2], model2.inputs[0].shape[1]], false);
|
||||
const resize = tf8.image.resizeBilinear(image22, [(model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[2] : 0, (model2 == null ? void 0 : model2.inputs[0].shape) ? model2.inputs[0].shape[1] : 0], false);
|
||||
const [red, green, blue] = tf8.split(resize, 3, 3);
|
||||
tf8.dispose(resize);
|
||||
const redNorm = tf8.mul(red, rgb[0]);
|
||||
|
@ -5240,7 +5251,7 @@ async function predict3(image22, config3, idx, count2) {
|
|||
tf8.dispose(grayscale);
|
||||
const obj = [];
|
||||
if ((_a2 = config3.face.emotion) == null ? void 0 : _a2.enabled) {
|
||||
const emotionT = await model2.predict(normalize);
|
||||
const emotionT = await (model2 == null ? void 0 : model2.predict(normalize));
|
||||
const data = await emotionT.data();
|
||||
tf8.dispose(emotionT);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
@ -5592,7 +5603,7 @@ async function predict4(input, config3) {
|
|||
return scaled;
|
||||
}
|
||||
async function load5(config3) {
|
||||
if (!model3) {
|
||||
if (!model3 || env.initial) {
|
||||
model3 = await tf9.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model3 || !model3["modelUrl"])
|
||||
log("load model failed:", config3.body.modelPath);
|
||||
|
@ -9332,6 +9343,10 @@ async function predict5(input, config3) {
|
|||
}
|
||||
async function load6(config3) {
|
||||
var _a, _b, _c, _d, _e, _f;
|
||||
if (env.initial) {
|
||||
handDetectorModel = null;
|
||||
handPoseModel = null;
|
||||
}
|
||||
if (!handDetectorModel || !handPoseModel) {
|
||||
[handDetectorModel, handPoseModel] = await Promise.all([
|
||||
config3.hand.enabled ? tf13.loadGraphModel(join(config3.modelBasePath, ((_a = config3.hand.detector) == null ? void 0 : _a.modelPath) || ""), { fromTFHub: (((_b = config3.hand.detector) == null ? void 0 : _b.modelPath) || "").includes("tfhub.dev") }) : null,
|
||||
|
@ -9440,6 +9455,8 @@ var upper = [
|
|||
// src/blazepose/blazepose.ts
|
||||
var model4;
|
||||
async function load7(config3) {
|
||||
if (env.initial)
|
||||
model4 = null;
|
||||
if (!model4) {
|
||||
model4 = await tf14.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
model4["width"] = parseInt(model4["signature"].inputs["input_1:0"].tensorShape.dim[2].size);
|
||||
|
@ -9510,6 +9527,8 @@ var score = 0;
|
|||
var skipped3 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts = ["head", "neck", "rightShoulder", "rightElbow", "rightWrist", "chest", "leftShoulder", "leftElbow", "leftWrist", "pelvis", "rightHip", "rightKnee", "rightAnkle", "leftHip", "leftKnee", "leftAnkle"];
|
||||
async function load8(config3) {
|
||||
if (env.initial)
|
||||
model5 = null;
|
||||
if (!model5) {
|
||||
model5 = await tf15.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model5 || !model5["modelUrl"])
|
||||
|
@ -9545,7 +9564,7 @@ async function predict7(image22, config3) {
|
|||
return new Promise(async (resolve) => {
|
||||
var _a2;
|
||||
const tensor3 = tf15.tidy(() => {
|
||||
if (!model5.inputs[0].shape)
|
||||
if (!(model5 == null ? void 0 : model5.inputs[0].shape))
|
||||
return null;
|
||||
const resize = tf15.image.resizeBilinear(image22, [model5.inputs[0].shape[2], model5.inputs[0].shape[1]], false);
|
||||
const enhance2 = tf15.mul(resize, 2);
|
||||
|
@ -9554,7 +9573,7 @@ async function predict7(image22, config3) {
|
|||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model5.predict(tensor3);
|
||||
resT = await (model5 == null ? void 0 : model5.predict(tensor3));
|
||||
tf15.dispose(tensor3);
|
||||
if (resT) {
|
||||
keypoints.length = 0;
|
||||
|
@ -9612,6 +9631,8 @@ var score2 = 0;
|
|||
var skipped4 = Number.MAX_SAFE_INTEGER;
|
||||
var bodyParts2 = ["nose", "leftEye", "rightEye", "leftEar", "rightEar", "leftShoulder", "rightShoulder", "leftElbow", "rightElbow", "leftWrist", "rightWrist", "leftHip", "rightHip", "leftKnee", "rightKnee", "leftAnkle", "rightAnkle"];
|
||||
async function load9(config3) {
|
||||
if (env.initial)
|
||||
model6 = null;
|
||||
if (!model6) {
|
||||
model6 = await tf16.loadGraphModel(join(config3.modelBasePath, config3.body.modelPath || ""));
|
||||
if (!model6 || !model6["modelUrl"])
|
||||
|
@ -9712,18 +9733,18 @@ async function predict8(image22, config3) {
|
|||
skipped4 = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor3 = tf16.tidy(() => {
|
||||
if (!model6.inputs[0].shape)
|
||||
if (!(model6 == null ? void 0 : model6.inputs[0].shape))
|
||||
return null;
|
||||
let inputSize = model6.inputs[0].shape[2];
|
||||
if (inputSize === -1)
|
||||
inputSize = 256;
|
||||
const resize = tf16.image.resizeBilinear(image22, [inputSize, inputSize], false);
|
||||
let inputSize2 = model6.inputs[0].shape[2];
|
||||
if (inputSize2 === -1)
|
||||
inputSize2 = 256;
|
||||
const resize = tf16.image.resizeBilinear(image22, [inputSize2, inputSize2], false);
|
||||
const cast4 = tf16.cast(resize, "int32");
|
||||
return cast4;
|
||||
});
|
||||
let resT;
|
||||
if (config3.body.enabled)
|
||||
resT = await model6.predict(tensor3);
|
||||
resT = await (model6 == null ? void 0 : model6.predict(tensor3));
|
||||
tf16.dispose(tensor3);
|
||||
if (!resT)
|
||||
resolve([]);
|
||||
|
@ -9831,7 +9852,7 @@ var last3 = [];
|
|||
var skipped5 = Number.MAX_SAFE_INTEGER;
|
||||
var scaleBox = 2.5;
|
||||
async function load10(config3) {
|
||||
if (!model7) {
|
||||
if (!model7 || env.initial) {
|
||||
model7 = await tf17.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model7.modelSignature["inputs"]);
|
||||
model7.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
|
@ -9845,7 +9866,7 @@ async function load10(config3) {
|
|||
log("cached model:", model7.modelUrl);
|
||||
return model7;
|
||||
}
|
||||
async function process3(res, inputSize, outputShape, config3) {
|
||||
async function process3(res, inputSize2, outputShape, config3) {
|
||||
let id = 0;
|
||||
let results = [];
|
||||
for (const strideSize of [1, 2, 4]) {
|
||||
|
@ -9863,7 +9884,7 @@ async function process3(res, inputSize, outputShape, config3) {
|
|||
if (score3 > config3.object.minConfidence && j !== 61) {
|
||||
const cx = (0.5 + Math.trunc(i % baseSize)) / baseSize;
|
||||
const cy = (0.5 + Math.trunc(i / baseSize)) / baseSize;
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize));
|
||||
const boxOffset = boxIdx[i].map((a) => a * (baseSize / strideSize / inputSize2));
|
||||
const [x, y] = [
|
||||
cx - scaleBox / strideSize * boxOffset[0],
|
||||
cy - scaleBox / strideSize * boxOffset[1]
|
||||
|
@ -9934,24 +9955,25 @@ async function predict9(image22, config3) {
|
|||
// src/object/centernet.ts
|
||||
var tf18 = __toModule(require_tfjs_esm());
|
||||
var model8;
|
||||
var inputSize = 0;
|
||||
var last4 = [];
|
||||
var skipped6 = Number.MAX_SAFE_INTEGER;
|
||||
async function load11(config3) {
|
||||
if (env.initial)
|
||||
model8 = null;
|
||||
if (!model8) {
|
||||
model8 = await tf18.loadGraphModel(join(config3.modelBasePath, config3.object.modelPath || ""));
|
||||
const inputs = Object.values(model8.modelSignature["inputs"]);
|
||||
model8.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
if (!model8.inputSize)
|
||||
throw new Error(`Human: Cannot determine model inputSize: ${config3.object.modelPath}`);
|
||||
if (!model8 || !model8.modelUrl)
|
||||
inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
|
||||
if (!model8 || !model8["modelUrl"])
|
||||
log("load model failed:", config3.object.modelPath);
|
||||
else if (config3.debug)
|
||||
log("load model:", model8.modelUrl);
|
||||
log("load model:", model8["modelUrl"]);
|
||||
} else if (config3.debug)
|
||||
log("cached model:", model8.modelUrl);
|
||||
log("cached model:", model8["modelUrl"]);
|
||||
return model8;
|
||||
}
|
||||
async function process4(res, inputSize, outputShape, config3) {
|
||||
async function process4(res, outputShape, config3) {
|
||||
if (!res)
|
||||
return [];
|
||||
const results = [];
|
||||
|
@ -10007,10 +10029,10 @@ async function predict10(input, config3) {
|
|||
return last4;
|
||||
return new Promise(async (resolve) => {
|
||||
const outputSize = [input.shape[2], input.shape[1]];
|
||||
const resize = tf18.image.resizeBilinear(input, [model8.inputSize, model8.inputSize]);
|
||||
const objectT = config3.object.enabled ? model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
const resize = tf18.image.resizeBilinear(input, [inputSize, inputSize]);
|
||||
const objectT = config3.object.enabled ? model8 == null ? void 0 : model8.execute(resize, ["tower_0/detections"]) : null;
|
||||
tf18.dispose(resize);
|
||||
const obj = await process4(objectT, model8.inputSize, outputSize, config3);
|
||||
const obj = await process4(objectT, outputSize, config3);
|
||||
last4 = obj;
|
||||
resolve(obj);
|
||||
});
|
||||
|
@ -10021,7 +10043,7 @@ var tf19 = __toModule(require_tfjs_esm());
|
|||
var model9;
|
||||
var busy = false;
|
||||
async function load12(config3) {
|
||||
if (!model9) {
|
||||
if (!model9 || env.initial) {
|
||||
model9 = await tf19.loadGraphModel(join(config3.modelBasePath, config3.segmentation.modelPath || ""));
|
||||
if (!model9 || !model9["modelUrl"])
|
||||
log("load model failed:", config3.segmentation.modelPath);
|
||||
|
@ -10133,7 +10155,27 @@ async function process5(input, background, config3) {
|
|||
}
|
||||
|
||||
// src/models.ts
|
||||
function reset(instance) {
|
||||
instance.models = {
|
||||
face: null,
|
||||
handpose: null,
|
||||
posenet: null,
|
||||
blazepose: null,
|
||||
efficientpose: null,
|
||||
movenet: null,
|
||||
age: null,
|
||||
gender: null,
|
||||
emotion: null,
|
||||
embedding: null,
|
||||
nanodet: null,
|
||||
centernet: null,
|
||||
faceres: null,
|
||||
segmentation: null
|
||||
};
|
||||
}
|
||||
async function load13(instance) {
|
||||
if (env.initial)
|
||||
reset(instance);
|
||||
if (instance.config.async) {
|
||||
[
|
||||
instance.models.face,
|
||||
|
@ -10189,20 +10231,28 @@ async function validate(instance) {
|
|||
const simpleOps = ["const", "placeholder", "noop", "pad", "squeeze", "add", "sub", "mul", "div"];
|
||||
for (const defined of Object.keys(instance.models)) {
|
||||
if (instance.models[defined]) {
|
||||
let models2 = [];
|
||||
let models3 = [];
|
||||
if (Array.isArray(instance.models[defined]))
|
||||
models2 = instance.models[defined].map((model10) => model10.executor ? model10 : model10.model);
|
||||
models3 = instance.models[defined].map((model10) => model10 && model10.executor ? model10 : model10.model);
|
||||
else
|
||||
models2 = [instance.models[defined]];
|
||||
for (const model10 of models2) {
|
||||
models3 = [instance.models[defined]];
|
||||
for (const model10 of models3) {
|
||||
if (!model10) {
|
||||
if (instance.config.debug)
|
||||
log("model marked as loaded but not defined:", defined);
|
||||
continue;
|
||||
}
|
||||
const ops = [];
|
||||
const executor = model10 == null ? void 0 : model10.executor;
|
||||
if (executor) {
|
||||
if (executor && executor.graph.nodes) {
|
||||
for (const kernel of Object.values(executor.graph.nodes)) {
|
||||
const op = kernel.op.toLowerCase();
|
||||
if (!ops.includes(op))
|
||||
ops.push(op);
|
||||
}
|
||||
} else {
|
||||
if (!executor && instance.config.debug)
|
||||
log("model signature not determined:", defined);
|
||||
}
|
||||
const missing = [];
|
||||
for (const op of ops) {
|
||||
|
@ -10210,8 +10260,6 @@ async function validate(instance) {
|
|||
missing.push(op);
|
||||
}
|
||||
}
|
||||
if (!executor && instance.config.debug)
|
||||
log("model executor not found:", defined);
|
||||
if (missing.length > 0 && instance.config.debug)
|
||||
log("model validation:", defined, missing);
|
||||
}
|
||||
|
@ -11164,11 +11212,9 @@ function calc(newResult) {
|
|||
var tf21 = __toModule(require_tfjs_esm());
|
||||
var config2 = {
|
||||
name: "humangl",
|
||||
priority: 99,
|
||||
priority: 999,
|
||||
canvas: null,
|
||||
gl: null,
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
extensions: [],
|
||||
webGLattr: {
|
||||
alpha: false,
|
||||
|
@ -11187,27 +11233,58 @@ function extensions() {
|
|||
return;
|
||||
config2.extensions = gl.getSupportedExtensions();
|
||||
}
|
||||
function register() {
|
||||
async function register(instance) {
|
||||
var _a;
|
||||
if (config2.name in tf21.engine().registry && (!config2.gl || !config2.gl.getParameter(config2.gl.VERSION))) {
|
||||
log("error: humangl backend invalid context");
|
||||
log("resetting humangl backend");
|
||||
reset(instance);
|
||||
await tf21.removeBackend(config2.name);
|
||||
await register(instance);
|
||||
}
|
||||
if (!tf21.findBackend(config2.name)) {
|
||||
try {
|
||||
config2.canvas = canvas(100, 100);
|
||||
config2.canvas = await canvas(100, 100);
|
||||
} catch (err) {
|
||||
log("error: cannot create canvas:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config2.gl = (_a = config2.canvas) == null ? void 0 : _a.getContext("webgl2", config2.webGLattr);
|
||||
if (config2.canvas) {
|
||||
config2.canvas.addEventListener("webglcontextlost", async (e) => {
|
||||
var _a2;
|
||||
const err = (_a2 = config2.gl) == null ? void 0 : _a2.getError();
|
||||
log("error: humangl context lost:", err, e);
|
||||
log("gpu memory usage:", instance.tf.engine().backendInstance.numBytesInGPU);
|
||||
log("resetting humangl backend");
|
||||
env.initial = true;
|
||||
reset(instance);
|
||||
await tf21.removeBackend(config2.name);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextrestored", (e) => {
|
||||
log("error: humangl context restored:", e);
|
||||
});
|
||||
config2.canvas.addEventListener("webglcontextcreationerror", (e) => {
|
||||
log("error: humangl context create:", e);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
log("error: cannot get WebGL2 context:", err);
|
||||
log("error: cannot get WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
tf21.setWebGLContext(2, config2.gl);
|
||||
} catch (err) {
|
||||
log("error: cannot set WebGL2 context:", err);
|
||||
log("error: cannot set WebGL context:", err);
|
||||
return;
|
||||
}
|
||||
const current = tf21.backend().getGPGPUContext().gl;
|
||||
if (current) {
|
||||
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);
|
||||
} else {
|
||||
log("error: no current context:", current, config2.gl);
|
||||
}
|
||||
try {
|
||||
const ctx = new tf21.GPGPUContext(config2.gl);
|
||||
tf21.registerBackend(config2.name, () => new tf21.MathBackendWebGL(ctx), config2.priority);
|
||||
|
@ -11239,19 +11316,22 @@ function register() {
|
|||
// src/tfjs/backend.ts
|
||||
var tf22 = __toModule(require_tfjs_esm());
|
||||
async function check(instance) {
|
||||
if (instance.initial || instance.config.backend && instance.config.backend.length > 0 && tf22.getBackend() !== instance.config.backend) {
|
||||
if (env.initial || instance.config.backend && instance.config.backend.length > 0 && tf22.getBackend() !== instance.config.backend) {
|
||||
const timeStamp = now();
|
||||
instance.state = "backend";
|
||||
if (instance.config.backend && instance.config.backend.length > 0) {
|
||||
if (typeof window === "undefined" && typeof WorkerGlobalScope !== "undefined" && instance.config.debug) {
|
||||
log("running inside web worker");
|
||||
if (instance.config.debug)
|
||||
log("running inside web worker");
|
||||
}
|
||||
if (env.browser && instance.config.backend === "tensorflow") {
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
if (instance.config.debug)
|
||||
log("override: backend set to tensorflow while running in browser");
|
||||
instance.config.backend = "humangl";
|
||||
}
|
||||
if (env.node && (instance.config.backend === "webgl" || instance.config.backend === "humangl")) {
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
if (instance.config.debug)
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
instance.config.backend = "tensorflow";
|
||||
}
|
||||
if (env.browser && instance.config.backend === "webgpu") {
|
||||
|
@ -11265,14 +11345,15 @@ async function check(instance) {
|
|||
}
|
||||
}
|
||||
if (instance.config.backend === "humangl")
|
||||
register();
|
||||
await register(instance);
|
||||
const available = Object.keys(tf22.engine().registryFactory);
|
||||
if (instance.config.debug)
|
||||
log("available backends:", available);
|
||||
if (!available.includes(instance.config.backend)) {
|
||||
log(`error: backend ${instance.config.backend} not found in registry`);
|
||||
instance.config.backend = env.node ? "tensorflow" : "humangl";
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
if (instance.config.debug)
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
}
|
||||
if (instance.config.debug)
|
||||
log("setting backend:", instance.config.backend);
|
||||
|
@ -11298,6 +11379,7 @@ async function check(instance) {
|
|||
log("error: cannot set backend:", instance.config.backend, err);
|
||||
}
|
||||
}
|
||||
tf22.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD", 0);
|
||||
if (tf22.getBackend() === "humangl") {
|
||||
tf22.ENV.set("CHECK_COMPUTATION_FOR_ERRORS", false);
|
||||
tf22.ENV.set("WEBGL_CPU_FORWARD", true);
|
||||
|
@ -12169,7 +12251,7 @@ var Human = class {
|
|||
__privateAdd(this, _numTensors, void 0);
|
||||
__privateAdd(this, _analyzeMemoryLeaks, void 0);
|
||||
__privateAdd(this, _checkSanity, void 0);
|
||||
__publicField(this, "initial");
|
||||
__publicField(this, "gl");
|
||||
__publicField(this, "analyze", (...msg) => {
|
||||
if (!__privateGet(this, _analyzeMemoryLeaks))
|
||||
return;
|
||||
|
@ -12212,7 +12294,6 @@ var Human = class {
|
|||
__privateSet(this, _numTensors, 0);
|
||||
__privateSet(this, _analyzeMemoryLeaks, false);
|
||||
__privateSet(this, _checkSanity, false);
|
||||
this.initial = true;
|
||||
this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };
|
||||
this.events = new EventTarget();
|
||||
this.models = {
|
||||
|
@ -12246,6 +12327,7 @@ var Human = class {
|
|||
this.process = { tensor: null, canvas: null };
|
||||
this.faceTriangulation = triangulation;
|
||||
this.faceUVMap = uvmap;
|
||||
this.gl = config2;
|
||||
this.emit("create");
|
||||
}
|
||||
similarity(embedding1, embedding2) {
|
||||
|
@ -12266,7 +12348,7 @@ var Human = class {
|
|||
const count2 = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (userConfig)
|
||||
this.config = mergeDeep(this.config, userConfig);
|
||||
if (this.initial) {
|
||||
if (env.initial) {
|
||||
if (this.config.debug)
|
||||
log(`version: ${this.version}`);
|
||||
if (this.config.debug)
|
||||
|
@ -12281,9 +12363,9 @@ var Human = class {
|
|||
}
|
||||
}
|
||||
await load13(this);
|
||||
if (this.initial && this.config.debug)
|
||||
if (env.initial && this.config.debug)
|
||||
log("tf engine state:", this.tf.engine().state.numBytes, "bytes", this.tf.engine().state.numTensors, "tensors");
|
||||
this.initial = false;
|
||||
env.initial = false;
|
||||
const loaded = Object.values(this.models).filter((model10) => model10).length;
|
||||
if (loaded !== count2) {
|
||||
await validate(this);
|
||||
|
|
|
@ -7,19 +7,23 @@ import { log, join } from '../helpers';
|
|||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import type { Config } from '../config';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
|
||||
let last = { age: 0 };
|
||||
let skipped = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export async function load(config: Config | any) {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.age.modelPath)) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.face.age.modelPath);
|
||||
else if (config.debug) log('load model:', model['modelUrl']);
|
||||
} else if (config.debug) log('cached model:', model['modelUrl']);
|
||||
} else {
|
||||
if (config.debug) log('cached model:', model['modelUrl']);
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
|
@ -32,7 +36,7 @@ export async function predict(image: Tensor, config: Config | any) {
|
|||
}
|
||||
skipped = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
if (!model.inputs || !model.inputs[0] || !model.inputs[0].shape) return;
|
||||
if (!model?.inputs || !model.inputs[0] || !model.inputs[0].shape) return;
|
||||
const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
|
||||
const enhance = tf.mul(resize, [255.0]);
|
||||
tf.dispose(resize);
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as coords from './coords';
|
|||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import type { FaceResult } from '../result';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let faceModels: [blazeface.BlazeFaceModel | null, GraphModel | null, GraphModel | null] = [null, null, null];
|
||||
let facePipeline;
|
||||
|
@ -58,7 +59,8 @@ export async function predict(input: Tensor, config: Config): Promise<FaceResult
|
|||
}
|
||||
|
||||
export async function load(config): Promise<[unknown, GraphModel | null, GraphModel | null]> {
|
||||
if ((!faceModels[0] && config.face.enabled) || (!faceModels[1] && config.face.mesh.enabled) || (!faceModels[2] && config.face.iris.enabled)) {
|
||||
if (env.initial) faceModels = [null, null, null];
|
||||
if ((!faceModels[0] && config.face.enabled) || (!faceModels[1] && config.face.mesh.enabled) || (!faceModels[2] && config.face.iris.enabled) || env.initial) {
|
||||
faceModels = await Promise.all([
|
||||
(!faceModels[0] && config.face.enabled) ? blazeface.load(config) : null,
|
||||
(!faceModels[1] && config.face.mesh.enabled) ? tf.loadGraphModel(join(config.modelBasePath, config.face.mesh.modelPath), { fromTFHub: config.face.mesh.modelPath.includes('tfhub.dev') }) as unknown as GraphModel : null,
|
||||
|
|
|
@ -10,10 +10,12 @@ import * as annotations from './annotations';
|
|||
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||
import type { BodyResult } from '../result';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;
|
||||
model['width'] = parseInt(model['signature'].inputs['input_1:0'].tensorShape.dim[2].size);
|
||||
|
|
|
@ -7,8 +7,9 @@ import * as tf from '../../dist/tfjs.esm.js';
|
|||
import type { BodyResult } from '../result';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
|
||||
type Keypoints = { score: number, part: string, position: [number, number], positionRaw: [number, number] };
|
||||
|
||||
|
@ -21,6 +22,7 @@ let skipped = Number.MAX_SAFE_INTEGER;
|
|||
const bodyParts = ['head', 'neck', 'rightShoulder', 'rightElbow', 'rightWrist', 'chest', 'leftShoulder', 'leftElbow', 'leftWrist', 'pelvis', 'rightHip', 'rightKnee', 'rightAnkle', 'leftHip', 'leftKnee', 'leftAnkle'];
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);
|
||||
|
@ -54,7 +56,7 @@ export async function predict(image: Tensor, config: Config): Promise<BodyResult
|
|||
skipped = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor = tf.tidy(() => {
|
||||
if (!model.inputs[0].shape) return null;
|
||||
if (!model?.inputs[0].shape) return null;
|
||||
const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
|
||||
const enhance = tf.mul(resize, 2);
|
||||
const norm = enhance.sub(1);
|
||||
|
@ -62,7 +64,7 @@ export async function predict(image: Tensor, config: Config): Promise<BodyResult
|
|||
});
|
||||
|
||||
let resT;
|
||||
if (config.body.enabled) resT = await model.predict(tensor);
|
||||
if (config.body.enabled) resT = await model?.predict(tensor);
|
||||
tf.dispose(tensor);
|
||||
|
||||
if (resT) {
|
||||
|
|
|
@ -6,12 +6,14 @@
|
|||
import { log, join } from '../helpers';
|
||||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||
import { env } from '../env';
|
||||
|
||||
type DB = Array<{ name: string, source: string, embedding: number[] }>;
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
|
||||
export async function load(config) {
|
||||
const modelUrl = join(config.modelBasePath, config.face.embedding.modelPath);
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(modelUrl) as unknown as GraphModel;
|
||||
if (!model) log('load model failed:', config.face.embedding.modelPath);
|
||||
|
@ -99,7 +101,7 @@ export async function predict(input, config): Promise<number[]> {
|
|||
const nchw = image.transpose([3, 0, 1, 2]);
|
||||
*/
|
||||
|
||||
const res = model.predict(image);
|
||||
const res = model?.predict(image);
|
||||
|
||||
/*
|
||||
// optionally do it twice with flipped image and average results
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
|
||||
import { log, join } from '../helpers';
|
||||
import type { Config } from '../config';
|
||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import { env } from '../env';
|
||||
|
||||
const annotations = ['angry', 'disgust', 'fear', 'happy', 'sad', 'surprise', 'neutral'];
|
||||
let model;
|
||||
let model: GraphModel | null;
|
||||
// let last: Array<{ score: number, emotion: string }> = [];
|
||||
const last: Array<Array<{ score: number, emotion: string }>> = [];
|
||||
let lastCount = 0;
|
||||
|
@ -18,11 +19,12 @@ let skipped = Number.MAX_SAFE_INTEGER;
|
|||
const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when converting to grayscale
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.emotion?.modelPath || ''));
|
||||
if (!model || !model.modelUrl) log('load model failed:', config.face.emotion?.modelPath || '');
|
||||
else if (config.debug) log('load model:', model.modelUrl);
|
||||
} else if (config.debug) log('cached model:', model.modelUrl);
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.emotion?.modelPath || '')) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);
|
||||
else if (config.debug) log('load model:', model['modelUrl']);
|
||||
} else if (config.debug) log('cached model:', model['modelUrl']);
|
||||
return model;
|
||||
}
|
||||
|
||||
|
@ -34,7 +36,7 @@ export async function predict(image: Tensor, config: Config, idx, count) {
|
|||
}
|
||||
skipped = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
|
||||
const resize = tf.image.resizeBilinear(image, [model?.inputs[0].shape ? model.inputs[0].shape[2] : 0, model?.inputs[0].shape ? model.inputs[0].shape[1] : 0], false);
|
||||
const [red, green, blue] = tf.split(resize, 3, 3);
|
||||
tf.dispose(resize);
|
||||
// weighted rgb to grayscale: https://www.mathworks.com/help/matlab/ref/rgb2gray.html
|
||||
|
@ -52,7 +54,7 @@ export async function predict(image: Tensor, config: Config, idx, count) {
|
|||
tf.dispose(grayscale);
|
||||
const obj: Array<{ score: number, emotion: string }> = [];
|
||||
if (config.face.emotion?.enabled) {
|
||||
const emotionT = await model.predict(normalize); // result is already in range 0..1, no need for additional activation
|
||||
const emotionT = await model?.predict(normalize) as Tensor; // result is already in range 0..1, no need for additional activation
|
||||
const data = await emotionT.data();
|
||||
tf.dispose(emotionT);
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
|
|
|
@ -8,6 +8,7 @@ export interface Env {
|
|||
platform: undefined | string,
|
||||
agent: undefined | string,
|
||||
backends: string[],
|
||||
initial: boolean,
|
||||
tfjs: {
|
||||
version: undefined | string,
|
||||
},
|
||||
|
@ -39,6 +40,7 @@ export const env: Env = {
|
|||
worker: undefined,
|
||||
platform: undefined,
|
||||
agent: undefined,
|
||||
initial: true,
|
||||
backends: [],
|
||||
tfjs: {
|
||||
version: undefined,
|
||||
|
|
|
@ -8,8 +8,9 @@ import { log, join } from '../helpers';
|
|||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
const last: Array<{
|
||||
age: number,
|
||||
gender: string,
|
||||
|
@ -24,6 +25,7 @@ type DB = Array<{ name: string, source: string, embedding: number[] }>;
|
|||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
const modelUrl = join(config.modelBasePath, config.face.description?.modelPath || '');
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(modelUrl) as unknown as GraphModel;
|
||||
if (!model) log('load model failed:', config.face.description?.modelPath || '');
|
||||
|
@ -66,7 +68,7 @@ export function enhance(input): Tensor {
|
|||
// do a tight crop of image and resize it to fit the model
|
||||
const box = [[0.05, 0.15, 0.85, 0.85]]; // empyrical values for top, left, bottom, right
|
||||
// const box = [[0.0, 0.0, 1.0, 1.0]]; // basically no crop for test
|
||||
if (!model.inputs[0].shape) return null; // model has no shape so no point continuing
|
||||
if (!model?.inputs[0].shape) return null; // model has no shape so no point continuing
|
||||
const crop = (tensor.shape.length === 3)
|
||||
? tf.image.cropAndResize(tf.expandDims(tensor, 0), box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]) // add batch dimension if missing
|
||||
: tf.image.cropAndResize(tensor, box, [0], [model.inputs[0].shape[2], model.inputs[0].shape[1]]);
|
||||
|
@ -128,7 +130,7 @@ export async function predict(image: Tensor, config: Config, idx, count) {
|
|||
descriptor: <number[]>[],
|
||||
};
|
||||
|
||||
if (config.face.description?.enabled) resT = await model.predict(enhanced);
|
||||
if (config.face.description?.enabled) resT = await model?.predict(enhanced);
|
||||
tf.dispose(enhanced);
|
||||
|
||||
if (resT) {
|
||||
|
|
|
@ -25,14 +25,16 @@ import { log, join } from '../helpers';
|
|||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import type { Config } from '../config';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
|
||||
let last = { age: 0 };
|
||||
let skipped = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export async function load(config: Config | any) {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.agegenderrace.modelPath)) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.face.agegenderrace.modelPath);
|
||||
|
@ -51,8 +53,8 @@ export async function predict(image: Tensor, config: Config) {
|
|||
}
|
||||
skipped = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
if (!model.inputs[0].shape) return;
|
||||
const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
|
||||
if (!model?.inputs[0].shape) return;
|
||||
const resize = tf.image.resizeBilinear(image, [model?.inputs[0].shape[2], model?.inputs[0].shape[1]], false);
|
||||
// const enhance = tf.mul(resize, [255.0]);
|
||||
|
||||
let ageT;
|
||||
|
|
|
@ -7,8 +7,9 @@ import { log, join } from '../helpers';
|
|||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import type { Config } from '../config';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
let last = { gender: '' };
|
||||
let skipped = Number.MAX_SAFE_INTEGER;
|
||||
let alternative = false;
|
||||
|
@ -18,6 +19,7 @@ const rgb = [0.2989, 0.5870, 0.1140]; // factors for red/green/blue colors when
|
|||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export async function load(config: Config | any) {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.face.gender.modelPath)) as unknown as GraphModel;
|
||||
alternative = model.inputs[0].shape ? model.inputs[0]?.shape[3] === 1 : false;
|
||||
|
@ -36,7 +38,7 @@ export async function predict(image: Tensor, config: Config | any) {
|
|||
}
|
||||
skipped = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
if (!model.inputs[0].shape) return;
|
||||
if (!model?.inputs[0].shape) return;
|
||||
const resize = tf.image.resizeBilinear(image, [model.inputs[0].shape[2], model.inputs[0].shape[1]], false);
|
||||
let enhance;
|
||||
if (alternative) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import * as fingerPose from '../fingerpose/fingerpose';
|
|||
import type { HandResult } from '../result';
|
||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
const meshAnnotations = {
|
||||
thumb: [1, 2, 3, 4],
|
||||
|
@ -79,6 +80,10 @@ export async function predict(input: Tensor, config: Config): Promise<HandResult
|
|||
}
|
||||
|
||||
export async function load(config: Config): Promise<[GraphModel | null, GraphModel | null]> {
|
||||
if (env.initial) {
|
||||
handDetectorModel = null;
|
||||
handPoseModel = null;
|
||||
}
|
||||
if (!handDetectorModel || !handPoseModel) {
|
||||
[handDetectorModel, handPoseModel] = await Promise.all([
|
||||
config.hand.enabled ? tf.loadGraphModel(join(config.modelBasePath, config.hand.detector?.modelPath || ''), { fromTFHub: (config.hand.detector?.modelPath || '').includes('tfhub.dev') }) as unknown as GraphModel : null,
|
||||
|
|
14
src/human.ts
14
src/human.ts
|
@ -25,6 +25,7 @@ import * as persons from './persons';
|
|||
import * as interpolate from './interpolate';
|
||||
import * as env from './env';
|
||||
import * as backend from './tfjs/backend';
|
||||
import * as humangl from './tfjs/humangl';
|
||||
import * as app from '../package.json';
|
||||
import * as warmups from './warmup';
|
||||
import type { Tensor, GraphModel } from './tfjs/types';
|
||||
|
@ -152,7 +153,8 @@ export class Human {
|
|||
#numTensors: number;
|
||||
#analyzeMemoryLeaks: boolean;
|
||||
#checkSanity: boolean;
|
||||
initial: boolean;
|
||||
/** WebGL debug info */
|
||||
gl: Record<string, unknown>;
|
||||
// definition end
|
||||
|
||||
/**
|
||||
|
@ -173,7 +175,6 @@ export class Human {
|
|||
this.#numTensors = 0;
|
||||
this.#analyzeMemoryLeaks = false;
|
||||
this.#checkSanity = false;
|
||||
this.initial = true;
|
||||
this.performance = { backend: 0, load: 0, image: 0, frames: 0, cached: 0, changed: 0, total: 0, draw: 0 };
|
||||
this.events = new EventTarget();
|
||||
// object that contains all initialized models
|
||||
|
@ -212,6 +213,8 @@ export class Human {
|
|||
// export raw access to underlying models
|
||||
this.faceTriangulation = facemesh.triangulation;
|
||||
this.faceUVMap = facemesh.uvmap;
|
||||
// set gl info
|
||||
this.gl = humangl.config;
|
||||
// include platform info
|
||||
this.emit('create');
|
||||
}
|
||||
|
@ -303,7 +306,7 @@ export class Human {
|
|||
const count = Object.values(this.models).filter((model) => model).length;
|
||||
if (userConfig) this.config = mergeDeep(this.config, userConfig) as Config;
|
||||
|
||||
if (this.initial) { // print version info on first run and check for correct backend setup
|
||||
if (env.env.initial) { // print version info on first run and check for correct backend setup
|
||||
if (this.config.debug) log(`version: ${this.version}`);
|
||||
if (this.config.debug) log(`tfjs version: ${this.tf.version_core}`);
|
||||
await backend.check(this);
|
||||
|
@ -315,9 +318,8 @@ export class Human {
|
|||
}
|
||||
|
||||
await models.load(this); // actually loads models
|
||||
|
||||
if (this.initial && this.config.debug) log('tf engine state:', this.tf.engine().state.numBytes, 'bytes', this.tf.engine().state.numTensors, 'tensors'); // print memory stats on first run
|
||||
this.initial = false;
|
||||
if (env.env.initial && this.config.debug) log('tf engine state:', this.tf.engine().state.numBytes, 'bytes', this.tf.engine().state.numTensors, 'tensors'); // print memory stats on first run
|
||||
env.env.initial = false;
|
||||
|
||||
const loaded = Object.values(this.models).filter((model) => model).length;
|
||||
if (loaded !== count) { // number of loaded models changed
|
||||
|
|
|
@ -18,7 +18,7 @@ let outCanvas;
|
|||
// @ts-ignore // imagefx is js module that should be converted to a class
|
||||
let fx: fxImage.GLImageFilter | null; // instance of imagefx
|
||||
|
||||
export function canvas(width, height) {
|
||||
export function canvas(width, height): HTMLCanvasElement | OffscreenCanvas {
|
||||
let c;
|
||||
if (env.browser) {
|
||||
if (typeof OffscreenCanvas !== 'undefined') {
|
||||
|
@ -180,9 +180,11 @@ export function process(input: Input, config: Config): { tensor: Tensor | null,
|
|||
} else { // cpu and wasm kernel does not implement efficient fromPixels method
|
||||
// we cant use canvas as-is as it already has a context, so we do a silly one more canvas and do fromPixels on ImageData instead
|
||||
const tempCanvas = canvas(targetWidth, targetHeight);
|
||||
if (!tempCanvas) return { tensor: null, canvas: inCanvas };
|
||||
tempCanvas.width = targetWidth;
|
||||
tempCanvas.height = targetHeight;
|
||||
const tempCtx = tempCanvas.getContext('2d');
|
||||
if (!tempCtx) return { tensor: null, canvas: inCanvas };
|
||||
tempCtx.drawImage(outCanvas, 0, 0);
|
||||
const data = tempCtx.getImageData(0, 0, targetWidth, targetHeight);
|
||||
if (tf.browser && env.browser) {
|
||||
|
|
|
@ -11,13 +11,35 @@ import * as movenet from './movenet/movenet';
|
|||
import * as nanodet from './object/nanodet';
|
||||
import * as centernet from './object/centernet';
|
||||
import * as segmentation from './segmentation/segmentation';
|
||||
import { env } from './env';
|
||||
// import * as agegenderrace from './gear/agegenderrace';
|
||||
|
||||
export function reset(instance) {
|
||||
// if (instance.config.debug) log('resetting loaded models');
|
||||
instance.models = {
|
||||
face: null, // array of models
|
||||
handpose: null, // array of models
|
||||
posenet: null,
|
||||
blazepose: null,
|
||||
efficientpose: null,
|
||||
movenet: null,
|
||||
age: null,
|
||||
gender: null,
|
||||
emotion: null,
|
||||
embedding: null,
|
||||
nanodet: null,
|
||||
centernet: null,
|
||||
faceres: null,
|
||||
segmentation: null,
|
||||
};
|
||||
}
|
||||
|
||||
/** Load method preloads all instance.configured models on-demand
|
||||
* - Not explicitly required as any required model is load implicitly on it's first run
|
||||
* @param userinstance.config?: {@link instance.config}
|
||||
*/
|
||||
export async function load(instance) {
|
||||
if (env.initial) reset(instance);
|
||||
if (instance.config.async) { // load models concurrently
|
||||
[
|
||||
instance.models.face,
|
||||
|
@ -68,17 +90,23 @@ export async function validate(instance) {
|
|||
for (const defined of Object.keys(instance.models)) {
|
||||
if (instance.models[defined]) { // check if model is loaded
|
||||
let models: GraphModel[] = [];
|
||||
if (Array.isArray(instance.models[defined])) models = instance.models[defined].map((model) => (model.executor ? model : model.model));
|
||||
if (Array.isArray(instance.models[defined])) models = instance.models[defined].map((model) => ((model && model.executor) ? model : model.model));
|
||||
else models = [instance.models[defined]];
|
||||
for (const model of models) {
|
||||
if (!model) {
|
||||
if (instance.config.debug) log('model marked as loaded but not defined:', defined);
|
||||
continue;
|
||||
}
|
||||
const ops: string[] = [];
|
||||
// @ts-ignore // executor is a private method
|
||||
const executor = model?.executor;
|
||||
if (executor) {
|
||||
if (executor && executor.graph.nodes) {
|
||||
for (const kernel of Object.values(executor.graph.nodes)) {
|
||||
const op = (kernel as Op).op.toLowerCase();
|
||||
if (!ops.includes(op)) ops.push(op);
|
||||
}
|
||||
} else {
|
||||
if (!executor && instance.config.debug) log('model signature not determined:', defined);
|
||||
}
|
||||
const missing: string[] = [];
|
||||
for (const op of ops) {
|
||||
|
@ -90,10 +118,9 @@ export async function validate(instance) {
|
|||
missing.push(op);
|
||||
}
|
||||
}
|
||||
if (!executor && instance.config.debug) log('model executor not found:', defined);
|
||||
// log('model validation ops:', defined, ops);
|
||||
if (missing.length > 0 && instance.config.debug) log('model validation:', defined, missing);
|
||||
}
|
||||
}
|
||||
}
|
||||
// log.data('ops used by model:', ops);
|
||||
}
|
||||
|
|
|
@ -7,8 +7,9 @@ import * as tf from '../../dist/tfjs.esm.js';
|
|||
import type { BodyResult } from '../result';
|
||||
import type { GraphModel, Tensor } from '../tfjs/types';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
let model: GraphModel | null;
|
||||
|
||||
type Keypoints = { score: number, part: string, position: [number, number], positionRaw: [number, number] };
|
||||
const keypoints: Array<Keypoints> = [];
|
||||
|
@ -22,6 +23,7 @@ let skipped = Number.MAX_SAFE_INTEGER;
|
|||
const bodyParts = ['nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder', 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist', 'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle'];
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);
|
||||
|
@ -122,7 +124,7 @@ export async function predict(image: Tensor, config: Config): Promise<BodyResult
|
|||
skipped = 0;
|
||||
return new Promise(async (resolve) => {
|
||||
const tensor = tf.tidy(() => {
|
||||
if (!model.inputs[0].shape) return null;
|
||||
if (!model?.inputs[0].shape) return null;
|
||||
let inputSize = model.inputs[0].shape[2];
|
||||
if (inputSize === -1) inputSize = 256;
|
||||
const resize = tf.image.resizeBilinear(image, [inputSize, inputSize], false);
|
||||
|
@ -131,7 +133,7 @@ export async function predict(image: Tensor, config: Config): Promise<BodyResult
|
|||
});
|
||||
|
||||
let resT;
|
||||
if (config.body.enabled) resT = await model.predict(tensor);
|
||||
if (config.body.enabled) resT = await model?.predict(tensor);
|
||||
tf.dispose(tensor);
|
||||
|
||||
if (!resT) resolve([]);
|
||||
|
|
|
@ -10,23 +10,24 @@ import type { GraphModel, Tensor } from '../tfjs/types';
|
|||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let model;
|
||||
let model: GraphModel | null;
|
||||
let inputSize = 0;
|
||||
let last: ObjectResult[] = [];
|
||||
let skipped = Number.MAX_SAFE_INTEGER;
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (env.initial) model = null;
|
||||
if (!model) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || ''));
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || '')) as unknown as GraphModel;
|
||||
const inputs = Object.values(model.modelSignature['inputs']);
|
||||
model.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
if (!model.inputSize) throw new Error(`Human: Cannot determine model inputSize: ${config.object.modelPath}`);
|
||||
if (!model || !model.modelUrl) log('load model failed:', config.object.modelPath);
|
||||
else if (config.debug) log('load model:', model.modelUrl);
|
||||
} else if (config.debug) log('cached model:', model.modelUrl);
|
||||
inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : 0;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.object.modelPath);
|
||||
else if (config.debug) log('load model:', model['modelUrl']);
|
||||
} else if (config.debug) log('cached model:', model['modelUrl']);
|
||||
return model;
|
||||
}
|
||||
|
||||
async function process(res: Tensor, inputSize, outputShape, config: Config) {
|
||||
async function process(res: Tensor | null, outputShape, config: Config) {
|
||||
if (!res) return [];
|
||||
const results: Array<ObjectResult> = [];
|
||||
const detections = await res.array();
|
||||
|
@ -81,11 +82,11 @@ export async function predict(input: Tensor, config: Config): Promise<ObjectResu
|
|||
if (!env.kernels.includes('mod') || !env.kernels.includes('sparsetodense')) return last;
|
||||
return new Promise(async (resolve) => {
|
||||
const outputSize = [input.shape[2], input.shape[1]];
|
||||
const resize = tf.image.resizeBilinear(input, [model.inputSize, model.inputSize]);
|
||||
const objectT = config.object.enabled ? model.execute(resize, ['tower_0/detections']) : null;
|
||||
const resize = tf.image.resizeBilinear(input, [inputSize, inputSize]);
|
||||
const objectT = config.object.enabled ? model?.execute(resize, ['tower_0/detections']) as Tensor : null;
|
||||
tf.dispose(resize);
|
||||
|
||||
const obj = await process(objectT, model.inputSize, outputSize, config);
|
||||
const obj = await process(objectT, outputSize, config);
|
||||
last = obj;
|
||||
|
||||
resolve(obj);
|
||||
|
|
|
@ -17,7 +17,7 @@ let skipped = Number.MAX_SAFE_INTEGER;
|
|||
const scaleBox = 2.5; // increase box size
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (!model) {
|
||||
if (!model || env.initial) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.object.modelPath || ''));
|
||||
const inputs = Object.values(model.modelSignature['inputs']);
|
||||
model.inputSize = Array.isArray(inputs) ? parseInt(inputs[0].tensorShape.dim[2].size) : null;
|
||||
|
|
|
@ -9,6 +9,7 @@ import * as util from './utils';
|
|||
import type { BodyResult } from '../result';
|
||||
import type { Tensor, GraphModel } from '../tfjs/types';
|
||||
import type { Config } from '../config';
|
||||
import { env } from '../env';
|
||||
|
||||
let model: GraphModel;
|
||||
const poseNetOutputs = ['MobilenetV1/offset_2/BiasAdd'/* offsets */, 'MobilenetV1/heatmap_2/BiasAdd'/* heatmapScores */, 'MobilenetV1/displacement_fwd_2/BiasAdd'/* displacementFwd */, 'MobilenetV1/displacement_bwd_2/BiasAdd'/* displacementBwd */];
|
||||
|
@ -34,7 +35,7 @@ export async function predict(input: Tensor, config: Config): Promise<BodyResult
|
|||
}
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (!model) {
|
||||
if (!model || env.initial) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.body.modelPath || '')) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.body.modelPath);
|
||||
else if (config.debug) log('load model:', model['modelUrl']);
|
||||
|
|
|
@ -15,7 +15,7 @@ let model: GraphModel;
|
|||
let busy = false;
|
||||
|
||||
export async function load(config: Config): Promise<GraphModel> {
|
||||
if (!model) {
|
||||
if (!model || env.initial) {
|
||||
model = await tf.loadGraphModel(join(config.modelBasePath, config.segmentation.modelPath || '')) as unknown as GraphModel;
|
||||
if (!model || !model['modelUrl']) log('load model failed:', config.segmentation.modelPath);
|
||||
else if (config.debug) log('load model:', model['modelUrl']);
|
||||
|
|
|
@ -4,33 +4,24 @@ import * as env from '../env';
|
|||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
|
||||
export async function check(instance) {
|
||||
if (instance.initial || (instance.config.backend && (instance.config.backend.length > 0) && (tf.getBackend() !== instance.config.backend))) {
|
||||
if (env.env.initial || (instance.config.backend && (instance.config.backend.length > 0) && (tf.getBackend() !== instance.config.backend))) {
|
||||
const timeStamp = now();
|
||||
instance.state = 'backend';
|
||||
/* force backend reload
|
||||
if (instance.config.backend in tf.engine().registry) {
|
||||
const backendFactory = tf.findBackendFactory(instance.config.backend);
|
||||
tf.removeBackend(instance.config.backend);
|
||||
tf.registerBackend(instance.config.backend, backendFactory);
|
||||
} else {
|
||||
log('Backend not registred:', instance.config.backend);
|
||||
}
|
||||
*/
|
||||
|
||||
if (instance.config.backend && instance.config.backend.length > 0) {
|
||||
// detect web worker
|
||||
// @ts-ignore ignore missing type for WorkerGlobalScope as that is the point
|
||||
if (typeof window === 'undefined' && typeof WorkerGlobalScope !== 'undefined' && instance.config.debug) {
|
||||
log('running inside web worker');
|
||||
if (instance.config.debug) log('running inside web worker');
|
||||
}
|
||||
|
||||
// force browser vs node backend
|
||||
if (env.env.browser && instance.config.backend === 'tensorflow') {
|
||||
log('override: backend set to tensorflow while running in browser');
|
||||
if (instance.config.debug) log('override: backend set to tensorflow while running in browser');
|
||||
instance.config.backend = 'humangl';
|
||||
}
|
||||
if (env.env.node && (instance.config.backend === 'webgl' || instance.config.backend === 'humangl')) {
|
||||
log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
if (instance.config.debug) log(`override: backend set to ${instance.config.backend} while running in nodejs`);
|
||||
instance.config.backend = 'tensorflow';
|
||||
}
|
||||
|
||||
|
@ -46,14 +37,14 @@ export async function check(instance) {
|
|||
}
|
||||
|
||||
// check available backends
|
||||
if (instance.config.backend === 'humangl') humangl.register();
|
||||
if (instance.config.backend === 'humangl') await humangl.register(instance);
|
||||
const available = Object.keys(tf.engine().registryFactory);
|
||||
if (instance.config.debug) log('available backends:', available);
|
||||
|
||||
if (!available.includes(instance.config.backend)) {
|
||||
log(`error: backend ${instance.config.backend} not found in registry`);
|
||||
instance.config.backend = env.env.node ? 'tensorflow' : 'humangl';
|
||||
log(`override: setting backend ${instance.config.backend}`);
|
||||
if (instance.config.debug) log(`override: setting backend ${instance.config.backend}`);
|
||||
}
|
||||
|
||||
if (instance.config.debug) log('setting backend:', instance.config.backend);
|
||||
|
@ -79,6 +70,8 @@ export async function check(instance) {
|
|||
}
|
||||
}
|
||||
|
||||
tf.ENV.set('WEBGL_DELETE_TEXTURE_THRESHOLD', 0);
|
||||
|
||||
// handle webgl & humangl
|
||||
if (tf.getBackend() === 'humangl') {
|
||||
tf.ENV.set('CHECK_COMPUTATION_FOR_ERRORS', false);
|
||||
|
|
|
@ -4,16 +4,16 @@
|
|||
*/
|
||||
|
||||
import { log } from '../helpers';
|
||||
import { env } from '../env';
|
||||
import * as models from '../models';
|
||||
import * as tf from '../../dist/tfjs.esm.js';
|
||||
import * as image from '../image/image';
|
||||
|
||||
export const config = {
|
||||
name: 'humangl',
|
||||
priority: 99,
|
||||
priority: 999,
|
||||
canvas: <null | OffscreenCanvas | HTMLCanvasElement>null,
|
||||
gl: <null | WebGL2RenderingContext>null,
|
||||
width: 1024,
|
||||
height: 1024,
|
||||
extensions: <string[]> [],
|
||||
webGLattr: { // https://www.khronos.org/registry/webgl/specs/latest/1.0/#5.2
|
||||
alpha: false,
|
||||
|
@ -43,27 +43,58 @@ function extensions(): void {
|
|||
*
|
||||
* @returns void
|
||||
*/
|
||||
export function register(): void {
|
||||
export async function register(instance): Promise<void> {
|
||||
// force backend reload if gl context is not valid
|
||||
if ((config.name in tf.engine().registry) && (!config.gl || !config.gl.getParameter(config.gl.VERSION))) {
|
||||
log('error: humangl backend invalid context');
|
||||
log('resetting humangl backend');
|
||||
models.reset(instance);
|
||||
await tf.removeBackend(config.name);
|
||||
await register(instance); // re-register
|
||||
}
|
||||
if (!tf.findBackend(config.name)) {
|
||||
// log('backend registration:', config.name);
|
||||
try {
|
||||
config.canvas = image.canvas(100, 100);
|
||||
config.canvas = await image.canvas(100, 100);
|
||||
} catch (err) {
|
||||
log('error: cannot create canvas:', err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
config.gl = config.canvas?.getContext('webgl2', config.webGLattr) as WebGL2RenderingContext;
|
||||
if (config.canvas) {
|
||||
config.canvas.addEventListener('webglcontextlost', async (e) => {
|
||||
const err = config.gl?.getError();
|
||||
log('error: humangl context lost:', err, e);
|
||||
log('gpu memory usage:', instance.tf.engine().backendInstance.numBytesInGPU);
|
||||
log('resetting humangl backend');
|
||||
env.initial = true;
|
||||
models.reset(instance);
|
||||
await tf.removeBackend(config.name);
|
||||
// await register(instance); // re-register
|
||||
});
|
||||
config.canvas.addEventListener('webglcontextrestored', (e) => {
|
||||
log('error: humangl context restored:', e);
|
||||
});
|
||||
config.canvas.addEventListener('webglcontextcreationerror', (e) => {
|
||||
log('error: humangl context create:', e);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
log('error: cannot get WebGL2 context:', err);
|
||||
log('error: cannot get WebGL context:', err);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
tf.setWebGLContext(2, config.gl);
|
||||
} catch (err) {
|
||||
log('error: cannot set WebGL2 context:', err);
|
||||
log('error: cannot set WebGL context:', err);
|
||||
return;
|
||||
}
|
||||
const current = tf.backend().getGPGPUContext().gl;
|
||||
if (current) {
|
||||
log(`humangl webgl version:${current.getParameter(current.VERSION)} renderer:${current.getParameter(current.RENDERER)}`);
|
||||
} else {
|
||||
log('error: no current context:', current, config.gl);
|
||||
}
|
||||
try {
|
||||
const ctx = new tf.GPGPUContext(config.gl);
|
||||
tf.registerBackend(config.name, () => new tf.MathBackendWebGL(ctx), config.priority);
|
||||
|
|
3372
test/build.log
3372
test/build.log
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue