From b47e6251c8f9984a7dfca53e41be88a96889a596 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 22 Nov 2022 10:33:31 -0500 Subject: [PATCH] support dynamic loads --- README.md | 1 + TODO.md | 3 + demo/faceid/index.js | 357 +- demo/faceid/index.js.map | 4 +- demo/facematch/node-match-worker.js | 4 +- demo/facematch/node-match.js | 2 +- demo/nodejs/node-bench.js | 66 + demo/nodejs/node-canvas.js | 3 +- demo/nodejs/node-similarity.js | 3 +- demo/segmentation/index.html | 6 +- demo/segmentation/index.js | 12 +- demo/typescript/index.html | 2 +- demo/typescript/index.js | 98 +- demo/typescript/index.js.map | 6 +- demo/typescript/index.ts | 4 +- dist/human.esm-nobundle.js | 14363 ++++++++++++++++++++++++- dist/human.esm.js | 535 +- dist/human.esm.js.map | 6 +- dist/human.js | 902 +- dist/human.node-gpu.js | 14467 ++++++++++++++++++++++++- dist/human.node-wasm.js | 14469 +++++++++++++++++++++++++- dist/human.node.js | 14467 ++++++++++++++++++++++++- dist/tfjs.esm.js | 22 +- dist/tfjs.version.js | 33 +- samples/in/background.jpg | Bin 0 -> 100118 bytes src/image/image.ts | 3 +- src/tfjs/backend.ts | 2 +- src/util/env.ts | 20 +- src/util/webcam.ts | 4 +- src/warmup.ts | 7 +- test/build.log | 1443 +++ test/node.js | 1 + test/test-node-main.js | 22 +- test/test.log | 1998 ++-- wiki | 2 +- 35 files changed, 61480 insertions(+), 1857 deletions(-) create mode 100644 demo/nodejs/node-bench.js create mode 100644 samples/in/background.jpg diff --git a/README.md b/README.md index a952ec53..aea18d0e 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,7 @@ - **Similarity** [[*Details*]](https://github.com/vladmandic/human/tree/main/demo/nodejs): Compares two input images for similarity of detected faces - **Face Match** [[*Details*]](https://github.com/vladmandic/human/tree/main/demo/facematch): Parallel processing of face **match** in multiple child worker threads - **Multiple Workers** [[*Details*]](https://github.com/vladmandic/human/tree/main/demo/nodejs): Runs multiple parallel `human` by dispaching them to pool of pre-created worker processes +- **Dynamic Load** [[*Details*]](https://github.com/vladmandic/human/tree/main/demo/nodejs): Loads Human dynamically with multiple different desired backends ## Project pages diff --git a/TODO.md b/TODO.md index 39879e1d..2dab37ae 100644 --- a/TODO.md +++ b/TODO.md @@ -68,6 +68,7 @@ Optimizations: Features: - Add [draw label templates](https://github.com/vladmandic/human/wiki/Draw) + Allows easy customization of results labels drawn on canvas - Add `config.filter.autoBrightness` (*enabled by default*) Per-frame video on-the-fly brightness adjustments Which significantly increases performance and precision in poorly lit scenes @@ -94,6 +95,8 @@ Architecture: - Cleanup `@vladmandic/human-models` - Support for **NodeJS v19** - Upgrade to **TypeScript 4.9** +- Support for dynamic module load in **NodeJS** + See Breaking changes: - Replaced `result.face[n].iris` with `result.face[n].distance` diff --git a/demo/faceid/index.js b/demo/faceid/index.js index 635d01de..67a9f377 100644 --- a/demo/faceid/index.js +++ b/demo/faceid/index.js @@ -4,6 +4,359 @@ author: ' */ -import*as S from"../../dist/human.esm.js";var l,F="human",f="person",v=(...a)=>console.log("indexdb",...a);async function h(){return l?!0:new Promise(a=>{let n=indexedDB.open(F,1);n.onerror=o=>v("error:",o),n.onupgradeneeded=o=>{v("create:",o.target),l=o.target.result,l.createObjectStore(f,{keyPath:"id",autoIncrement:!0})},n.onsuccess=o=>{l=o.target.result,v("open:",l),a(!0)}})}async function C(){let a=[];return l||await h(),new Promise(n=>{let o=l.transaction([f],"readwrite").objectStore(f).openCursor(null,"next");o.onerror=i=>v("load error:",i),o.onsuccess=i=>{i.target.result?(a.push(i.target.result.value),i.target.result.continue()):n(a)}})}async function b(){return l||await h(),new Promise(a=>{let n=l.transaction([f],"readwrite").objectStore(f).count();n.onerror=o=>v("count error:",o),n.onsuccess=()=>a(n.result)})}async function x(a){l||await h();let n={name:a.name,descriptor:a.descriptor,image:a.image};l.transaction([f],"readwrite").objectStore(f).put(n),v("save:",n)}async function D(a){l||await h(),l.transaction([f],"readwrite").objectStore(f).delete(a.id),v("delete:",a)}var g={cacheSensitivity:0,modelBasePath:"../../models",filter:{enabled:!0,equalization:!0},debug:!0,face:{enabled:!0,detector:{rotation:!0,return:!0,cropFactor:1.6,mask:!1},description:{enabled:!0},iris:{enabled:!0},emotion:{enabled:!1},antispoof:{enabled:!0},liveness:{enabled:!0}},body:{enabled:!1},hand:{enabled:!1},object:{enabled:!1},gesture:{enabled:!0}},B={order:2,multiplier:25,min:.2,max:.8},r={minConfidence:.6,minSize:224,maxTime:3e4,blinkMin:10,blinkMax:800,threshold:.5,distanceMin:.4,distanceMax:1,mask:g.face.detector.mask,rotation:g.face.detector.rotation,cropFactor:g.face.detector.cropFactor,...B},e={faceCount:{status:!1,val:0},faceConfidence:{status:!1,val:0},facingCenter:{status:!1,val:0},lookingCenter:{status:!1,val:0},blinkDetected:{status:!1,val:0},faceSize:{status:!1,val:0},antispoofCheck:{status:!1,val:0},livenessCheck:{status:!1,val:0},distance:{status:!1,val:0},age:{status:!1,val:0},gender:{status:!1,val:0},timeout:{status:!0,val:0},descriptor:{status:!1,val:0},elapsedMs:{status:void 0,val:0},detectFPS:{status:void 0,val:0},drawFPS:{status:void 0,val:0}},E=()=>e.faceCount.status&&e.faceSize.status&&e.blinkDetected.status&&e.facingCenter.status&&e.lookingCenter.status&&e.faceConfidence.status&&e.antispoofCheck.status&&e.livenessCheck.status&&e.distance.status&&e.descriptor.status&&e.age.status&&e.gender.status,c={face:null,record:null},u={start:0,end:0,time:0},s=new S.Human(g);s.env.perfadd=!1;s.draw.options.font='small-caps 18px "Lato"';s.draw.options.lineHeight=20;var t={video:document.getElementById("video"),canvas:document.getElementById("canvas"),log:document.getElementById("log"),fps:document.getElementById("fps"),match:document.getElementById("match"),name:document.getElementById("name"),save:document.getElementById("save"),delete:document.getElementById("delete"),retry:document.getElementById("retry"),source:document.getElementById("source"),ok:document.getElementById("ok")},y={detect:0,draw:0},I=0,d=(...a)=>{t.log.innerText+=a.join(" ")+` -`,console.log(...a)};async function H(){let a={audio:!1,video:{facingMode:"user",resizeMode:"none",width:{ideal:document.body.clientWidth}}},n=await navigator.mediaDevices.getUserMedia(a),o=new Promise(i=>{t.video.onloadeddata=()=>i(!0)});t.video.srcObject=n,t.video.play(),await o,t.canvas.width=t.video.videoWidth,t.canvas.height=t.video.videoHeight,t.canvas.style.width="50%",t.canvas.style.height="50%",s.env.initial&&d("video:",t.video.videoWidth,t.video.videoHeight,"|",n.getVideoTracks()[0].label),t.canvas.onclick=()=>{t.video.paused?t.video.play():t.video.pause()}}async function T(){var a;if(!t.video.paused){(a=c.face)!=null&&a.tensor&&s.tf.dispose(c.face.tensor),await s.detect(t.video);let n=s.now();e.detectFPS.val=Math.round(1e4/(n-y.detect))/10,y.detect=n,requestAnimationFrame(T)}}function P(){let a=32;for(let[n,o]of Object.entries(e)){let i=document.getElementById(`ok-${n}`);i||(i=document.createElement("div"),i.id=`ok-${n}`,i.innerText=n,i.className="ok",i.style.top=`${a}px`,t.ok.appendChild(i)),typeof o.status=="boolean"&&(i.style.backgroundColor=o.status?"lightgreen":"lightcoral");let m=o.status?"ok":"fail";i.innerText=`${n}: ${o.val===0?m:o.val}`,a+=28}}async function R(){var o;let a=s.next(s.result);s.draw.canvas(t.video,t.canvas),await s.draw.all(t.canvas,a);let n=s.now();if(e.drawFPS.val=Math.round(1e4/(n-y.draw))/10,y.draw=n,e.faceCount.val=s.result.face.length,e.faceCount.status=e.faceCount.val===1,e.faceCount.status){let i=Object.values(s.result.gesture).map(m=>m.gesture);(i.includes("blink left eye")||i.includes("blink right eye"))&&(u.start=s.now()),u.start>0&&!i.includes("blink left eye")&&!i.includes("blink right eye")&&(u.end=s.now()),e.blinkDetected.status=e.blinkDetected.status||Math.abs(u.end-u.start)>r.blinkMin&&Math.abs(u.end-u.start)=r.minConfidence,e.antispoofCheck.val=s.result.face[0].real||0,e.antispoofCheck.status=e.antispoofCheck.val>=r.minConfidence,e.livenessCheck.val=s.result.face[0].live||0,e.livenessCheck.status=e.livenessCheck.val>=r.minConfidence,e.faceSize.val=Math.min(s.result.face[0].box[2],s.result.face[0].box[3]),e.faceSize.status=e.faceSize.val>=r.minSize,e.distance.val=s.result.face[0].distance||0,e.distance.status=e.distance.val>=r.distanceMin&&e.distance.val<=r.distanceMax,e.descriptor.val=((o=s.result.face[0].embedding)==null?void 0:o.length)||0,e.descriptor.status=e.descriptor.val>0,e.age.val=s.result.face[0].age||0,e.age.status=e.age.val>0,e.gender.val=s.result.face[0].genderScore||0,e.gender.status=e.gender.val>=r.minConfidence}return e.timeout.status=e.elapsedMs.val<=r.maxTime,P(),E()||!e.timeout.status?(t.video.pause(),s.result.face[0]):(e.elapsedMs.val=Math.trunc(s.now()-I),new Promise(i=>{setTimeout(async()=>{await R(),i(s.result.face[0])},30)}))}async function z(){var a,n,o,i;if(t.name.value.length>0){let m=(a=t.canvas.getContext("2d"))==null?void 0:a.getImageData(0,0,t.canvas.width,t.canvas.height),p={id:0,name:t.name.value,descriptor:(n=c.face)==null?void 0:n.embedding,image:m};await x(p),d("saved face record:",p.name,"descriptor length:",(i=(o=c.face)==null?void 0:o.embedding)==null?void 0:i.length),d("known face records:",await b())}else d("invalid name")}async function j(){c.record&&c.record.id>0&&await D(c.record)}async function $(){var i,m,p,k;if(t.canvas.style.height="",(i=t.canvas.getContext("2d"))==null||i.clearRect(0,0,r.minSize,r.minSize),!((m=c==null?void 0:c.face)!=null&&m.tensor)||!((p=c==null?void 0:c.face)!=null&&p.embedding))return!1;if(console.log("face record:",c.face),d(`detected face: ${c.face.gender} ${c.face.age||0}y distance ${100*(c.face.distance||0)}cm/${Math.round(100*(c.face.distance||0)/2.54)}in`),await s.tf.browser.toPixels(c.face.tensor,t.canvas),await b()===0)return d("face database is empty: nothing to compare face with"),document.body.style.background="black",t.delete.style.display="none",!1;let a=await C(),n=a.map(w=>w.descriptor).filter(w=>w.length>0),o=s.match.find(c.face.embedding,n,B);return c.record=a[o.index]||null,c.record&&(d(`best match: ${c.record.name} | id: ${c.record.id} | similarity: ${Math.round(1e3*o.similarity)/10}%`),t.name.value=c.record.name,t.source.style.display="",(k=t.source.getContext("2d"))==null||k.putImageData(c.record.image,0,0)),document.body.style.background=o.similarity>r.threshold?"darkgreen":"maroon",o.similarity>r.threshold}async function M(){var a,n,o,i;return e.faceCount.status=!1,e.faceConfidence.status=!1,e.facingCenter.status=!1,e.blinkDetected.status=!1,e.faceSize.status=!1,e.antispoofCheck.status=!1,e.livenessCheck.status=!1,e.age.status=!1,e.gender.status=!1,e.elapsedMs.val=0,t.match.style.display="none",t.retry.style.display="none",t.source.style.display="none",t.canvas.style.height="50%",document.body.style.background="black",await H(),await T(),I=s.now(),c.face=await R(),t.canvas.width=((n=(a=c.face)==null?void 0:a.tensor)==null?void 0:n.shape[1])||r.minSize,t.canvas.height=((i=(o=c.face)==null?void 0:o.tensor)==null?void 0:i.shape[0])||r.minSize,t.source.width=t.canvas.width,t.source.height=t.canvas.height,t.canvas.style.width="",t.match.style.display="flex",t.save.style.display="flex",t.delete.style.display="flex",t.retry.style.display="block",E()?$():(d("did not find valid face"),!1)}async function q(){var a,n;d("human version:",s.version,"| tfjs version:",s.tf.version["tfjs-core"]),d("options:",JSON.stringify(r).replace(/{|}|"|\[|\]/g,"").replace(/,/g," ")),d("initializing webcam..."),await H(),d("loading human models..."),await s.load(),d("initializing human..."),d("face embedding model:",g.face.description.enabled?"faceres":"",(a=g.face.mobilefacenet)!=null&&a.enabled?"mobilefacenet":"",(n=g.face.insightface)!=null&&n.enabled?"insightface":""),d("loading face database..."),d("known face records:",await b()),t.retry.addEventListener("click",M),t.save.addEventListener("click",z),t.delete.addEventListener("click",j),await s.warmup(),await M()}window.onload=q; + +// demo/faceid/index.ts +import * as H from "../../dist/human.esm.js"; + +// demo/faceid/indexdb.ts +var db; +var database = "human"; +var table = "person"; +var log = (...msg) => console.log("indexdb", ...msg); +async function open() { + if (db) + return true; + return new Promise((resolve) => { + const request = indexedDB.open(database, 1); + request.onerror = (evt) => log("error:", evt); + request.onupgradeneeded = (evt) => { + log("create:", evt.target); + db = evt.target.result; + db.createObjectStore(table, { keyPath: "id", autoIncrement: true }); + }; + request.onsuccess = (evt) => { + db = evt.target.result; + log("open:", db); + resolve(true); + }; + }); +} +async function load() { + const faceDB = []; + if (!db) + await open(); + return new Promise((resolve) => { + const cursor = db.transaction([table], "readwrite").objectStore(table).openCursor(null, "next"); + cursor.onerror = (evt) => log("load error:", evt); + cursor.onsuccess = (evt) => { + if (evt.target.result) { + faceDB.push(evt.target.result.value); + evt.target.result.continue(); + } else { + resolve(faceDB); + } + }; + }); +} +async function count() { + if (!db) + await open(); + return new Promise((resolve) => { + const store = db.transaction([table], "readwrite").objectStore(table).count(); + store.onerror = (evt) => log("count error:", evt); + store.onsuccess = () => resolve(store.result); + }); +} +async function save(faceRecord) { + if (!db) + await open(); + const newRecord = { name: faceRecord.name, descriptor: faceRecord.descriptor, image: faceRecord.image }; + db.transaction([table], "readwrite").objectStore(table).put(newRecord); + log("save:", newRecord); +} +async function remove(faceRecord) { + if (!db) + await open(); + db.transaction([table], "readwrite").objectStore(table).delete(faceRecord.id); + log("delete:", faceRecord); +} + +// demo/faceid/index.ts +var humanConfig = { + cacheSensitivity: 0, + modelBasePath: "../../models", + filter: { enabled: true, equalization: true }, + debug: true, + face: { + enabled: true, + detector: { rotation: true, return: true, cropFactor: 1.6, mask: false }, + description: { enabled: true }, + iris: { enabled: true }, + emotion: { enabled: false }, + antispoof: { enabled: true }, + liveness: { enabled: true } + }, + body: { enabled: false }, + hand: { enabled: false }, + object: { enabled: false }, + gesture: { enabled: true } +}; +var matchOptions = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }; +var options = { + minConfidence: 0.6, + minSize: 224, + maxTime: 3e4, + blinkMin: 10, + blinkMax: 800, + threshold: 0.5, + distanceMin: 0.4, + distanceMax: 1, + mask: humanConfig.face.detector.mask, + rotation: humanConfig.face.detector.rotation, + cropFactor: humanConfig.face.detector.cropFactor, + ...matchOptions +}; +var ok = { + faceCount: { status: false, val: 0 }, + faceConfidence: { status: false, val: 0 }, + facingCenter: { status: false, val: 0 }, + lookingCenter: { status: false, val: 0 }, + blinkDetected: { status: false, val: 0 }, + faceSize: { status: false, val: 0 }, + antispoofCheck: { status: false, val: 0 }, + livenessCheck: { status: false, val: 0 }, + distance: { status: false, val: 0 }, + age: { status: false, val: 0 }, + gender: { status: false, val: 0 }, + timeout: { status: true, val: 0 }, + descriptor: { status: false, val: 0 }, + elapsedMs: { status: void 0, val: 0 }, + detectFPS: { status: void 0, val: 0 }, + drawFPS: { status: void 0, val: 0 } +}; +var allOk = () => ok.faceCount.status && ok.faceSize.status && ok.blinkDetected.status && ok.facingCenter.status && ok.lookingCenter.status && ok.faceConfidence.status && ok.antispoofCheck.status && ok.livenessCheck.status && ok.distance.status && ok.descriptor.status && ok.age.status && ok.gender.status; +var current = { face: null, record: null }; +var blink = { + start: 0, + end: 0, + time: 0 +}; +var human = new H.Human(humanConfig); +human.env.perfadd = false; +human.draw.options.font = 'small-caps 18px "Lato"'; +human.draw.options.lineHeight = 20; +var dom = { + video: document.getElementById("video"), + canvas: document.getElementById("canvas"), + log: document.getElementById("log"), + fps: document.getElementById("fps"), + match: document.getElementById("match"), + name: document.getElementById("name"), + save: document.getElementById("save"), + delete: document.getElementById("delete"), + retry: document.getElementById("retry"), + source: document.getElementById("source"), + ok: document.getElementById("ok") +}; +var timestamp = { detect: 0, draw: 0 }; +var startTime = 0; +var log2 = (...msg) => { + dom.log.innerText += msg.join(" ") + "\n"; + console.log(...msg); +}; +async function webCam() { + const cameraOptions = { audio: false, video: { facingMode: "user", resizeMode: "none", width: { ideal: document.body.clientWidth } } }; + const stream = await navigator.mediaDevices.getUserMedia(cameraOptions); + const ready = new Promise((resolve) => { + dom.video.onloadeddata = () => resolve(true); + }); + dom.video.srcObject = stream; + void dom.video.play(); + await ready; + dom.canvas.width = dom.video.videoWidth; + dom.canvas.height = dom.video.videoHeight; + dom.canvas.style.width = "50%"; + dom.canvas.style.height = "50%"; + if (human.env.initial) + log2("video:", dom.video.videoWidth, dom.video.videoHeight, "|", stream.getVideoTracks()[0].label); + dom.canvas.onclick = () => { + if (dom.video.paused) + void dom.video.play(); + else + dom.video.pause(); + }; +} +async function detectionLoop() { + var _a; + if (!dom.video.paused) { + if ((_a = current.face) == null ? void 0 : _a.tensor) + human.tf.dispose(current.face.tensor); + await human.detect(dom.video); + const now = human.now(); + ok.detectFPS.val = Math.round(1e4 / (now - timestamp.detect)) / 10; + timestamp.detect = now; + requestAnimationFrame(detectionLoop); + } +} +function drawValidationTests() { + let y = 32; + for (const [key, val] of Object.entries(ok)) { + let el = document.getElementById(`ok-${key}`); + if (!el) { + el = document.createElement("div"); + el.id = `ok-${key}`; + el.innerText = key; + el.className = "ok"; + el.style.top = `${y}px`; + dom.ok.appendChild(el); + } + if (typeof val.status === "boolean") + el.style.backgroundColor = val.status ? "lightgreen" : "lightcoral"; + const status = val.status ? "ok" : "fail"; + el.innerText = `${key}: ${val.val === 0 ? status : val.val}`; + y += 28; + } +} +async function validationLoop() { + var _a; + const interpolated = human.next(human.result); + human.draw.canvas(dom.video, dom.canvas); + await human.draw.all(dom.canvas, interpolated); + const now = human.now(); + ok.drawFPS.val = Math.round(1e4 / (now - timestamp.draw)) / 10; + timestamp.draw = now; + ok.faceCount.val = human.result.face.length; + ok.faceCount.status = ok.faceCount.val === 1; + if (ok.faceCount.status) { + const gestures = Object.values(human.result.gesture).map((gesture) => gesture.gesture); + if (gestures.includes("blink left eye") || gestures.includes("blink right eye")) + blink.start = human.now(); + if (blink.start > 0 && !gestures.includes("blink left eye") && !gestures.includes("blink right eye")) + blink.end = human.now(); + ok.blinkDetected.status = ok.blinkDetected.status || Math.abs(blink.end - blink.start) > options.blinkMin && Math.abs(blink.end - blink.start) < options.blinkMax; + if (ok.blinkDetected.status && blink.time === 0) + blink.time = Math.trunc(blink.end - blink.start); + ok.facingCenter.status = gestures.includes("facing center"); + ok.lookingCenter.status = gestures.includes("looking center"); + ok.faceConfidence.val = human.result.face[0].faceScore || human.result.face[0].boxScore || 0; + ok.faceConfidence.status = ok.faceConfidence.val >= options.minConfidence; + ok.antispoofCheck.val = human.result.face[0].real || 0; + ok.antispoofCheck.status = ok.antispoofCheck.val >= options.minConfidence; + ok.livenessCheck.val = human.result.face[0].live || 0; + ok.livenessCheck.status = ok.livenessCheck.val >= options.minConfidence; + ok.faceSize.val = Math.min(human.result.face[0].box[2], human.result.face[0].box[3]); + ok.faceSize.status = ok.faceSize.val >= options.minSize; + ok.distance.val = human.result.face[0].distance || 0; + ok.distance.status = ok.distance.val >= options.distanceMin && ok.distance.val <= options.distanceMax; + ok.descriptor.val = ((_a = human.result.face[0].embedding) == null ? void 0 : _a.length) || 0; + ok.descriptor.status = ok.descriptor.val > 0; + ok.age.val = human.result.face[0].age || 0; + ok.age.status = ok.age.val > 0; + ok.gender.val = human.result.face[0].genderScore || 0; + ok.gender.status = ok.gender.val >= options.minConfidence; + } + ok.timeout.status = ok.elapsedMs.val <= options.maxTime; + drawValidationTests(); + if (allOk() || !ok.timeout.status) { + dom.video.pause(); + return human.result.face[0]; + } + ok.elapsedMs.val = Math.trunc(human.now() - startTime); + return new Promise((resolve) => { + setTimeout(async () => { + await validationLoop(); + resolve(human.result.face[0]); + }, 30); + }); +} +async function saveRecords() { + var _a, _b, _c, _d; + if (dom.name.value.length > 0) { + const image = (_a = dom.canvas.getContext("2d")) == null ? void 0 : _a.getImageData(0, 0, dom.canvas.width, dom.canvas.height); + const rec = { id: 0, name: dom.name.value, descriptor: (_b = current.face) == null ? void 0 : _b.embedding, image }; + await save(rec); + log2("saved face record:", rec.name, "descriptor length:", (_d = (_c = current.face) == null ? void 0 : _c.embedding) == null ? void 0 : _d.length); + log2("known face records:", await count()); + } else { + log2("invalid name"); + } +} +async function deleteRecord() { + if (current.record && current.record.id > 0) { + await remove(current.record); + } +} +async function detectFace() { + var _a, _b, _c, _d; + dom.canvas.style.height = ""; + (_a = dom.canvas.getContext("2d")) == null ? void 0 : _a.clearRect(0, 0, options.minSize, options.minSize); + if (!((_b = current == null ? void 0 : current.face) == null ? void 0 : _b.tensor) || !((_c = current == null ? void 0 : current.face) == null ? void 0 : _c.embedding)) + return false; + console.log("face record:", current.face); + log2(`detected face: ${current.face.gender} ${current.face.age || 0}y distance ${100 * (current.face.distance || 0)}cm/${Math.round(100 * (current.face.distance || 0) / 2.54)}in`); + await human.tf.browser.toPixels(current.face.tensor, dom.canvas); + if (await count() === 0) { + log2("face database is empty: nothing to compare face with"); + document.body.style.background = "black"; + dom.delete.style.display = "none"; + return false; + } + const db2 = await load(); + const descriptors = db2.map((rec) => rec.descriptor).filter((desc) => desc.length > 0); + const res = human.match.find(current.face.embedding, descriptors, matchOptions); + current.record = db2[res.index] || null; + if (current.record) { + log2(`best match: ${current.record.name} | id: ${current.record.id} | similarity: ${Math.round(1e3 * res.similarity) / 10}%`); + dom.name.value = current.record.name; + dom.source.style.display = ""; + (_d = dom.source.getContext("2d")) == null ? void 0 : _d.putImageData(current.record.image, 0, 0); + } + document.body.style.background = res.similarity > options.threshold ? "darkgreen" : "maroon"; + return res.similarity > options.threshold; +} +async function main() { + var _a, _b, _c, _d; + ok.faceCount.status = false; + ok.faceConfidence.status = false; + ok.facingCenter.status = false; + ok.blinkDetected.status = false; + ok.faceSize.status = false; + ok.antispoofCheck.status = false; + ok.livenessCheck.status = false; + ok.age.status = false; + ok.gender.status = false; + ok.elapsedMs.val = 0; + dom.match.style.display = "none"; + dom.retry.style.display = "none"; + dom.source.style.display = "none"; + dom.canvas.style.height = "50%"; + document.body.style.background = "black"; + await webCam(); + await detectionLoop(); + startTime = human.now(); + current.face = await validationLoop(); + dom.canvas.width = ((_b = (_a = current.face) == null ? void 0 : _a.tensor) == null ? void 0 : _b.shape[1]) || options.minSize; + dom.canvas.height = ((_d = (_c = current.face) == null ? void 0 : _c.tensor) == null ? void 0 : _d.shape[0]) || options.minSize; + dom.source.width = dom.canvas.width; + dom.source.height = dom.canvas.height; + dom.canvas.style.width = ""; + dom.match.style.display = "flex"; + dom.save.style.display = "flex"; + dom.delete.style.display = "flex"; + dom.retry.style.display = "block"; + if (!allOk()) { + log2("did not find valid face"); + return false; + } + return detectFace(); +} +async function init() { + var _a, _b; + log2("human version:", human.version, "| tfjs version:", human.tf.version["tfjs-core"]); + log2("options:", JSON.stringify(options).replace(/{|}|"|\[|\]/g, "").replace(/,/g, " ")); + log2("initializing webcam..."); + await webCam(); + log2("loading human models..."); + await human.load(); + log2("initializing human..."); + log2("face embedding model:", humanConfig.face.description.enabled ? "faceres" : "", ((_a = humanConfig.face["mobilefacenet"]) == null ? void 0 : _a.enabled) ? "mobilefacenet" : "", ((_b = humanConfig.face["insightface"]) == null ? void 0 : _b.enabled) ? "insightface" : ""); + log2("loading face database..."); + log2("known face records:", await count()); + dom.retry.addEventListener("click", main); + dom.save.addEventListener("click", saveRecords); + dom.delete.addEventListener("click", deleteRecord); + await human.warmup(); + await main(); +} +window.onload = init; //# sourceMappingURL=index.js.map diff --git a/demo/faceid/index.js.map b/demo/faceid/index.js.map index e15df82b..3f5d4efb 100644 --- a/demo/faceid/index.js.map +++ b/demo/faceid/index.js.map @@ -2,6 +2,6 @@ "version": 3, "sources": ["index.ts", "indexdb.ts"], "sourcesContent": ["/**\n * Human demo for browsers\n * @default Human Library\n * @summary \n * @author \n * @copyright \n * @license MIT\n */\n\nimport * as H from '../../dist/human.esm.js'; // equivalent of @vladmandic/Human\nimport * as indexDb from './indexdb'; // methods to deal with indexdb\n\nconst humanConfig = { // user configuration for human, used to fine-tune behavior\n cacheSensitivity: 0,\n modelBasePath: '../../models',\n filter: { enabled: true, equalization: true }, // lets run with histogram equilizer\n debug: true,\n face: {\n enabled: true,\n detector: { rotation: true, return: true, cropFactor: 1.6, mask: false }, // return tensor is used to get detected face image\n description: { enabled: true }, // default model for face descriptor extraction is faceres\n // mobilefacenet: { enabled: true, modelPath: 'https://vladmandic.github.io/human-models/models/mobilefacenet.json' }, // alternative model\n // insightface: { enabled: true, modelPath: 'https://vladmandic.github.io/insightface/models/insightface-mobilenet-swish.json' }, // alternative model\n iris: { enabled: true }, // needed to determine gaze direction\n emotion: { enabled: false }, // not needed\n antispoof: { enabled: true }, // enable optional antispoof module\n liveness: { enabled: true }, // enable optional liveness module\n },\n body: { enabled: false },\n hand: { enabled: false },\n object: { enabled: false },\n gesture: { enabled: true }, // parses face and iris gestures\n};\n\n// const matchOptions = { order: 2, multiplier: 1000, min: 0.0, max: 1.0 }; // for embedding model\nconst matchOptions = { order: 2, multiplier: 25, min: 0.2, max: 0.8 }; // for faceres model\n\nconst options = {\n minConfidence: 0.6, // overal face confidence for box, face, gender, real, live\n minSize: 224, // min input to face descriptor model before degradation\n maxTime: 30000, // max time before giving up\n blinkMin: 10, // minimum duration of a valid blink\n blinkMax: 800, // maximum duration of a valid blink\n threshold: 0.5, // minimum similarity\n distanceMin: 0.4, // closest that face is allowed to be to the cammera in cm\n distanceMax: 1.0, // farthest that face is allowed to be to the cammera in cm\n mask: humanConfig.face.detector.mask,\n rotation: humanConfig.face.detector.rotation,\n cropFactor: humanConfig.face.detector.cropFactor,\n ...matchOptions,\n};\n\nconst ok: Record = { // must meet all rules\n faceCount: { status: false, val: 0 },\n faceConfidence: { status: false, val: 0 },\n facingCenter: { status: false, val: 0 },\n lookingCenter: { status: false, val: 0 },\n blinkDetected: { status: false, val: 0 },\n faceSize: { status: false, val: 0 },\n antispoofCheck: { status: false, val: 0 },\n livenessCheck: { status: false, val: 0 },\n distance: { status: false, val: 0 },\n age: { status: false, val: 0 },\n gender: { status: false, val: 0 },\n timeout: { status: true, val: 0 },\n descriptor: { status: false, val: 0 },\n elapsedMs: { status: undefined, val: 0 }, // total time while waiting for valid face\n detectFPS: { status: undefined, val: 0 }, // mark detection fps performance\n drawFPS: { status: undefined, val: 0 }, // mark redraw fps performance\n};\n\nconst allOk = () => ok.faceCount.status\n && ok.faceSize.status\n && ok.blinkDetected.status\n && ok.facingCenter.status\n && ok.lookingCenter.status\n && ok.faceConfidence.status\n && ok.antispoofCheck.status\n && ok.livenessCheck.status\n && ok.distance.status\n && ok.descriptor.status\n && ok.age.status\n && ok.gender.status;\n\nconst current: { face: H.FaceResult | null, record: indexDb.FaceRecord | null } = { face: null, record: null }; // current face record and matched database record\n\nconst blink = { // internal timers for blink start/end/duration\n start: 0,\n end: 0,\n time: 0,\n};\n\n// let db: Array<{ name: string, source: string, embedding: number[] }> = []; // holds loaded face descriptor database\nconst human = new H.Human(humanConfig); // create instance of human with overrides from user configuration\n\nhuman.env.perfadd = false; // is performance data showing instant or total values\nhuman.draw.options.font = 'small-caps 18px \"Lato\"'; // set font used to draw labels when using draw methods\nhuman.draw.options.lineHeight = 20;\n\nconst dom = { // grab instances of dom objects so we dont have to look them up later\n video: document.getElementById('video') as HTMLVideoElement,\n canvas: document.getElementById('canvas') as HTMLCanvasElement,\n log: document.getElementById('log') as HTMLPreElement,\n fps: document.getElementById('fps') as HTMLPreElement,\n match: document.getElementById('match') as HTMLDivElement,\n name: document.getElementById('name') as HTMLInputElement,\n save: document.getElementById('save') as HTMLSpanElement,\n delete: document.getElementById('delete') as HTMLSpanElement,\n retry: document.getElementById('retry') as HTMLDivElement,\n source: document.getElementById('source') as HTMLCanvasElement,\n ok: document.getElementById('ok') as HTMLDivElement,\n};\nconst timestamp = { detect: 0, draw: 0 }; // holds information used to calculate performance and possible memory leaks\nlet startTime = 0;\n\nconst log = (...msg) => { // helper method to output messages\n dom.log.innerText += msg.join(' ') + '\\n';\n console.log(...msg); // eslint-disable-line no-console\n};\n\nasync function webCam() { // initialize webcam\n // @ts-ignore resizeMode is not yet defined in tslib\n const cameraOptions: MediaStreamConstraints = { audio: false, video: { facingMode: 'user', resizeMode: 'none', width: { ideal: document.body.clientWidth } } };\n const stream: MediaStream = await navigator.mediaDevices.getUserMedia(cameraOptions);\n const ready = new Promise((resolve) => { dom.video.onloadeddata = () => resolve(true); });\n dom.video.srcObject = stream;\n void dom.video.play();\n await ready;\n dom.canvas.width = dom.video.videoWidth;\n dom.canvas.height = dom.video.videoHeight;\n dom.canvas.style.width = '50%';\n dom.canvas.style.height = '50%';\n if (human.env.initial) log('video:', dom.video.videoWidth, dom.video.videoHeight, '|', stream.getVideoTracks()[0].label);\n dom.canvas.onclick = () => { // pause when clicked on screen and resume on next click\n if (dom.video.paused) void dom.video.play();\n else dom.video.pause();\n };\n}\n\nasync function detectionLoop() { // main detection loop\n if (!dom.video.paused) {\n if (current.face?.tensor) human.tf.dispose(current.face.tensor); // dispose previous tensor\n await human.detect(dom.video); // actual detection; were not capturing output in a local variable as it can also be reached via human.result\n const now = human.now();\n ok.detectFPS.val = Math.round(10000 / (now - timestamp.detect)) / 10;\n timestamp.detect = now;\n requestAnimationFrame(detectionLoop); // start new frame immediately\n }\n}\n\nfunction drawValidationTests() {\n let y = 32;\n for (const [key, val] of Object.entries(ok)) {\n let el = document.getElementById(`ok-${key}`);\n if (!el) {\n el = document.createElement('div');\n el.id = `ok-${key}`;\n el.innerText = key;\n el.className = 'ok';\n el.style.top = `${y}px`;\n dom.ok.appendChild(el);\n }\n if (typeof val.status === 'boolean') el.style.backgroundColor = val.status ? 'lightgreen' : 'lightcoral';\n const status = val.status ? 'ok' : 'fail';\n el.innerText = `${key}: ${val.val === 0 ? status : val.val}`;\n y += 28;\n }\n}\n\nasync function validationLoop(): Promise { // main screen refresh loop\n const interpolated = human.next(human.result); // smoothen result using last-known results\n human.draw.canvas(dom.video, dom.canvas); // draw canvas to screen\n await human.draw.all(dom.canvas, interpolated); // draw labels, boxes, lines, etc.\n const now = human.now();\n ok.drawFPS.val = Math.round(10000 / (now - timestamp.draw)) / 10;\n timestamp.draw = now;\n ok.faceCount.val = human.result.face.length;\n ok.faceCount.status = ok.faceCount.val === 1; // must be exactly detected face\n if (ok.faceCount.status) { // skip the rest if no face\n const gestures: string[] = Object.values(human.result.gesture).map((gesture: H.GestureResult) => gesture.gesture); // flatten all gestures\n if (gestures.includes('blink left eye') || gestures.includes('blink right eye')) blink.start = human.now(); // blink starts when eyes get closed\n if (blink.start > 0 && !gestures.includes('blink left eye') && !gestures.includes('blink right eye')) blink.end = human.now(); // if blink started how long until eyes are back open\n ok.blinkDetected.status = ok.blinkDetected.status || (Math.abs(blink.end - blink.start) > options.blinkMin && Math.abs(blink.end - blink.start) < options.blinkMax);\n if (ok.blinkDetected.status && blink.time === 0) blink.time = Math.trunc(blink.end - blink.start);\n ok.facingCenter.status = gestures.includes('facing center');\n ok.lookingCenter.status = gestures.includes('looking center'); // must face camera and look at camera\n ok.faceConfidence.val = human.result.face[0].faceScore || human.result.face[0].boxScore || 0;\n ok.faceConfidence.status = ok.faceConfidence.val >= options.minConfidence;\n ok.antispoofCheck.val = human.result.face[0].real || 0;\n ok.antispoofCheck.status = ok.antispoofCheck.val >= options.minConfidence;\n ok.livenessCheck.val = human.result.face[0].live || 0;\n ok.livenessCheck.status = ok.livenessCheck.val >= options.minConfidence;\n ok.faceSize.val = Math.min(human.result.face[0].box[2], human.result.face[0].box[3]);\n ok.faceSize.status = ok.faceSize.val >= options.minSize;\n ok.distance.val = human.result.face[0].distance || 0;\n ok.distance.status = (ok.distance.val >= options.distanceMin) && (ok.distance.val <= options.distanceMax);\n ok.descriptor.val = human.result.face[0].embedding?.length || 0;\n ok.descriptor.status = ok.descriptor.val > 0;\n ok.age.val = human.result.face[0].age || 0;\n ok.age.status = ok.age.val > 0;\n ok.gender.val = human.result.face[0].genderScore || 0;\n ok.gender.status = ok.gender.val >= options.minConfidence;\n }\n // run again\n ok.timeout.status = ok.elapsedMs.val <= options.maxTime;\n drawValidationTests();\n if (allOk() || !ok.timeout.status) { // all criteria met\n dom.video.pause();\n return human.result.face[0];\n }\n ok.elapsedMs.val = Math.trunc(human.now() - startTime);\n return new Promise((resolve) => {\n setTimeout(async () => {\n await validationLoop(); // run validation loop until conditions are met\n resolve(human.result.face[0]); // recursive promise resolve\n }, 30); // use to slow down refresh from max refresh rate to target of 30 fps\n });\n}\n\nasync function saveRecords() {\n if (dom.name.value.length > 0) {\n const image = dom.canvas.getContext('2d')?.getImageData(0, 0, dom.canvas.width, dom.canvas.height) as ImageData;\n const rec = { id: 0, name: dom.name.value, descriptor: current.face?.embedding as number[], image };\n await indexDb.save(rec);\n log('saved face record:', rec.name, 'descriptor length:', current.face?.embedding?.length);\n log('known face records:', await indexDb.count());\n } else {\n log('invalid name');\n }\n}\n\nasync function deleteRecord() {\n if (current.record && current.record.id > 0) {\n await indexDb.remove(current.record);\n }\n}\n\nasync function detectFace() {\n dom.canvas.style.height = '';\n dom.canvas.getContext('2d')?.clearRect(0, 0, options.minSize, options.minSize);\n if (!current?.face?.tensor || !current?.face?.embedding) return false;\n console.log('face record:', current.face); // eslint-disable-line no-console\n log(`detected face: ${current.face.gender} ${current.face.age || 0}y distance ${100 * (current.face.distance || 0)}cm/${Math.round(100 * (current.face.distance || 0) / 2.54)}in`);\n await human.tf.browser.toPixels(current.face.tensor, dom.canvas);\n if (await indexDb.count() === 0) {\n log('face database is empty: nothing to compare face with');\n document.body.style.background = 'black';\n dom.delete.style.display = 'none';\n return false;\n }\n const db = await indexDb.load();\n const descriptors = db.map((rec) => rec.descriptor).filter((desc) => desc.length > 0);\n const res = human.match.find(current.face.embedding, descriptors, matchOptions);\n current.record = db[res.index] || null;\n if (current.record) {\n log(`best match: ${current.record.name} | id: ${current.record.id} | similarity: ${Math.round(1000 * res.similarity) / 10}%`);\n dom.name.value = current.record.name;\n dom.source.style.display = '';\n dom.source.getContext('2d')?.putImageData(current.record.image, 0, 0);\n }\n document.body.style.background = res.similarity > options.threshold ? 'darkgreen' : 'maroon';\n return res.similarity > options.threshold;\n}\n\nasync function main() { // main entry point\n ok.faceCount.status = false;\n ok.faceConfidence.status = false;\n ok.facingCenter.status = false;\n ok.blinkDetected.status = false;\n ok.faceSize.status = false;\n ok.antispoofCheck.status = false;\n ok.livenessCheck.status = false;\n ok.age.status = false;\n ok.gender.status = false;\n ok.elapsedMs.val = 0;\n dom.match.style.display = 'none';\n dom.retry.style.display = 'none';\n dom.source.style.display = 'none';\n dom.canvas.style.height = '50%';\n document.body.style.background = 'black';\n await webCam();\n await detectionLoop(); // start detection loop\n startTime = human.now();\n current.face = await validationLoop(); // start validation loop\n dom.canvas.width = current.face?.tensor?.shape[1] || options.minSize;\n dom.canvas.height = current.face?.tensor?.shape[0] || options.minSize;\n dom.source.width = dom.canvas.width;\n dom.source.height = dom.canvas.height;\n dom.canvas.style.width = '';\n dom.match.style.display = 'flex';\n dom.save.style.display = 'flex';\n dom.delete.style.display = 'flex';\n dom.retry.style.display = 'block';\n if (!allOk()) { // is all criteria met?\n log('did not find valid face');\n return false;\n }\n return detectFace();\n}\n\nasync function init() {\n log('human version:', human.version, '| tfjs version:', human.tf.version['tfjs-core']);\n log('options:', JSON.stringify(options).replace(/{|}|\"|\\[|\\]/g, '').replace(/,/g, ' '));\n log('initializing webcam...');\n await webCam(); // start webcam\n log('loading human models...');\n await human.load(); // preload all models\n log('initializing human...');\n log('face embedding model:', humanConfig.face.description.enabled ? 'faceres' : '', humanConfig.face['mobilefacenet']?.enabled ? 'mobilefacenet' : '', humanConfig.face['insightface']?.enabled ? 'insightface' : '');\n log('loading face database...');\n log('known face records:', await indexDb.count());\n dom.retry.addEventListener('click', main);\n dom.save.addEventListener('click', saveRecords);\n dom.delete.addEventListener('click', deleteRecord);\n await human.warmup(); // warmup function to initialize backend for future faster detection\n await main();\n}\n\nwindow.onload = init;\n", "let db: IDBDatabase; // instance of indexdb\n\nconst database = 'human';\nconst table = 'person';\n\nexport interface FaceRecord { id: number, name: string, descriptor: number[], image: ImageData }\n\nconst log = (...msg) => console.log('indexdb', ...msg); // eslint-disable-line no-console\n\nexport async function open() {\n if (db) return true;\n return new Promise((resolve) => {\n const request: IDBOpenDBRequest = indexedDB.open(database, 1);\n request.onerror = (evt) => log('error:', evt);\n request.onupgradeneeded = (evt: IDBVersionChangeEvent) => { // create if doesnt exist\n log('create:', evt.target);\n db = (evt.target as IDBOpenDBRequest).result;\n db.createObjectStore(table, { keyPath: 'id', autoIncrement: true });\n };\n request.onsuccess = (evt) => { // open\n db = (evt.target as IDBOpenDBRequest).result;\n log('open:', db);\n resolve(true);\n };\n });\n}\n\nexport async function load(): Promise {\n const faceDB: FaceRecord[] = [];\n if (!db) await open(); // open or create if not already done\n return new Promise((resolve) => {\n const cursor: IDBRequest = db.transaction([table], 'readwrite').objectStore(table).openCursor(null, 'next');\n cursor.onerror = (evt) => log('load error:', evt);\n cursor.onsuccess = (evt) => {\n if ((evt.target as IDBRequest).result) {\n faceDB.push((evt.target as IDBRequest).result.value);\n (evt.target as IDBRequest).result.continue();\n } else {\n resolve(faceDB);\n }\n };\n });\n}\n\nexport async function count(): Promise {\n if (!db) await open(); // open or create if not already done\n return new Promise((resolve) => {\n const store: IDBRequest = db.transaction([table], 'readwrite').objectStore(table).count();\n store.onerror = (evt) => log('count error:', evt);\n store.onsuccess = () => resolve(store.result);\n });\n}\n\nexport async function save(faceRecord: FaceRecord) {\n if (!db) await open(); // open or create if not already done\n const newRecord = { name: faceRecord.name, descriptor: faceRecord.descriptor, image: faceRecord.image }; // omit id as its autoincrement\n db.transaction([table], 'readwrite').objectStore(table).put(newRecord);\n log('save:', newRecord);\n}\n\nexport async function remove(faceRecord: FaceRecord) {\n if (!db) await open(); // open or create if not already done\n db.transaction([table], 'readwrite').objectStore(table).delete(faceRecord.id); // delete based on id\n log('delete:', faceRecord);\n}\n"], - "mappings": "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", - "names": ["H", "db", "database", "table", "log", "msg", "open", "resolve", "request", "evt", "load", "faceDB", "cursor", "count", "store", "save", "faceRecord", "newRecord", "remove", "humanConfig", "matchOptions", "options", "ok", "allOk", "current", "blink", "human", "dom", "timestamp", "startTime", "log", "msg", "webCam", "cameraOptions", "stream", "ready", "resolve", "detectionLoop", "_a", "now", "drawValidationTests", "y", "key", "val", "el", "status", "validationLoop", "interpolated", "gestures", "gesture", "saveRecords", "_b", "_c", "_d", "image", "rec", "save", "count", "deleteRecord", "remove", "detectFace", "db", "load", "descriptors", "desc", "res", "main", "init"] + "mappings": "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", + "names": ["log", "db"] } diff --git a/demo/facematch/node-match-worker.js b/demo/facematch/node-match-worker.js index 2d30ef23..01e5eba7 100644 --- a/demo/facematch/node-match-worker.js +++ b/demo/facematch/node-match-worker.js @@ -61,11 +61,11 @@ threads.parentPort?.on('message', (msg) => { } if (typeof msg.debug !== 'undefined') { // set verbose logging debug = msg.debug; - if (debug) threads.parentPort?.postMessage(`debug: ${debug}`); + // if (debug) threads.parentPort?.postMessage(`debug: ${debug}`); } if (typeof msg.threshold !== 'undefined') { // set minimum similarity threshold threshold = msg.threshold; - if (debug) threads.parentPort?.postMessage(`threshold: ${threshold}`); + // if (debug) threads.parentPort?.postMessage(`threshold: ${threshold}`); } if (typeof msg.shutdown !== 'undefined') { // got message to close worker if (debug) threads.parentPort?.postMessage('shutting down'); diff --git a/demo/facematch/node-match.js b/demo/facematch/node-match.js index 6fa43751..32612ffb 100644 --- a/demo/facematch/node-match.js +++ b/demo/facematch/node-match.js @@ -176,7 +176,7 @@ async function main() { data.requestID++; // increase request id if (testOptions.fuzDescriptors) match(fuzDescriptor(descriptor)); // fuz descriptor for harder match else match(descriptor); - if (options.debug) log.info('submited job', data.requestID); // we already know what we're searching for so we can compare results + if (options.debug) log.debug('submited job', data.requestID); // we already know what we're searching for so we can compare results } log.state('submitted:', { matchJobs: testOptions.maxJobs, poolSize: data.workers.length, activeWorkers: data.workers.filter((worker) => !!worker).length }); } diff --git a/demo/nodejs/node-bench.js b/demo/nodejs/node-bench.js new file mode 100644 index 00000000..e29f7db0 --- /dev/null +++ b/demo/nodejs/node-bench.js @@ -0,0 +1,66 @@ +/** + * Human simple demo for NodeJS + */ + +const childProcess = require('child_process'); // eslint-disable-line camelcase +const log = require('@vladmandic/pilogger'); // eslint-disable-line node/no-unpublished-require +const canvas = require('canvas'); // eslint-disable-line node/no-unpublished-require + +const config = { + cacheSensitivity: 0, + wasmPlatformFetch: true, + modelBasePath: 'https://vladmandic.github.io/human-models/models/', +}; +const count = 10; + +async function loadImage(input) { + const inputImage = await canvas.loadImage(input); + const inputCanvas = new canvas.Canvas(inputImage.width, inputImage.height); + const inputCtx = inputCanvas.getContext('2d'); + inputCtx.drawImage(inputImage, 0, 0); + const imageData = inputCtx.getImageData(0, 0, inputCanvas.width, inputCanvas.height); + process.send({ input, resolution: [inputImage.width, inputImage.height] }); + return imageData; +} + +async function runHuman(module, backend) { + if (backend === 'wasm') require('@tensorflow/tfjs-backend-wasm'); // eslint-disable-line node/no-unpublished-require, global-require + const Human = require('../../dist/' + module); // eslint-disable-line global-require, import/no-dynamic-require + config.backend = backend; + const human = new Human.Human(config); + human.env.Canvas = canvas.Canvas; + human.env.Image = canvas.Image; + human.env.ImageData = canvas.ImageData; + process.send({ human: human.version, module }); + await human.init(); + process.send({ desired: human.config.backend, wasm: human.env.wasm, tfjs: human.tf.version.tfjs, tensorflow: human.env.tensorflow }); + const imageData = await loadImage('samples/in/ai-body.jpg'); + const t0 = human.now(); + await human.load(); + const t1 = human.now(); + await human.warmup(); + const t2 = human.now(); + for (let i = 0; i < count; i++) await human.detect(imageData); + const t3 = human.now(); + process.send({ backend: human.tf.getBackend(), load: Math.round(t1 - t0), warmup: Math.round(t2 - t1), detect: Math.round(t3 - t2), count, memory: human.tf.memory().numBytes }); +} + +async function executeWorker(args) { + return new Promise((resolve) => { + const worker = childProcess.fork(process.argv[1], args); + worker.on('message', (msg) => log.data(msg)); + worker.on('exit', () => resolve(true)); + }); +} + +async function main() { + if (process.argv[2]) { + await runHuman(process.argv[2], process.argv[3]); + } else { + await executeWorker(['human.node.js', 'tensorflow']); + await executeWorker(['human.node-gpu.js', 'tensorflow']); + await executeWorker(['human.node-wasm.js', 'wasm']); + } +} + +main(); diff --git a/demo/nodejs/node-canvas.js b/demo/nodejs/node-canvas.js index 2a49e589..c9a403d0 100644 --- a/demo/nodejs/node-canvas.js +++ b/demo/nodejs/node-canvas.js @@ -40,7 +40,8 @@ async function main() { // parse cmdline const input = process.argv[2]; - const output = process.argv[3]; + let output = process.argv[3]; + if (!output.toLowerCase().endsWith('.jpg')) output += '.jpg'; if (process.argv.length !== 4) log.error('Parameters: missing'); else if (!fs.existsSync(input) && !input.startsWith('http')) log.error(`File not found: ${process.argv[2]}`); else { diff --git a/demo/nodejs/node-similarity.js b/demo/nodejs/node-similarity.js index 902caf7d..f5752daf 100644 --- a/demo/nodejs/node-similarity.js +++ b/demo/nodejs/node-similarity.js @@ -48,7 +48,8 @@ async function main() { log.configure({ inspect: { breakLength: 265 } }); log.header(); if (process.argv.length !== 4) { - throw new Error('Parameters: missing'); + log.error('Parameters: missing'); + return; } await init(); const res1 = await detect(process.argv[2]); diff --git a/demo/segmentation/index.html b/demo/segmentation/index.html index cd26802e..0567d9e5 100644 --- a/demo/segmentation/index.html +++ b/demo/segmentation/index.html @@ -46,9 +46,9 @@
- - - + background + +