From ec8c08c35ef32d81a2d6da61f3a1c1a3aedba853 Mon Sep 17 00:00:00 2001 From: Vladimir Mandic Date: Tue, 9 Mar 2021 13:19:52 -0500 Subject: [PATCH] update --- CHANGELOG.md | 8 ++++++-- README.md | 1 - dist/demo-browser-index.js | 2 +- dist/human.esm-nobundle.js | 2 +- dist/human.esm.js | 2 +- dist/human.node-gpu.js | 2 +- dist/human.node.js | 2 +- dist/human.ts | 2 +- 8 files changed, 12 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e4f01a5c..3c4d3169 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # @vladmandic/human -Version: **1.0.0** +Version: **1.0.1** Description: **Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition** Author: **Vladimir Mandic ** @@ -9,8 +9,12 @@ Repository: **** ## Changelog -### **HEAD -> main** 2021/03/08 mandic00@live.com +### **HEAD -> main** 2021/03/09 mandic00@live.com + +### **1.0.1** 2021/03/09 mandic00@live.com + +- fix for face detector when mesh is disabled - optimize for npm ### **0.40.9** 2021/03/08 mandic00@live.com diff --git a/README.md b/README.md index e029c680..759e6b08 100644 --- a/README.md +++ b/README.md @@ -148,4 +148,3 @@ detectVideo(); ![Downloads](https://img.shields.io/npm/dm/@vladmandic/human?style=flat-square) ![Stars](https://img.shields.io/github/stars/vladmandic/human?style=flat-square) ![Code Size](https://img.shields.io/github/languages/code-size/vladmandic/human?style=flat-square) -![Commit Activity](https://img.shields.io/github/commit-activity/m/vladmandic/human?style=flat-square) diff --git a/dist/demo-browser-index.js b/dist/demo-browser-index.js index 6ce5f2c4..69338564 100644 --- a/dist/demo-browser-index.js +++ b/dist/demo-browser-index.js @@ -4771,7 +4771,7 @@ AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ -2Q==`,r6={};er(r6,{author:()=>h6,browser:()=>u6,bugs:()=>d6,default:()=>Pae,description:()=>s6,devDependencies:()=>g6,engines:()=>m6,homepage:()=>p6,keywords:()=>w6,license:()=>f6,main:()=>o6,module:()=>l6,name:()=>a6,peerDependencies:()=>y6,repository:()=>A6,scripts:()=>x6,sideEffects:()=>i6,types:()=>c6,version:()=>S2});var a6="@vladmandic/human",S2="1.0.0",s6="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",i6=!1,o6="dist/human.node.js",l6="dist/human.esm.js",u6="dist/human.esm.js",c6="types/human.d.ts",h6="Vladimir Mandic ",d6={url:"https://github.com/vladmandic/human/issues"},p6="https://vladmandic.github.io/human/demo/index.html",f6="MIT",m6={node:">=12.0.0"},A6={type:"git",url:"git+https://github.com/vladmandic/human.git"},y6={},g6={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},x6={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},w6=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Pae={name:a6,version:S2,description:s6,sideEffects:i6,main:o6,module:l6,browser:u6,types:c6,author:h6,bugs:d6,homepage:p6,license:f6,engines:m6,repository:A6,peerDependencies:y6,devDependencies:g6,scripts:x6,keywords:w6},b6={};er(b6,{all:()=>Bae,body:()=>k6,canvas:()=>Wae,face:()=>v6,gesture:()=>_6,hand:()=>I6,options:()=>de});var de={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function a1(e,t,n){e.fillStyle=de.color,e.beginPath(),e.arc(t,n,de.pointSize,0,2*Math.PI),e.fill()}function N6(e,t,n,r,a){if(e.beginPath(),de.useCurves){let s=(t+t+r)/2,i=(n+n+a)/2;e.ellipse(s,i,r/2,a/2,0,0,2*Math.PI)}else e.lineWidth=de.lineWidth,e.moveTo(t+de.roundRect,n),e.lineTo(t+r-de.roundRect,n),e.quadraticCurveTo(t+r,n,t+r,n+de.roundRect),e.lineTo(t+r,n+a-de.roundRect),e.quadraticCurveTo(t+r,n+a,t+r-de.roundRect,n+a),e.lineTo(t+de.roundRect,n+a),e.quadraticCurveTo(t,n+a,t,n+a-de.roundRect),e.lineTo(t,n+de.roundRect),e.quadraticCurveTo(t,n,t+de.roundRect,n),e.closePath();e.stroke()}function T2(e,t=[]){if(!(t===void 0||t.length===0)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.lineTo(n[0],parseInt(n[1]));e.stroke(),de.fillPolygons&&(e.closePath(),e.fill())}}function s1(e,t=[]){if(!(t===void 0||t.length===0)){if(!de.useCurves||t.length<=2){T2(e,t);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;n1&&i[1].length>0){let o=s[1]>0?`#${s[1]}`:"",l=`${s[0]} ${o}: ${i[1]}`;de.shadowColor&&de.shadowColor!==""&&(n.fillStyle=de.shadowColor,n.fillText(l,8,2+r*de.lineHeight)),n.fillStyle=de.labelColor,n.fillText(l,6,0+r*de.lineHeight),r+=1}}}async function v6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(n)for(let r of t){n.font=de.font,n.strokeStyle=de.color,n.fillStyle=de.color,de.drawBoxes&&N6(n,r.box[0],r.box[1],r.box[2],r.box[3]);let a=[];if(a.push(`face confidence: ${Math.trunc(100*r.confidence)}%`),r.genderConfidence&&a.push(`${r.gender||""} ${Math.trunc(100*r.genderConfidence)}% confident`),r.age&&a.push(`age: ${r.age||""}`),r.iris&&a.push(`iris distance: ${r.iris}`),r.emotion&&r.emotion.length>0){let s=r.emotion.map(i=>`${Math.trunc(100*i.score)}% ${i.emotion}`);a.push(s.join(" "))}r.angle&&r.angle.roll&&a.push(`roll: ${Math.trunc(100*r.angle.roll)/100} yaw:${Math.trunc(100*r.angle.yaw)/100} pitch:${Math.trunc(100*r.angle.pitch)/100}`),a.length===0&&a.push("face"),n.fillStyle=de.color;for(let s=a.length-1;s>=0;s--){let i=Math.max(r.box[0],0),o=s*de.lineHeight+r.box[1];de.shadowColor&&de.shadowColor!==""&&(n.fillStyle=de.shadowColor,n.fillText(a[s],i+5,o+16)),n.fillStyle=de.labelColor,n.fillText(a[s],i+4,o+15)}if(n.lineWidth=1,r.mesh){if(de.drawPoints)for(let s of r.mesh)n.fillStyle=de.useDepth?`rgba(${127.5+2*s[2]}, ${127.5-2*s[2]}, 255, 0.5)`:de.color,a1(n,s[0],s[1]);if(de.drawPolygons){for(let s=0;sr.mesh[o]);n.strokeStyle=de.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:de.color,n.fillStyle=de.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:de.color,n.lineWidth=1,T2(n,i)}if(r.annotations&&r.annotations.leftEyeIris){n.strokeStyle=de.useDepth?"rgba(255, 200, 255, 0.3)":de.color,n.beginPath();let s=Math.abs(r.annotations.leftEyeIris[3][0]-r.annotations.leftEyeIris[1][0])/2,i=Math.abs(r.annotations.leftEyeIris[4][1]-r.annotations.leftEyeIris[2][1])/2;n.ellipse(r.annotations.leftEyeIris[0][0],r.annotations.leftEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),de.fillPolygons&&(n.fillStyle=de.useDepth?"rgba(255, 255, 200, 0.3)":de.color,n.fill())}if(r.annotations&&r.annotations.rightEyeIris){n.strokeStyle=de.useDepth?"rgba(255, 200, 255, 0.3)":de.color,n.beginPath();let s=Math.abs(r.annotations.rightEyeIris[3][0]-r.annotations.rightEyeIris[1][0])/2,i=Math.abs(r.annotations.rightEyeIris[4][1]-r.annotations.rightEyeIris[2][1])/2;n.ellipse(r.annotations.rightEyeIris[0][0],r.annotations.rightEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),de.fillPolygons&&(n.fillStyle=de.useDepth?"rgba(255, 255, 200, 0.3)":de.color,n.fill())}}}}}var Ga=[];async function k6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(n){n.lineJoin="round";for(let r=0;ri.part==="leftShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s.length===5&&T2(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftKnee"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftAnkle"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHeel"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftFoot"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightKnee"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightAnkle"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHeel"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightFoot"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftElbow"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftWrist"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftPalm"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightElbow"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightWrist"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightPalm"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s)}}}}async function I6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(n){n.lineJoin="round",n.font=de.font;for(let r of t){if(de.drawBoxes&&(n.strokeStyle=de.color,n.fillStyle=de.color,N6(n,r.box[0],r.box[1],r.box[2],r.box[3]),de.shadowColor&&de.shadowColor!==""&&(n.fillStyle=de.shadowColor,n.fillText("hand",r.box[0]+3,1+r.box[1]+de.lineHeight,r.box[2])),n.fillStyle=de.labelColor,n.fillText("hand",r.box[0]+2,0+r.box[1]+de.lineHeight,r.box[2]),n.stroke()),de.drawPoints&&r.landmarks&&r.landmarks.length>0)for(let a of r.landmarks)n.fillStyle=de.useDepth?`rgba(${127.5+2*a[2]}, ${127.5-2*a[2]}, 255, 0.5)`:de.color,a1(n,a[0],a[1]);if(de.drawPolygons){let a=s=>{if(s)for(let i=0;i0?i-1:0][0],s[i>0?i-1:0][1]),n.lineTo(s[i][0],s[i][1]),n.stroke()};a(r.annotations.indexFinger),a(r.annotations.middleFinger),a(r.annotations.ringFinger),a(r.annotations.pinky),a(r.annotations.thumb)}}}}async function Wae(e,t){if(!e||!t||!(e instanceof HTMLCanvasElement)||!(t instanceof HTMLCanvasElement))return;let n=e.getContext("2d");n==null||n.drawImage(e,0,0)}async function Bae(e,t){!t||!e||e instanceof HTMLCanvasElement&&(v6(e,t.face),k6(e,t.body),I6(e,t.hand),_6(e,t.gesture))}var dt=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function Fc(...e){let t=n=>n&&typeof n=="object";return e.reduce((n,r)=>(Object.keys(r||{}).forEach(a=>{let s=n[a],i=r[a];Array.isArray(s)&&Array.isArray(i)?n[a]=s.concat(...i):t(s)&&t(i)?n[a]=Fc(s,i):n[a]=i}),n),{})}var S6=class{constructor(e={}){this.calculateFaceAngle=t=>{if(!t||t.length<300)return{};let n=(a,s,i,o)=>Math.atan2(o-s,i-a),r=a=>Math.abs(a*180/Math.PI%360);return{roll:n(t[33][0],t[33][1],t[263][0],t[263][1]),yaw:n(t[33][0],t[33][2],t[263][0],t[263][2]),pitch:n(t[10][1],t[10][2],t[152][1],t[152][2])}},this.tf=V2,this.draw=b6,this.package=r6,this.version=S2,this.config=Fc(Nt,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>n6(t,this.config),this.facemesh=Iv,this.age=Ev,this.gender=Cv,this.emotion=Rv,this.body=this.config.body.modelType.startsWith("posenet")?Dv:t6,this.hand=qv,this.sysinfo=O4()}profile(){return this.config.profile?Tv:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,n=this.numTensors;this.numTensors=t;let r=t-n;r!==0&&Le(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?jre(e,t):0}async load(e=null){this.state="load";let t=dt();e&&(this.config=Fc(this.config,e)),this.firstRun&&(this.config.debug&&Le(`version: ${this.version}`),this.config.debug&&Le(`tfjs version: ${this.tf.version_core}`),this.config.debug&&Le("platform:",this.sysinfo.platform),this.config.debug&&Le("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&Le("configuration:",this.config),this.config.debug&&Le("tf flags:",this.tf.ENV.flags)));let n=this.config.face.detector.modelPath.includes("faceboxes")?Nv:Iv;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?n.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?n2(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?a2(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?u2(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?$v(this.config):null),this.models.handpose||(this.config.hand.enabled?g2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?p2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?v2(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await n.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await n2(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await a2(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await u2(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await $v(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await g2(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await p2(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await v2(this.config))),this.firstRun&&(this.config.debug&&Le("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(dt()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=dt();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&Le("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&Le("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let n=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&Le(`wasm execution: ${n?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),n||Le("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&wre();try{await this.tf.setBackend(this.config.backend)}catch(n){Le("error: cannot set backend:",this.config.backend,n)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(Le("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let n=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&Le(`gl version:${n.getParameter(n.VERSION)} renderer:${n.getParameter(n.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(dt()-t)}}async detectFace(e){var t,n,r,a,s,i;let o,l,u,c,h,d=[];this.state="run:face",o=dt();let p=await((t=this.models.face)==null?void 0:t.estimateFaces(e,this.config));this.perf.face=Math.trunc(dt()-o);for(let f of p){if(this.analyze("Get Face"),!f.image||f.image.isDisposedInternal){Le("Face object is disposed:",f.image);continue}let m=this.calculateFaceAngle(f.mesh);this.analyze("Start Age:"),this.config.async?l=this.config.face.age.enabled?r2(f.image,this.config):{}:(this.state="run:age",o=dt(),l=this.config.face.age.enabled?await r2(f.image,this.config):{},this.perf.age=Math.trunc(dt()-o)),this.analyze("Start Gender:"),this.config.async?u=this.config.face.gender.enabled?s2(f.image,this.config):{}:(this.state="run:gender",o=dt(),u=this.config.face.gender.enabled?await s2(f.image,this.config):{},this.perf.gender=Math.trunc(dt()-o)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?c2(f.image,this.config):{}:(this.state="run:emotion",o=dt(),c=this.config.face.emotion.enabled?await c2(f.image,this.config):{},this.perf.emotion=Math.trunc(dt()-o)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?h=this.config.face.embedding.enabled?Mv(f.image,this.config):[]:(this.state="run:embedding",o=dt(),h=this.config.face.embedding.enabled?await Mv(f.image,this.config):[],this.perf.embedding=Math.trunc(dt()-o)),this.analyze("End Emotion:"),this.config.async&&([l,u,c,h]=await Promise.all([l,u,c,h])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((n=f==null?void 0:f.annotations)==null?void 0:n.leftEyeIris)&&((r=f==null?void 0:f.annotations)==null?void 0:r.rightEyeIris)&&(delete f.annotations.leftEyeIris,delete f.annotations.rightEyeIris);let A=((a=f.annotations)==null?void 0:a.leftEyeIris)&&((s=f.annotations)==null?void 0:s.rightEyeIris)?11.7*Math.max(Math.abs(f.annotations.leftEyeIris[3][0]-f.annotations.leftEyeIris[1][0]),Math.abs(f.annotations.rightEyeIris[4][1]-f.annotations.rightEyeIris[2][1])):0;d.push({confidence:f.confidence,faceConfidence:f.faceConfidence,boxConfidence:f.boxConfidence,box:f.box,mesh:f.mesh,boxRaw:f.boxRaw,meshRaw:f.meshRaw,annotations:f.annotations,age:l.age,gender:u.gender,genderConfidence:u.confidence,emotion:c,embedding:h,iris:A!==0?Math.trunc(A)/100:0,angle:m}),(i=f.image)==null||i.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),d}async detect(e,t={}){return new Promise(async n=>{var r,a,s,i;this.state="config";let o;this.config=Fc(this.config,t),this.state="check";let l=this.sanity(e);l&&(Le(l,e),n({error:l}));let u=dt();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),o=dt();let c=n6(e,this.config);if(!c||!c.tensor){Le("could not convert input to tensor"),n({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(dt()-o),this.analyze("Get Image:");let h,d,p;this.config.async?(p=this.config.face.enabled?this.detectFace(c.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",o=dt(),p=this.config.face.enabled?await this.detectFace(c.tensor):[],this.perf.face=Math.trunc(dt()-o)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?h=this.config.body.enabled?(r=this.models.posenet)==null?void 0:r.estimatePoses(c.tensor,this.config):[]:h=this.config.body.enabled?k2(c.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",o=dt(),this.config.body.modelType.startsWith("posenet")?h=this.config.body.enabled?await((a=this.models.posenet)==null?void 0:a.estimatePoses(c.tensor,this.config)):[]:h=this.config.body.enabled?await k2(c.tensor,this.config):[],this.perf.body=Math.trunc(dt()-o)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(d=this.config.hand.enabled?(s=this.models.handpose)==null?void 0:s.estimateHands(c.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",o=dt(),d=this.config.hand.enabled?await((i=this.models.handpose)==null?void 0:i.estimateHands(c.tensor,this.config)):[],this.perf.hand=Math.trunc(dt()-o)),this.analyze("End Hand:"),this.config.async&&([p,h,d]=await Promise.all([p,h,d])),c.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let f=[];this.config.gesture.enabled&&(o=dt(),f=[...Mae(p),...$ae(h),...Oae(d),...Dae(p)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(dt()-o)),this.perf.total=Math.trunc(dt()-u),this.state="idle",n({face:p,body:h,hand:d,gesture:f,performance:this.perf,canvas:c.canvas})})}async warmupBitmap(){let e=(r,a="application/octet-stream")=>fetch(`data:${a};base64,${r}`).then(s=>s.blob()),t,n;switch(this.config.warmup){case"face":t=await e(I2);break;case"full":t=await e(N2);break;default:t=null}if(t){let r=await createImageBitmap(t);n=await this.detect(r,this.config),r.close()}return n}async warmupCanvas(){return new Promise(e=>{let t,n=0;switch(this.config.warmup){case"face":n=256,t="data:image/jpeg;base64,"+I2;break;case"full":case"body":n=1200,t="data:image/jpeg;base64,"+N2;break;default:t=null}let r=new Image;r.onload=async()=>{let a=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(n,n):document.createElement("canvas");a.width=r.naturalWidth,a.height=r.naturalHeight;let s=a.getContext("2d");s==null||s.drawImage(r,0,0);let i=await this.detect(a,this.config);e(i)},t?r.src=t:e(null)})}async warmupNode(){let e=s=>Buffer.from(s,"base64"),t=this.config.warmup==="face"?e(I2):e(N2),n=(void 0).decodeJpeg(t),r=n.expandDims(0);this.tf.dispose(n);let a=await this.detect(r,this.config);return this.tf.dispose(r),a}async warmup(e){let t=dt();e&&(this.config=Fc(this.config,e));let n=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=n;let a=dt();return this.config.debug&&Le("Warmup",this.config.warmup,Math.round(a-t),"ms",r),r}};var $c=0,T6=!1,wt={background:"darkslategray",hover:"lightgray",itemBackground:"black",itemColor:"white",buttonBackground:"lightblue",buttonHover:"lightgreen",checkboxOn:"lightgreen",checkboxOff:"lightcoral",rangeBackground:"lightblue",rangeLabel:"white",chartColor:"lightblue"};function Vae(){if(T6)return;let e=` +2Q==`,r6={};er(r6,{author:()=>h6,browser:()=>u6,bugs:()=>d6,default:()=>Pae,description:()=>s6,devDependencies:()=>g6,engines:()=>m6,homepage:()=>p6,keywords:()=>w6,license:()=>f6,main:()=>o6,module:()=>l6,name:()=>a6,peerDependencies:()=>y6,repository:()=>A6,scripts:()=>x6,sideEffects:()=>i6,types:()=>c6,version:()=>S2});var a6="@vladmandic/human",S2="1.0.1",s6="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",i6=!1,o6="dist/human.node.js",l6="dist/human.esm.js",u6="dist/human.esm.js",c6="types/human.d.ts",h6="Vladimir Mandic ",d6={url:"https://github.com/vladmandic/human/issues"},p6="https://vladmandic.github.io/human/demo/index.html",f6="MIT",m6={node:">=12.0.0"},A6={type:"git",url:"git+https://github.com/vladmandic/human.git"},y6={},g6={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},x6={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},w6=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Pae={name:a6,version:S2,description:s6,sideEffects:i6,main:o6,module:l6,browser:u6,types:c6,author:h6,bugs:d6,homepage:p6,license:f6,engines:m6,repository:A6,peerDependencies:y6,devDependencies:g6,scripts:x6,keywords:w6},b6={};er(b6,{all:()=>Bae,body:()=>k6,canvas:()=>Wae,face:()=>v6,gesture:()=>_6,hand:()=>I6,options:()=>de});var de={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function a1(e,t,n){e.fillStyle=de.color,e.beginPath(),e.arc(t,n,de.pointSize,0,2*Math.PI),e.fill()}function N6(e,t,n,r,a){if(e.beginPath(),de.useCurves){let s=(t+t+r)/2,i=(n+n+a)/2;e.ellipse(s,i,r/2,a/2,0,0,2*Math.PI)}else e.lineWidth=de.lineWidth,e.moveTo(t+de.roundRect,n),e.lineTo(t+r-de.roundRect,n),e.quadraticCurveTo(t+r,n,t+r,n+de.roundRect),e.lineTo(t+r,n+a-de.roundRect),e.quadraticCurveTo(t+r,n+a,t+r-de.roundRect,n+a),e.lineTo(t+de.roundRect,n+a),e.quadraticCurveTo(t,n+a,t,n+a-de.roundRect),e.lineTo(t,n+de.roundRect),e.quadraticCurveTo(t,n,t+de.roundRect,n),e.closePath();e.stroke()}function T2(e,t=[]){if(!(t===void 0||t.length===0)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.lineTo(n[0],parseInt(n[1]));e.stroke(),de.fillPolygons&&(e.closePath(),e.fill())}}function s1(e,t=[]){if(!(t===void 0||t.length===0)){if(!de.useCurves||t.length<=2){T2(e,t);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;n1&&i[1].length>0){let o=s[1]>0?`#${s[1]}`:"",l=`${s[0]} ${o}: ${i[1]}`;de.shadowColor&&de.shadowColor!==""&&(n.fillStyle=de.shadowColor,n.fillText(l,8,2+r*de.lineHeight)),n.fillStyle=de.labelColor,n.fillText(l,6,0+r*de.lineHeight),r+=1}}}async function v6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(n)for(let r of t){n.font=de.font,n.strokeStyle=de.color,n.fillStyle=de.color,de.drawBoxes&&N6(n,r.box[0],r.box[1],r.box[2],r.box[3]);let a=[];if(a.push(`face confidence: ${Math.trunc(100*r.confidence)}%`),r.genderConfidence&&a.push(`${r.gender||""} ${Math.trunc(100*r.genderConfidence)}% confident`),r.age&&a.push(`age: ${r.age||""}`),r.iris&&a.push(`iris distance: ${r.iris}`),r.emotion&&r.emotion.length>0){let s=r.emotion.map(i=>`${Math.trunc(100*i.score)}% ${i.emotion}`);a.push(s.join(" "))}r.angle&&r.angle.roll&&a.push(`roll: ${Math.trunc(100*r.angle.roll)/100} yaw:${Math.trunc(100*r.angle.yaw)/100} pitch:${Math.trunc(100*r.angle.pitch)/100}`),a.length===0&&a.push("face"),n.fillStyle=de.color;for(let s=a.length-1;s>=0;s--){let i=Math.max(r.box[0],0),o=s*de.lineHeight+r.box[1];de.shadowColor&&de.shadowColor!==""&&(n.fillStyle=de.shadowColor,n.fillText(a[s],i+5,o+16)),n.fillStyle=de.labelColor,n.fillText(a[s],i+4,o+15)}if(n.lineWidth=1,r.mesh){if(de.drawPoints)for(let s of r.mesh)n.fillStyle=de.useDepth?`rgba(${127.5+2*s[2]}, ${127.5-2*s[2]}, 255, 0.5)`:de.color,a1(n,s[0],s[1]);if(de.drawPolygons){for(let s=0;sr.mesh[o]);n.strokeStyle=de.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:de.color,n.fillStyle=de.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:de.color,n.lineWidth=1,T2(n,i)}if(r.annotations&&r.annotations.leftEyeIris){n.strokeStyle=de.useDepth?"rgba(255, 200, 255, 0.3)":de.color,n.beginPath();let s=Math.abs(r.annotations.leftEyeIris[3][0]-r.annotations.leftEyeIris[1][0])/2,i=Math.abs(r.annotations.leftEyeIris[4][1]-r.annotations.leftEyeIris[2][1])/2;n.ellipse(r.annotations.leftEyeIris[0][0],r.annotations.leftEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),de.fillPolygons&&(n.fillStyle=de.useDepth?"rgba(255, 255, 200, 0.3)":de.color,n.fill())}if(r.annotations&&r.annotations.rightEyeIris){n.strokeStyle=de.useDepth?"rgba(255, 200, 255, 0.3)":de.color,n.beginPath();let s=Math.abs(r.annotations.rightEyeIris[3][0]-r.annotations.rightEyeIris[1][0])/2,i=Math.abs(r.annotations.rightEyeIris[4][1]-r.annotations.rightEyeIris[2][1])/2;n.ellipse(r.annotations.rightEyeIris[0][0],r.annotations.rightEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),de.fillPolygons&&(n.fillStyle=de.useDepth?"rgba(255, 255, 200, 0.3)":de.color,n.fill())}}}}}var Ga=[];async function k6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(n){n.lineJoin="round";for(let r=0;ri.part==="leftShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s.length===5&&T2(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftKnee"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftAnkle"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHeel"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftFoot"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightKnee"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightAnkle"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHeel"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightFoot"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftElbow"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftWrist"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftPalm"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightElbow"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightWrist"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightPalm"),a&&a.score>Nt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s1(n,s)}}}}async function I6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(n){n.lineJoin="round",n.font=de.font;for(let r of t){if(de.drawBoxes&&(n.strokeStyle=de.color,n.fillStyle=de.color,N6(n,r.box[0],r.box[1],r.box[2],r.box[3]),de.shadowColor&&de.shadowColor!==""&&(n.fillStyle=de.shadowColor,n.fillText("hand",r.box[0]+3,1+r.box[1]+de.lineHeight,r.box[2])),n.fillStyle=de.labelColor,n.fillText("hand",r.box[0]+2,0+r.box[1]+de.lineHeight,r.box[2]),n.stroke()),de.drawPoints&&r.landmarks&&r.landmarks.length>0)for(let a of r.landmarks)n.fillStyle=de.useDepth?`rgba(${127.5+2*a[2]}, ${127.5-2*a[2]}, 255, 0.5)`:de.color,a1(n,a[0],a[1]);if(de.drawPolygons){let a=s=>{if(s)for(let i=0;i0?i-1:0][0],s[i>0?i-1:0][1]),n.lineTo(s[i][0],s[i][1]),n.stroke()};a(r.annotations.indexFinger),a(r.annotations.middleFinger),a(r.annotations.ringFinger),a(r.annotations.pinky),a(r.annotations.thumb)}}}}async function Wae(e,t){if(!e||!t||!(e instanceof HTMLCanvasElement)||!(t instanceof HTMLCanvasElement))return;let n=e.getContext("2d");n==null||n.drawImage(e,0,0)}async function Bae(e,t){!t||!e||e instanceof HTMLCanvasElement&&(v6(e,t.face),k6(e,t.body),I6(e,t.hand),_6(e,t.gesture))}var dt=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function Fc(...e){let t=n=>n&&typeof n=="object";return e.reduce((n,r)=>(Object.keys(r||{}).forEach(a=>{let s=n[a],i=r[a];Array.isArray(s)&&Array.isArray(i)?n[a]=s.concat(...i):t(s)&&t(i)?n[a]=Fc(s,i):n[a]=i}),n),{})}var S6=class{constructor(e={}){this.calculateFaceAngle=t=>{if(!t||t.length<300)return{};let n=(a,s,i,o)=>Math.atan2(o-s,i-a),r=a=>Math.abs(a*180/Math.PI%360);return{roll:n(t[33][0],t[33][1],t[263][0],t[263][1]),yaw:n(t[33][0],t[33][2],t[263][0],t[263][2]),pitch:n(t[10][1],t[10][2],t[152][1],t[152][2])}},this.tf=V2,this.draw=b6,this.package=r6,this.version=S2,this.config=Fc(Nt,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>n6(t,this.config),this.facemesh=Iv,this.age=Ev,this.gender=Cv,this.emotion=Rv,this.body=this.config.body.modelType.startsWith("posenet")?Dv:t6,this.hand=qv,this.sysinfo=O4()}profile(){return this.config.profile?Tv:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,n=this.numTensors;this.numTensors=t;let r=t-n;r!==0&&Le(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?jre(e,t):0}async load(e=null){this.state="load";let t=dt();e&&(this.config=Fc(this.config,e)),this.firstRun&&(this.config.debug&&Le(`version: ${this.version}`),this.config.debug&&Le(`tfjs version: ${this.tf.version_core}`),this.config.debug&&Le("platform:",this.sysinfo.platform),this.config.debug&&Le("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&Le("configuration:",this.config),this.config.debug&&Le("tf flags:",this.tf.ENV.flags)));let n=this.config.face.detector.modelPath.includes("faceboxes")?Nv:Iv;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?n.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?n2(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?a2(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?u2(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?$v(this.config):null),this.models.handpose||(this.config.hand.enabled?g2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?p2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?v2(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await n.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await n2(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await a2(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await u2(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await $v(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await g2(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await p2(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await v2(this.config))),this.firstRun&&(this.config.debug&&Le("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(dt()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=dt();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&Le("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&Le("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let n=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&Le(`wasm execution: ${n?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),n||Le("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&wre();try{await this.tf.setBackend(this.config.backend)}catch(n){Le("error: cannot set backend:",this.config.backend,n)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(Le("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let n=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&Le(`gl version:${n.getParameter(n.VERSION)} renderer:${n.getParameter(n.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(dt()-t)}}async detectFace(e){var t,n,r,a,s,i;let o,l,u,c,h,d=[];this.state="run:face",o=dt();let p=await((t=this.models.face)==null?void 0:t.estimateFaces(e,this.config));this.perf.face=Math.trunc(dt()-o);for(let f of p){if(this.analyze("Get Face"),!f.image||f.image.isDisposedInternal){Le("Face object is disposed:",f.image);continue}let m=this.calculateFaceAngle(f.mesh);this.analyze("Start Age:"),this.config.async?l=this.config.face.age.enabled?r2(f.image,this.config):{}:(this.state="run:age",o=dt(),l=this.config.face.age.enabled?await r2(f.image,this.config):{},this.perf.age=Math.trunc(dt()-o)),this.analyze("Start Gender:"),this.config.async?u=this.config.face.gender.enabled?s2(f.image,this.config):{}:(this.state="run:gender",o=dt(),u=this.config.face.gender.enabled?await s2(f.image,this.config):{},this.perf.gender=Math.trunc(dt()-o)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?c2(f.image,this.config):{}:(this.state="run:emotion",o=dt(),c=this.config.face.emotion.enabled?await c2(f.image,this.config):{},this.perf.emotion=Math.trunc(dt()-o)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?h=this.config.face.embedding.enabled?Mv(f.image,this.config):[]:(this.state="run:embedding",o=dt(),h=this.config.face.embedding.enabled?await Mv(f.image,this.config):[],this.perf.embedding=Math.trunc(dt()-o)),this.analyze("End Emotion:"),this.config.async&&([l,u,c,h]=await Promise.all([l,u,c,h])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((n=f==null?void 0:f.annotations)==null?void 0:n.leftEyeIris)&&((r=f==null?void 0:f.annotations)==null?void 0:r.rightEyeIris)&&(delete f.annotations.leftEyeIris,delete f.annotations.rightEyeIris);let A=((a=f.annotations)==null?void 0:a.leftEyeIris)&&((s=f.annotations)==null?void 0:s.rightEyeIris)?11.7*Math.max(Math.abs(f.annotations.leftEyeIris[3][0]-f.annotations.leftEyeIris[1][0]),Math.abs(f.annotations.rightEyeIris[4][1]-f.annotations.rightEyeIris[2][1])):0;d.push({confidence:f.confidence,faceConfidence:f.faceConfidence,boxConfidence:f.boxConfidence,box:f.box,mesh:f.mesh,boxRaw:f.boxRaw,meshRaw:f.meshRaw,annotations:f.annotations,age:l.age,gender:u.gender,genderConfidence:u.confidence,emotion:c,embedding:h,iris:A!==0?Math.trunc(A)/100:0,angle:m}),(i=f.image)==null||i.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),d}async detect(e,t={}){return new Promise(async n=>{var r,a,s,i;this.state="config";let o;this.config=Fc(this.config,t),this.state="check";let l=this.sanity(e);l&&(Le(l,e),n({error:l}));let u=dt();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),o=dt();let c=n6(e,this.config);if(!c||!c.tensor){Le("could not convert input to tensor"),n({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(dt()-o),this.analyze("Get Image:");let h,d,p;this.config.async?(p=this.config.face.enabled?this.detectFace(c.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",o=dt(),p=this.config.face.enabled?await this.detectFace(c.tensor):[],this.perf.face=Math.trunc(dt()-o)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?h=this.config.body.enabled?(r=this.models.posenet)==null?void 0:r.estimatePoses(c.tensor,this.config):[]:h=this.config.body.enabled?k2(c.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",o=dt(),this.config.body.modelType.startsWith("posenet")?h=this.config.body.enabled?await((a=this.models.posenet)==null?void 0:a.estimatePoses(c.tensor,this.config)):[]:h=this.config.body.enabled?await k2(c.tensor,this.config):[],this.perf.body=Math.trunc(dt()-o)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(d=this.config.hand.enabled?(s=this.models.handpose)==null?void 0:s.estimateHands(c.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",o=dt(),d=this.config.hand.enabled?await((i=this.models.handpose)==null?void 0:i.estimateHands(c.tensor,this.config)):[],this.perf.hand=Math.trunc(dt()-o)),this.analyze("End Hand:"),this.config.async&&([p,h,d]=await Promise.all([p,h,d])),c.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let f=[];this.config.gesture.enabled&&(o=dt(),f=[...Mae(p),...$ae(h),...Oae(d),...Dae(p)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(dt()-o)),this.perf.total=Math.trunc(dt()-u),this.state="idle",n({face:p,body:h,hand:d,gesture:f,performance:this.perf,canvas:c.canvas})})}async warmupBitmap(){let e=(r,a="application/octet-stream")=>fetch(`data:${a};base64,${r}`).then(s=>s.blob()),t,n;switch(this.config.warmup){case"face":t=await e(I2);break;case"full":t=await e(N2);break;default:t=null}if(t){let r=await createImageBitmap(t);n=await this.detect(r,this.config),r.close()}return n}async warmupCanvas(){return new Promise(e=>{let t,n=0;switch(this.config.warmup){case"face":n=256,t="data:image/jpeg;base64,"+I2;break;case"full":case"body":n=1200,t="data:image/jpeg;base64,"+N2;break;default:t=null}let r=new Image;r.onload=async()=>{let a=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(n,n):document.createElement("canvas");a.width=r.naturalWidth,a.height=r.naturalHeight;let s=a.getContext("2d");s==null||s.drawImage(r,0,0);let i=await this.detect(a,this.config);e(i)},t?r.src=t:e(null)})}async warmupNode(){let e=s=>Buffer.from(s,"base64"),t=this.config.warmup==="face"?e(I2):e(N2),n=(void 0).decodeJpeg(t),r=n.expandDims(0);this.tf.dispose(n);let a=await this.detect(r,this.config);return this.tf.dispose(r),a}async warmup(e){let t=dt();e&&(this.config=Fc(this.config,e));let n=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=n;let a=dt();return this.config.debug&&Le("Warmup",this.config.warmup,Math.round(a-t),"ms",r),r}};var $c=0,T6=!1,wt={background:"darkslategray",hover:"lightgray",itemBackground:"black",itemColor:"white",buttonBackground:"lightblue",buttonHover:"lightgreen",checkboxOn:"lightgreen",checkboxOff:"lightcoral",rangeBackground:"lightblue",rangeLabel:"white",chartColor:"lightblue"};function Vae(){if(T6)return;let e=` :root { --rounded: 0.1rem; } .menu { position: absolute; top: 0rem; right: 0; width: max-content; padding: 0 0.2rem 0 0.2rem; line-height: 1.8rem; z-index: 10; box-shadow: 0 0 8px dimgrey; background: ${wt.background}; border-radius: var(--rounded); border-color: black; border-style: solid; border-width: thin; } diff --git a/dist/human.esm-nobundle.js b/dist/human.esm-nobundle.js index f7bc106e..03041dd8 100644 --- a/dist/human.esm-nobundle.js +++ b/dist/human.esm-nobundle.js @@ -731,5 +731,5 @@ AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ -2Q==`;var X1={};q(X1,{author:()=>$0,browser:()=>G0,bugs:()=>et,default:()=>jn,description:()=>C0,devDependencies:()=>_t,engines:()=>rt,homepage:()=>tt,keywords:()=>ot,license:()=>nt,main:()=>U0,module:()=>D0,name:()=>B0,peerDependencies:()=>ct,repository:()=>At,scripts:()=>ht,sideEffects:()=>K0,types:()=>Q0,version:()=>F1});var B0="@vladmandic/human",F1="1.0.0",C0="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",K0=!1,U0="dist/human.node.js",D0="dist/human.esm.js",G0="dist/human.esm.js",Q0="types/human.d.ts",$0="Vladimir Mandic ",et={url:"https://github.com/vladmandic/human/issues"},tt="https://vladmandic.github.io/human/demo/index.html",nt="MIT",rt={node:">=12.0.0"},At={type:"git",url:"git+https://github.com/vladmandic/human.git"},ct={},_t={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},ht={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},ot=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],jn={name:B0,version:F1,description:C0,sideEffects:K0,main:U0,module:D0,browser:G0,types:Q0,author:$0,bugs:et,homepage:tt,license:nt,engines:rt,repository:At,peerDependencies:ct,devDependencies:_t,scripts:ht,keywords:ot};var q1={};q(q1,{all:()=>In,body:()=>yt,canvas:()=>Nn,face:()=>xt,gesture:()=>it,hand:()=>at,options:()=>l});var l={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function Oe(n,e,t){n.fillStyle=l.color,n.beginPath(),n.arc(e,t,l.pointSize,0,2*Math.PI),n.fill()}function st(n,e,t,A,r){if(n.beginPath(),l.useCurves){let c=(e+e+A)/2,_=(t+t+r)/2;n.ellipse(c,_,A/2,r/2,0,0,2*Math.PI)}else n.lineWidth=l.lineWidth,n.moveTo(e+l.roundRect,t),n.lineTo(e+A-l.roundRect,t),n.quadraticCurveTo(e+A,t,e+A,t+l.roundRect),n.lineTo(e+A,t+r-l.roundRect),n.quadraticCurveTo(e+A,t+r,e+A-l.roundRect,t+r),n.lineTo(e+l.roundRect,t+r),n.quadraticCurveTo(e,t+r,e,t+r-l.roundRect),n.lineTo(e,t+l.roundRect),n.quadraticCurveTo(e,t,e+l.roundRect,t),n.closePath();n.stroke()}function Y1(n,e=[]){if(!(e===void 0||e.length===0)){n.beginPath(),n.moveTo(e[0][0],e[0][1]);for(let t of e)n.lineTo(t[0],parseInt(t[1]));n.stroke(),l.fillPolygons&&(n.closePath(),n.fill())}}function ke(n,e=[]){if(!(e===void 0||e.length===0)){if(!l.useCurves||e.length<=2){Y1(n,e);return}n.moveTo(e[0][0],e[0][1]);for(let t=0;t1&&_[1].length>0){let h=c[1]>0?`#${c[1]}`:"",o=`${c[0]} ${h}: ${_[1]}`;l.shadowColor&&l.shadowColor!==""&&(t.fillStyle=l.shadowColor,t.fillText(o,8,2+A*l.lineHeight)),t.fillStyle=l.labelColor,t.fillText(o,6,0+A*l.lineHeight),A+=1}}}async function xt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t)for(let A of e){t.font=l.font,t.strokeStyle=l.color,t.fillStyle=l.color,l.drawBoxes&&st(t,A.box[0],A.box[1],A.box[2],A.box[3]);let r=[];if(r.push(`face confidence: ${Math.trunc(100*A.confidence)}%`),A.genderConfidence&&r.push(`${A.gender||""} ${Math.trunc(100*A.genderConfidence)}% confident`),A.age&&r.push(`age: ${A.age||""}`),A.iris&&r.push(`iris distance: ${A.iris}`),A.emotion&&A.emotion.length>0){let c=A.emotion.map(_=>`${Math.trunc(100*_.score)}% ${_.emotion}`);r.push(c.join(" "))}A.angle&&A.angle.roll&&r.push(`roll: ${Math.trunc(100*A.angle.roll)/100} yaw:${Math.trunc(100*A.angle.yaw)/100} pitch:${Math.trunc(100*A.angle.pitch)/100}`),r.length===0&&r.push("face"),t.fillStyle=l.color;for(let c=r.length-1;c>=0;c--){let _=Math.max(A.box[0],0),h=c*l.lineHeight+A.box[1];l.shadowColor&&l.shadowColor!==""&&(t.fillStyle=l.shadowColor,t.fillText(r[c],_+5,h+16)),t.fillStyle=l.labelColor,t.fillText(r[c],_+4,h+15)}if(t.lineWidth=1,A.mesh){if(l.drawPoints)for(let c of A.mesh)t.fillStyle=l.useDepth?`rgba(${127.5+2*c[2]}, ${127.5-2*c[2]}, 255, 0.5)`:l.color,Oe(t,c[0],c[1]);if(l.drawPolygons){for(let c=0;cA.mesh[h]);t.strokeStyle=l.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:l.color,t.fillStyle=l.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:l.color,t.lineWidth=1,Y1(t,_)}if(A.annotations&&A.annotations.leftEyeIris){t.strokeStyle=l.useDepth?"rgba(255, 200, 255, 0.3)":l.color,t.beginPath();let c=Math.abs(A.annotations.leftEyeIris[3][0]-A.annotations.leftEyeIris[1][0])/2,_=Math.abs(A.annotations.leftEyeIris[4][1]-A.annotations.leftEyeIris[2][1])/2;t.ellipse(A.annotations.leftEyeIris[0][0],A.annotations.leftEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),l.fillPolygons&&(t.fillStyle=l.useDepth?"rgba(255, 255, 200, 0.3)":l.color,t.fill())}if(A.annotations&&A.annotations.rightEyeIris){t.strokeStyle=l.useDepth?"rgba(255, 200, 255, 0.3)":l.color,t.beginPath();let c=Math.abs(A.annotations.rightEyeIris[3][0]-A.annotations.rightEyeIris[1][0])/2,_=Math.abs(A.annotations.rightEyeIris[4][1]-A.annotations.rightEyeIris[2][1])/2;t.ellipse(A.annotations.rightEyeIris[0][0],A.annotations.rightEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),l.fillPolygons&&(t.fillStyle=l.useDepth?"rgba(255, 255, 200, 0.3)":l.color,t.fill())}}}}}var ne=[];async function yt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round";for(let A=0;A_.part==="leftShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),c.length===5&&Y1(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftKnee"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftAnkle"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHeel"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftFoot"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightKnee"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightAnkle"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHeel"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightFoot"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftElbow"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftWrist"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftPalm"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightElbow"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightWrist"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightPalm"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c)}}}}async function at(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round",t.font=l.font;for(let A of e){if(l.drawBoxes&&(t.strokeStyle=l.color,t.fillStyle=l.color,st(t,A.box[0],A.box[1],A.box[2],A.box[3]),l.shadowColor&&l.shadowColor!==""&&(t.fillStyle=l.shadowColor,t.fillText("hand",A.box[0]+3,1+A.box[1]+l.lineHeight,A.box[2])),t.fillStyle=l.labelColor,t.fillText("hand",A.box[0]+2,0+A.box[1]+l.lineHeight,A.box[2]),t.stroke()),l.drawPoints&&A.landmarks&&A.landmarks.length>0)for(let r of A.landmarks)t.fillStyle=l.useDepth?`rgba(${127.5+2*r[2]}, ${127.5-2*r[2]}, 255, 0.5)`:l.color,Oe(t,r[0],r[1]);if(l.drawPolygons){let r=c=>{if(!!c)for(let _=0;_0?_-1:0][0],c[_>0?_-1:0][1]),t.lineTo(c[_][0],c[_][1]),t.stroke()};r(A.annotations.indexFinger),r(A.annotations.middleFinger),r(A.annotations.ringFinger),r(A.annotations.pinky),r(A.annotations.thumb)}}}}async function Nn(n,e){if(!n||!e||!(n instanceof HTMLCanvasElement)||!(e instanceof HTMLCanvasElement))return;let t=n.getContext("2d");t==null||t.drawImage(n,0,0)}async function In(n,e){!e||!n||n instanceof HTMLCanvasElement&&(xt(n,e.face),yt(n,e.body),at(n,e.hand),it(n,e.gesture))}var v=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function we(...n){let e=t=>t&&typeof t=="object";return n.reduce((t,A)=>(Object.keys(A||{}).forEach(r=>{let c=t[r],_=A[r];Array.isArray(c)&&Array.isArray(_)?t[r]=c.concat(..._):e(c)&&e(_)?t[r]=we(c,_):t[r]=_}),t),{})}var lt=class{constructor(e={}){this.calculateFaceAngle=e=>{if(!e||e.length<300)return{};let t=(c,_,h,o)=>Math.atan2(o-_,h-c),A=c=>Math.abs(c*180/Math.PI%360);return{roll:t(e[33][0],e[33][1],e[263][0],e[263][1]),yaw:t(e[33][0],e[33][2],e[263][0],e[263][2]),pitch:t(e[10][1],e[10][2],e[152][1],e[152][2])}};this.tf=wt,this.draw=q1,this.package=X1,this.version=F1,this.config=we(z,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>H1(t,this.config),this.facemesh=dt,this.age=Qe,this.gender=t1,this.emotion=h1,this.body=this.config.body.modelType.startsWith("posenet")?v1:Z1,this.hand=j1,this.sysinfo=U1()}profile(){return this.config.profile?Ue:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,A=this.numTensors;this.numTensors=t;let r=t-A;r!==0&&u(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?i0(e,t):0}async load(e=null){this.state="load";let t=v();e&&(this.config=we(this.config,e)),this.firstRun&&(this.config.debug&&u(`version: ${this.version}`),this.config.debug&&u(`tfjs version: ${this.tf.version_core}`),this.config.debug&&u("platform:",this.sysinfo.platform),this.config.debug&&u("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&u("configuration:",this.config),this.config.debug&&u("tf flags:",this.tf.ENV.flags)));let A=this.config.face.detector.modelPath.includes("faceboxes")?De:dt;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?A.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?$e(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?c1(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?i1(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?y1(this.config):null),this.models.handpose||(this.config.hand.enabled?k1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?E1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?V1(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await A.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await $e(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await c1(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await i1(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await y1(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await k1(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await E1(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await V1(this.config))),this.firstRun&&(this.config.debug&&u("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(v()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=v();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&u("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&u("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let A=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&u(`wasm execution: ${A?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),A||u("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&D1();try{await this.tf.setBackend(this.config.backend)}catch(A){u("error: cannot set backend:",this.config.backend,A)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(u("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let A=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&u(`gl version:${A.getParameter(A.VERSION)} renderer:${A.getParameter(A.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(v()-t)}}async detectFace(e){var x,a,i,w,f,p;let t,A,r,c,_,h=[];this.state="run:face",t=v();let o=await((x=this.models.face)==null?void 0:x.estimateFaces(e,this.config));this.perf.face=Math.trunc(v()-t);for(let s of o){if(this.analyze("Get Face"),!s.image||s.image.isDisposedInternal){u("Face object is disposed:",s.image);continue}let k=this.calculateFaceAngle(s.mesh);this.analyze("Start Age:"),this.config.async?A=this.config.face.age.enabled?e1(s.image,this.config):{}:(this.state="run:age",t=v(),A=this.config.face.age.enabled?await e1(s.image,this.config):{},this.perf.age=Math.trunc(v()-t)),this.analyze("Start Gender:"),this.config.async?r=this.config.face.gender.enabled?_1(s.image,this.config):{}:(this.state="run:gender",t=v(),r=this.config.face.gender.enabled?await _1(s.image,this.config):{},this.perf.gender=Math.trunc(v()-t)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?x1(s.image,this.config):{}:(this.state="run:emotion",t=v(),c=this.config.face.emotion.enabled?await x1(s.image,this.config):{},this.perf.emotion=Math.trunc(v()-t)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?_=this.config.face.embedding.enabled?a1(s.image,this.config):[]:(this.state="run:embedding",t=v(),_=this.config.face.embedding.enabled?await a1(s.image,this.config):[],this.perf.embedding=Math.trunc(v()-t)),this.analyze("End Emotion:"),this.config.async&&([A,r,c,_]=await Promise.all([A,r,c,_])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((a=s==null?void 0:s.annotations)==null?void 0:a.leftEyeIris)&&((i=s==null?void 0:s.annotations)==null?void 0:i.rightEyeIris)&&(delete s.annotations.leftEyeIris,delete s.annotations.rightEyeIris);let j=((w=s.annotations)==null?void 0:w.leftEyeIris)&&((f=s.annotations)==null?void 0:f.rightEyeIris)?11.7*Math.max(Math.abs(s.annotations.leftEyeIris[3][0]-s.annotations.leftEyeIris[1][0]),Math.abs(s.annotations.rightEyeIris[4][1]-s.annotations.rightEyeIris[2][1])):0;h.push({confidence:s.confidence,faceConfidence:s.faceConfidence,boxConfidence:s.boxConfidence,box:s.box,mesh:s.mesh,boxRaw:s.boxRaw,meshRaw:s.meshRaw,annotations:s.annotations,age:A.age,gender:r.gender,genderConfidence:r.confidence,emotion:c,embedding:_,iris:j!==0?Math.trunc(j)/100:0,angle:k}),(p=s.image)==null||p.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),h}async detect(e,t={}){return new Promise(async A=>{var w,f,p,s;this.state="config";let r;this.config=we(this.config,t),this.state="check";let c=this.sanity(e);c&&(u(c,e),A({error:c}));let _=v();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),r=v();let h=H1(e,this.config);if(!h||!h.tensor){u("could not convert input to tensor"),A({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(v()-r),this.analyze("Get Image:");let o,x,a;this.config.async?(a=this.config.face.enabled?this.detectFace(h.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",r=v(),a=this.config.face.enabled?await this.detectFace(h.tensor):[],this.perf.face=Math.trunc(v()-r)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?(w=this.models.posenet)==null?void 0:w.estimatePoses(h.tensor,this.config):[]:o=this.config.body.enabled?L1(h.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",r=v(),this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?await((f=this.models.posenet)==null?void 0:f.estimatePoses(h.tensor,this.config)):[]:o=this.config.body.enabled?await L1(h.tensor,this.config):[],this.perf.body=Math.trunc(v()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(x=this.config.hand.enabled?(p=this.models.handpose)==null?void 0:p.estimateHands(h.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",r=v(),x=this.config.hand.enabled?await((s=this.models.handpose)==null?void 0:s.estimateHands(h.tensor,this.config)):[],this.perf.hand=Math.trunc(v()-r)),this.analyze("End Hand:"),this.config.async&&([a,o,x]=await Promise.all([a,o,x])),h.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let i=[];this.config.gesture.enabled&&(r=v(),i=[...F0(a),...X0(o),...Y0(x),...q0(a)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(v()-r)),this.perf.total=Math.trunc(v()-_),this.state="idle",A({face:a,body:o,hand:x,gesture:i,performance:this.perf,canvas:h.canvas})})}async warmupBitmap(){let e=(r,c="application/octet-stream")=>fetch(`data:${c};base64,${r}`).then(_=>_.blob()),t,A;switch(this.config.warmup){case"face":t=await e(Ne);break;case"full":t=await e(Ie);break;default:t=null}if(t){let r=await createImageBitmap(t);A=await this.detect(r,this.config),r.close()}return A}async warmupCanvas(){return new Promise(e=>{let t,A=0;switch(this.config.warmup){case"face":A=256,t="data:image/jpeg;base64,"+Ne;break;case"full":case"body":A=1200,t="data:image/jpeg;base64,"+Ie;break;default:t=null}let r=new Image;r.onload=async()=>{let c=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(A,A):document.createElement("canvas");c.width=r.naturalWidth,c.height=r.naturalHeight;let _=c.getContext("2d");_==null||_.drawImage(r,0,0);let h=await this.detect(c,this.config);e(h)},t?r.src=t:e(null)})}async warmupNode(){let e=_=>Buffer.from(_,"base64"),t=this.config.warmup==="face"?e(Ne):e(Ie),A=wt.node.decodeJpeg(t),r=A.expandDims(0);this.tf.dispose(A);let c=await this.detect(r,this.config);return this.tf.dispose(r),c}async warmup(e){let t=v();e&&(this.config=we(this.config,e));let A=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=A;let c=v();return this.config.debug&&u("Warmup",this.config.warmup,Math.round(c-t),"ms",r),r}};export{lt as default}; +2Q==`;var X1={};q(X1,{author:()=>$0,browser:()=>G0,bugs:()=>et,default:()=>jn,description:()=>C0,devDependencies:()=>_t,engines:()=>rt,homepage:()=>tt,keywords:()=>ot,license:()=>nt,main:()=>U0,module:()=>D0,name:()=>B0,peerDependencies:()=>ct,repository:()=>At,scripts:()=>ht,sideEffects:()=>K0,types:()=>Q0,version:()=>F1});var B0="@vladmandic/human",F1="1.0.1",C0="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",K0=!1,U0="dist/human.node.js",D0="dist/human.esm.js",G0="dist/human.esm.js",Q0="types/human.d.ts",$0="Vladimir Mandic ",et={url:"https://github.com/vladmandic/human/issues"},tt="https://vladmandic.github.io/human/demo/index.html",nt="MIT",rt={node:">=12.0.0"},At={type:"git",url:"git+https://github.com/vladmandic/human.git"},ct={},_t={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},ht={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},ot=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],jn={name:B0,version:F1,description:C0,sideEffects:K0,main:U0,module:D0,browser:G0,types:Q0,author:$0,bugs:et,homepage:tt,license:nt,engines:rt,repository:At,peerDependencies:ct,devDependencies:_t,scripts:ht,keywords:ot};var q1={};q(q1,{all:()=>In,body:()=>yt,canvas:()=>Nn,face:()=>xt,gesture:()=>it,hand:()=>at,options:()=>l});var l={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function Oe(n,e,t){n.fillStyle=l.color,n.beginPath(),n.arc(e,t,l.pointSize,0,2*Math.PI),n.fill()}function st(n,e,t,A,r){if(n.beginPath(),l.useCurves){let c=(e+e+A)/2,_=(t+t+r)/2;n.ellipse(c,_,A/2,r/2,0,0,2*Math.PI)}else n.lineWidth=l.lineWidth,n.moveTo(e+l.roundRect,t),n.lineTo(e+A-l.roundRect,t),n.quadraticCurveTo(e+A,t,e+A,t+l.roundRect),n.lineTo(e+A,t+r-l.roundRect),n.quadraticCurveTo(e+A,t+r,e+A-l.roundRect,t+r),n.lineTo(e+l.roundRect,t+r),n.quadraticCurveTo(e,t+r,e,t+r-l.roundRect),n.lineTo(e,t+l.roundRect),n.quadraticCurveTo(e,t,e+l.roundRect,t),n.closePath();n.stroke()}function Y1(n,e=[]){if(!(e===void 0||e.length===0)){n.beginPath(),n.moveTo(e[0][0],e[0][1]);for(let t of e)n.lineTo(t[0],parseInt(t[1]));n.stroke(),l.fillPolygons&&(n.closePath(),n.fill())}}function ke(n,e=[]){if(!(e===void 0||e.length===0)){if(!l.useCurves||e.length<=2){Y1(n,e);return}n.moveTo(e[0][0],e[0][1]);for(let t=0;t1&&_[1].length>0){let h=c[1]>0?`#${c[1]}`:"",o=`${c[0]} ${h}: ${_[1]}`;l.shadowColor&&l.shadowColor!==""&&(t.fillStyle=l.shadowColor,t.fillText(o,8,2+A*l.lineHeight)),t.fillStyle=l.labelColor,t.fillText(o,6,0+A*l.lineHeight),A+=1}}}async function xt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t)for(let A of e){t.font=l.font,t.strokeStyle=l.color,t.fillStyle=l.color,l.drawBoxes&&st(t,A.box[0],A.box[1],A.box[2],A.box[3]);let r=[];if(r.push(`face confidence: ${Math.trunc(100*A.confidence)}%`),A.genderConfidence&&r.push(`${A.gender||""} ${Math.trunc(100*A.genderConfidence)}% confident`),A.age&&r.push(`age: ${A.age||""}`),A.iris&&r.push(`iris distance: ${A.iris}`),A.emotion&&A.emotion.length>0){let c=A.emotion.map(_=>`${Math.trunc(100*_.score)}% ${_.emotion}`);r.push(c.join(" "))}A.angle&&A.angle.roll&&r.push(`roll: ${Math.trunc(100*A.angle.roll)/100} yaw:${Math.trunc(100*A.angle.yaw)/100} pitch:${Math.trunc(100*A.angle.pitch)/100}`),r.length===0&&r.push("face"),t.fillStyle=l.color;for(let c=r.length-1;c>=0;c--){let _=Math.max(A.box[0],0),h=c*l.lineHeight+A.box[1];l.shadowColor&&l.shadowColor!==""&&(t.fillStyle=l.shadowColor,t.fillText(r[c],_+5,h+16)),t.fillStyle=l.labelColor,t.fillText(r[c],_+4,h+15)}if(t.lineWidth=1,A.mesh){if(l.drawPoints)for(let c of A.mesh)t.fillStyle=l.useDepth?`rgba(${127.5+2*c[2]}, ${127.5-2*c[2]}, 255, 0.5)`:l.color,Oe(t,c[0],c[1]);if(l.drawPolygons){for(let c=0;cA.mesh[h]);t.strokeStyle=l.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:l.color,t.fillStyle=l.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:l.color,t.lineWidth=1,Y1(t,_)}if(A.annotations&&A.annotations.leftEyeIris){t.strokeStyle=l.useDepth?"rgba(255, 200, 255, 0.3)":l.color,t.beginPath();let c=Math.abs(A.annotations.leftEyeIris[3][0]-A.annotations.leftEyeIris[1][0])/2,_=Math.abs(A.annotations.leftEyeIris[4][1]-A.annotations.leftEyeIris[2][1])/2;t.ellipse(A.annotations.leftEyeIris[0][0],A.annotations.leftEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),l.fillPolygons&&(t.fillStyle=l.useDepth?"rgba(255, 255, 200, 0.3)":l.color,t.fill())}if(A.annotations&&A.annotations.rightEyeIris){t.strokeStyle=l.useDepth?"rgba(255, 200, 255, 0.3)":l.color,t.beginPath();let c=Math.abs(A.annotations.rightEyeIris[3][0]-A.annotations.rightEyeIris[1][0])/2,_=Math.abs(A.annotations.rightEyeIris[4][1]-A.annotations.rightEyeIris[2][1])/2;t.ellipse(A.annotations.rightEyeIris[0][0],A.annotations.rightEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),l.fillPolygons&&(t.fillStyle=l.useDepth?"rgba(255, 255, 200, 0.3)":l.color,t.fill())}}}}}var ne=[];async function yt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round";for(let A=0;A_.part==="leftShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),c.length===5&&Y1(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftKnee"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftAnkle"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHeel"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftFoot"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightKnee"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightAnkle"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHeel"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightFoot"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftElbow"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftWrist"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftPalm"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightElbow"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightWrist"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightPalm"),r&&r.score>z.body.scoreThreshold&&c.push([r.position.x,r.position.y]),ke(t,c)}}}}async function at(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round",t.font=l.font;for(let A of e){if(l.drawBoxes&&(t.strokeStyle=l.color,t.fillStyle=l.color,st(t,A.box[0],A.box[1],A.box[2],A.box[3]),l.shadowColor&&l.shadowColor!==""&&(t.fillStyle=l.shadowColor,t.fillText("hand",A.box[0]+3,1+A.box[1]+l.lineHeight,A.box[2])),t.fillStyle=l.labelColor,t.fillText("hand",A.box[0]+2,0+A.box[1]+l.lineHeight,A.box[2]),t.stroke()),l.drawPoints&&A.landmarks&&A.landmarks.length>0)for(let r of A.landmarks)t.fillStyle=l.useDepth?`rgba(${127.5+2*r[2]}, ${127.5-2*r[2]}, 255, 0.5)`:l.color,Oe(t,r[0],r[1]);if(l.drawPolygons){let r=c=>{if(!!c)for(let _=0;_0?_-1:0][0],c[_>0?_-1:0][1]),t.lineTo(c[_][0],c[_][1]),t.stroke()};r(A.annotations.indexFinger),r(A.annotations.middleFinger),r(A.annotations.ringFinger),r(A.annotations.pinky),r(A.annotations.thumb)}}}}async function Nn(n,e){if(!n||!e||!(n instanceof HTMLCanvasElement)||!(e instanceof HTMLCanvasElement))return;let t=n.getContext("2d");t==null||t.drawImage(n,0,0)}async function In(n,e){!e||!n||n instanceof HTMLCanvasElement&&(xt(n,e.face),yt(n,e.body),at(n,e.hand),it(n,e.gesture))}var v=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function we(...n){let e=t=>t&&typeof t=="object";return n.reduce((t,A)=>(Object.keys(A||{}).forEach(r=>{let c=t[r],_=A[r];Array.isArray(c)&&Array.isArray(_)?t[r]=c.concat(..._):e(c)&&e(_)?t[r]=we(c,_):t[r]=_}),t),{})}var lt=class{constructor(e={}){this.calculateFaceAngle=e=>{if(!e||e.length<300)return{};let t=(c,_,h,o)=>Math.atan2(o-_,h-c),A=c=>Math.abs(c*180/Math.PI%360);return{roll:t(e[33][0],e[33][1],e[263][0],e[263][1]),yaw:t(e[33][0],e[33][2],e[263][0],e[263][2]),pitch:t(e[10][1],e[10][2],e[152][1],e[152][2])}};this.tf=wt,this.draw=q1,this.package=X1,this.version=F1,this.config=we(z,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>H1(t,this.config),this.facemesh=dt,this.age=Qe,this.gender=t1,this.emotion=h1,this.body=this.config.body.modelType.startsWith("posenet")?v1:Z1,this.hand=j1,this.sysinfo=U1()}profile(){return this.config.profile?Ue:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,A=this.numTensors;this.numTensors=t;let r=t-A;r!==0&&u(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?i0(e,t):0}async load(e=null){this.state="load";let t=v();e&&(this.config=we(this.config,e)),this.firstRun&&(this.config.debug&&u(`version: ${this.version}`),this.config.debug&&u(`tfjs version: ${this.tf.version_core}`),this.config.debug&&u("platform:",this.sysinfo.platform),this.config.debug&&u("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&u("configuration:",this.config),this.config.debug&&u("tf flags:",this.tf.ENV.flags)));let A=this.config.face.detector.modelPath.includes("faceboxes")?De:dt;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?A.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?$e(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?c1(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?i1(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?y1(this.config):null),this.models.handpose||(this.config.hand.enabled?k1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?E1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?V1(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await A.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await $e(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await c1(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await i1(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await y1(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await k1(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await E1(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await V1(this.config))),this.firstRun&&(this.config.debug&&u("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(v()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=v();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&u("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&u("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let A=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&u(`wasm execution: ${A?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),A||u("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&D1();try{await this.tf.setBackend(this.config.backend)}catch(A){u("error: cannot set backend:",this.config.backend,A)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(u("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let A=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&u(`gl version:${A.getParameter(A.VERSION)} renderer:${A.getParameter(A.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(v()-t)}}async detectFace(e){var x,a,i,w,f,p;let t,A,r,c,_,h=[];this.state="run:face",t=v();let o=await((x=this.models.face)==null?void 0:x.estimateFaces(e,this.config));this.perf.face=Math.trunc(v()-t);for(let s of o){if(this.analyze("Get Face"),!s.image||s.image.isDisposedInternal){u("Face object is disposed:",s.image);continue}let k=this.calculateFaceAngle(s.mesh);this.analyze("Start Age:"),this.config.async?A=this.config.face.age.enabled?e1(s.image,this.config):{}:(this.state="run:age",t=v(),A=this.config.face.age.enabled?await e1(s.image,this.config):{},this.perf.age=Math.trunc(v()-t)),this.analyze("Start Gender:"),this.config.async?r=this.config.face.gender.enabled?_1(s.image,this.config):{}:(this.state="run:gender",t=v(),r=this.config.face.gender.enabled?await _1(s.image,this.config):{},this.perf.gender=Math.trunc(v()-t)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?x1(s.image,this.config):{}:(this.state="run:emotion",t=v(),c=this.config.face.emotion.enabled?await x1(s.image,this.config):{},this.perf.emotion=Math.trunc(v()-t)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?_=this.config.face.embedding.enabled?a1(s.image,this.config):[]:(this.state="run:embedding",t=v(),_=this.config.face.embedding.enabled?await a1(s.image,this.config):[],this.perf.embedding=Math.trunc(v()-t)),this.analyze("End Emotion:"),this.config.async&&([A,r,c,_]=await Promise.all([A,r,c,_])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((a=s==null?void 0:s.annotations)==null?void 0:a.leftEyeIris)&&((i=s==null?void 0:s.annotations)==null?void 0:i.rightEyeIris)&&(delete s.annotations.leftEyeIris,delete s.annotations.rightEyeIris);let j=((w=s.annotations)==null?void 0:w.leftEyeIris)&&((f=s.annotations)==null?void 0:f.rightEyeIris)?11.7*Math.max(Math.abs(s.annotations.leftEyeIris[3][0]-s.annotations.leftEyeIris[1][0]),Math.abs(s.annotations.rightEyeIris[4][1]-s.annotations.rightEyeIris[2][1])):0;h.push({confidence:s.confidence,faceConfidence:s.faceConfidence,boxConfidence:s.boxConfidence,box:s.box,mesh:s.mesh,boxRaw:s.boxRaw,meshRaw:s.meshRaw,annotations:s.annotations,age:A.age,gender:r.gender,genderConfidence:r.confidence,emotion:c,embedding:_,iris:j!==0?Math.trunc(j)/100:0,angle:k}),(p=s.image)==null||p.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),h}async detect(e,t={}){return new Promise(async A=>{var w,f,p,s;this.state="config";let r;this.config=we(this.config,t),this.state="check";let c=this.sanity(e);c&&(u(c,e),A({error:c}));let _=v();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),r=v();let h=H1(e,this.config);if(!h||!h.tensor){u("could not convert input to tensor"),A({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(v()-r),this.analyze("Get Image:");let o,x,a;this.config.async?(a=this.config.face.enabled?this.detectFace(h.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",r=v(),a=this.config.face.enabled?await this.detectFace(h.tensor):[],this.perf.face=Math.trunc(v()-r)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?(w=this.models.posenet)==null?void 0:w.estimatePoses(h.tensor,this.config):[]:o=this.config.body.enabled?L1(h.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",r=v(),this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?await((f=this.models.posenet)==null?void 0:f.estimatePoses(h.tensor,this.config)):[]:o=this.config.body.enabled?await L1(h.tensor,this.config):[],this.perf.body=Math.trunc(v()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(x=this.config.hand.enabled?(p=this.models.handpose)==null?void 0:p.estimateHands(h.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",r=v(),x=this.config.hand.enabled?await((s=this.models.handpose)==null?void 0:s.estimateHands(h.tensor,this.config)):[],this.perf.hand=Math.trunc(v()-r)),this.analyze("End Hand:"),this.config.async&&([a,o,x]=await Promise.all([a,o,x])),h.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let i=[];this.config.gesture.enabled&&(r=v(),i=[...F0(a),...X0(o),...Y0(x),...q0(a)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(v()-r)),this.perf.total=Math.trunc(v()-_),this.state="idle",A({face:a,body:o,hand:x,gesture:i,performance:this.perf,canvas:h.canvas})})}async warmupBitmap(){let e=(r,c="application/octet-stream")=>fetch(`data:${c};base64,${r}`).then(_=>_.blob()),t,A;switch(this.config.warmup){case"face":t=await e(Ne);break;case"full":t=await e(Ie);break;default:t=null}if(t){let r=await createImageBitmap(t);A=await this.detect(r,this.config),r.close()}return A}async warmupCanvas(){return new Promise(e=>{let t,A=0;switch(this.config.warmup){case"face":A=256,t="data:image/jpeg;base64,"+Ne;break;case"full":case"body":A=1200,t="data:image/jpeg;base64,"+Ie;break;default:t=null}let r=new Image;r.onload=async()=>{let c=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(A,A):document.createElement("canvas");c.width=r.naturalWidth,c.height=r.naturalHeight;let _=c.getContext("2d");_==null||_.drawImage(r,0,0);let h=await this.detect(c,this.config);e(h)},t?r.src=t:e(null)})}async warmupNode(){let e=_=>Buffer.from(_,"base64"),t=this.config.warmup==="face"?e(Ne):e(Ie),A=wt.node.decodeJpeg(t),r=A.expandDims(0);this.tf.dispose(A);let c=await this.detect(r,this.config);return this.tf.dispose(r),c}async warmup(e){let t=v();e&&(this.config=we(this.config,e));let A=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=A;let c=v();return this.config.debug&&u("Warmup",this.config.warmup,Math.round(c-t),"ms",r),r}};export{lt as default}; //# sourceMappingURL=human.esm-nobundle.js.map diff --git a/dist/human.esm.js b/dist/human.esm.js index 59e9ef37..adcf7f9a 100644 --- a/dist/human.esm.js +++ b/dist/human.esm.js @@ -4771,7 +4771,7 @@ AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ -2Q==`;var q2={};Jn(q2,{author:()=>L6,browser:()=>z6,bugs:()=>W6,default:()=>Eae,description:()=>F6,devDependencies:()=>G6,engines:()=>U6,homepage:()=>B6,keywords:()=>X6,license:()=>V6,main:()=>O6,module:()=>D6,name:()=>M6,peerDependencies:()=>j6,repository:()=>H6,scripts:()=>q6,sideEffects:()=>$6,types:()=>P6,version:()=>X2});var M6="@vladmandic/human",X2="1.0.0",F6="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",$6=!1,O6="dist/human.node.js",D6="dist/human.esm.js",z6="dist/human.esm.js",P6="types/human.d.ts",L6="Vladimir Mandic ",W6={url:"https://github.com/vladmandic/human/issues"},B6="https://vladmandic.github.io/human/demo/index.html",V6="MIT",U6={node:">=12.0.0"},H6={type:"git",url:"git+https://github.com/vladmandic/human.git"},j6={},G6={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},q6={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},X6=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Eae={name:M6,version:X2,description:F6,sideEffects:$6,main:O6,module:D6,browser:z6,types:P6,author:L6,bugs:W6,homepage:B6,license:V6,engines:U6,repository:H6,peerDependencies:j6,devDependencies:G6,scripts:q6,keywords:X6};var K2={};Jn(K2,{all:()=>Rae,body:()=>J6,canvas:()=>Cae,face:()=>Y6,gesture:()=>Z6,hand:()=>Q6,options:()=>ce});var ce={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function u0(e,t,n){e.fillStyle=ce.color,e.beginPath(),e.arc(t,n,ce.pointSize,0,2*Math.PI),e.fill()}function K6(e,t,n,r,a){if(e.beginPath(),ce.useCurves){let s=(t+t+r)/2,i=(n+n+a)/2;e.ellipse(s,i,r/2,a/2,0,0,2*Math.PI)}else e.lineWidth=ce.lineWidth,e.moveTo(t+ce.roundRect,n),e.lineTo(t+r-ce.roundRect,n),e.quadraticCurveTo(t+r,n,t+r,n+ce.roundRect),e.lineTo(t+r,n+a-ce.roundRect),e.quadraticCurveTo(t+r,n+a,t+r-ce.roundRect,n+a),e.lineTo(t+ce.roundRect,n+a),e.quadraticCurveTo(t,n+a,t,n+a-ce.roundRect),e.lineTo(t,n+ce.roundRect),e.quadraticCurveTo(t,n,t+ce.roundRect,n),e.closePath();e.stroke()}function Z2(e,t=[]){if(!(t===void 0||t.length===0)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.lineTo(n[0],parseInt(n[1]));e.stroke(),ce.fillPolygons&&(e.closePath(),e.fill())}}function c0(e,t=[]){if(!(t===void 0||t.length===0)){if(!ce.useCurves||t.length<=2){Z2(e,t);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;n1&&i[1].length>0){let o=s[1]>0?`#${s[1]}`:"",l=`${s[0]} ${o}: ${i[1]}`;ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(l,8,2+r*ce.lineHeight)),n.fillStyle=ce.labelColor,n.fillText(l,6,0+r*ce.lineHeight),r+=1}}}async function Y6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n)for(let r of t){n.font=ce.font,n.strokeStyle=ce.color,n.fillStyle=ce.color,ce.drawBoxes&&K6(n,r.box[0],r.box[1],r.box[2],r.box[3]);let a=[];if(a.push(`face confidence: ${Math.trunc(100*r.confidence)}%`),r.genderConfidence&&a.push(`${r.gender||""} ${Math.trunc(100*r.genderConfidence)}% confident`),r.age&&a.push(`age: ${r.age||""}`),r.iris&&a.push(`iris distance: ${r.iris}`),r.emotion&&r.emotion.length>0){let s=r.emotion.map(i=>`${Math.trunc(100*i.score)}% ${i.emotion}`);a.push(s.join(" "))}r.angle&&r.angle.roll&&a.push(`roll: ${Math.trunc(100*r.angle.roll)/100} yaw:${Math.trunc(100*r.angle.yaw)/100} pitch:${Math.trunc(100*r.angle.pitch)/100}`),a.length===0&&a.push("face"),n.fillStyle=ce.color;for(let s=a.length-1;s>=0;s--){let i=Math.max(r.box[0],0),o=s*ce.lineHeight+r.box[1];ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(a[s],i+5,o+16)),n.fillStyle=ce.labelColor,n.fillText(a[s],i+4,o+15)}if(n.lineWidth=1,r.mesh){if(ce.drawPoints)for(let s of r.mesh)n.fillStyle=ce.useDepth?`rgba(${127.5+2*s[2]}, ${127.5-2*s[2]}, 255, 0.5)`:ce.color,u0(n,s[0],s[1]);if(ce.drawPolygons){for(let s=0;sr.mesh[o]);n.strokeStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.fillStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.lineWidth=1,Z2(n,i)}if(r.annotations&&r.annotations.leftEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.leftEyeIris[3][0]-r.annotations.leftEyeIris[1][0])/2,i=Math.abs(r.annotations.leftEyeIris[4][1]-r.annotations.leftEyeIris[2][1])/2;n.ellipse(r.annotations.leftEyeIris[0][0],r.annotations.leftEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}if(r.annotations&&r.annotations.rightEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.rightEyeIris[3][0]-r.annotations.rightEyeIris[1][0])/2,i=Math.abs(r.annotations.rightEyeIris[4][1]-r.annotations.rightEyeIris[2][1])/2;n.ellipse(r.annotations.rightEyeIris[0][0],r.annotations.rightEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}}}}}var ja=[];async function J6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round";for(let r=0;ri.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s.length===5&&Z2(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s)}}}}async function Q6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round",n.font=ce.font;for(let r of t){if(ce.drawBoxes&&(n.strokeStyle=ce.color,n.fillStyle=ce.color,K6(n,r.box[0],r.box[1],r.box[2],r.box[3]),ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText("hand",r.box[0]+3,1+r.box[1]+ce.lineHeight,r.box[2])),n.fillStyle=ce.labelColor,n.fillText("hand",r.box[0]+2,0+r.box[1]+ce.lineHeight,r.box[2]),n.stroke()),ce.drawPoints&&r.landmarks&&r.landmarks.length>0)for(let a of r.landmarks)n.fillStyle=ce.useDepth?`rgba(${127.5+2*a[2]}, ${127.5-2*a[2]}, 255, 0.5)`:ce.color,u0(n,a[0],a[1]);if(ce.drawPolygons){let a=s=>{if(!!s)for(let i=0;i0?i-1:0][0],s[i>0?i-1:0][1]),n.lineTo(s[i][0],s[i][1]),n.stroke()};a(r.annotations.indexFinger),a(r.annotations.middleFinger),a(r.annotations.ringFinger),a(r.annotations.pinky),a(r.annotations.thumb)}}}}async function Cae(e,t){if(!e||!t||!(e instanceof HTMLCanvasElement)||!(t instanceof HTMLCanvasElement))return;let n=e.getContext("2d");n==null||n.drawImage(e,0,0)}async function Rae(e,t){!t||!e||e instanceof HTMLCanvasElement&&(Y6(e,t.face),J6(e,t.body),Q6(e,t.hand),Z6(e,t.gesture))}var ct=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function Cc(...e){let t=n=>n&&typeof n=="object";return e.reduce((n,r)=>(Object.keys(r||{}).forEach(a=>{let s=n[a],i=r[a];Array.isArray(s)&&Array.isArray(i)?n[a]=s.concat(...i):t(s)&&t(i)?n[a]=Cc(s,i):n[a]=i}),n),{})}var t4=class{constructor(t={}){this.calculateFaceAngle=t=>{if(!t||t.length<300)return{};let n=(s,i,o,l)=>Math.atan2(l-i,o-s),r=s=>Math.abs(s*180/Math.PI%360);return{roll:n(t[33][0],t[33][1],t[263][0],t[263][1]),yaw:n(t[33][0],t[33][2],t[263][0],t[263][2]),pitch:n(t[10][1],t[10][2],t[152][1],t[152][2])}};this.tf=nh,this.draw=K2,this.package=q2,this.version=X2,this.config=Cc(pt,t),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=n=>G2(n,this.config),this.facemesh=e4,this.age=s2,this.gender=l2,this.emotion=f2,this.body=this.config.body.modelType.startsWith("posenet")?M2:U2,this.hand=L2,this.sysinfo=cg()}profile(){return this.config.profile?n2:{}}analyze(...t){if(!this.analyzeMemoryLeaks)return;let n=this.tf.engine().state.numTensors,r=this.numTensors;this.numTensors=n;let a=n-r;a!==0&&Se(...t,a)}sanity(t){if(!this.checkSanity)return null;if(!t)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(t instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(n){return"backend not loaded"}return null}simmilarity(t,n){return this.config.face.embedding.enabled?Qv(t,n):0}async load(t=null){this.state="load";let n=ct();t&&(this.config=Cc(this.config,t)),this.firstRun&&(this.config.debug&&Se(`version: ${this.version}`),this.config.debug&&Se(`tfjs version: ${this.tf.version_core}`),this.config.debug&&Se("platform:",this.sysinfo.platform),this.config.debug&&Se("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&Se("configuration:",this.config),this.config.debug&&Se("tf flags:",this.tf.ENV.flags)));let r=this.config.face.detector.modelPath.includes("faceboxes")?r2:e4;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?r.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?i2(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?d2(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?y2(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?x2(this.config):null),this.models.handpose||(this.config.hand.enabled?V2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?$2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?H2(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await r.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await i2(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await d2(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await y2(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await x2(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await V2(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await $2(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await H2(this.config))),this.firstRun&&(this.config.debug&&Se("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let a=Math.trunc(ct()-n);a>(this.perf.load||0)&&(this.perf.load=a)}async checkBackend(t=!1){if(this.config.backend&&this.config.backend!==""&&t||this.tf.getBackend()!==this.config.backend){let n=ct();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&Se("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&Se("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let r=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),a=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&Se(`wasm execution: ${r?"SIMD":"no SIMD"} ${a?"multithreaded":"singlethreaded"}`),r||Se("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&Wv();try{await this.tf.setBackend(this.config.backend)}catch(r){Se("error: cannot set backend:",this.config.backend,r)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(Se("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let r=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&Se(`gl version:${r.getParameter(r.VERSION)} renderer:${r.getParameter(r.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(ct()-n)}}async detectFace(t){var u,c,h,d,p,m;let n,r,a,s,i,o=[];this.state="run:face",n=ct();let l=await((u=this.models.face)==null?void 0:u.estimateFaces(t,this.config));this.perf.face=Math.trunc(ct()-n);for(let f of l){if(this.analyze("Get Face"),!f.image||f.image.isDisposedInternal){Se("Face object is disposed:",f.image);continue}let A=this.calculateFaceAngle(f.mesh);this.analyze("Start Age:"),this.config.async?r=this.config.face.age.enabled?o2(f.image,this.config):{}:(this.state="run:age",n=ct(),r=this.config.face.age.enabled?await o2(f.image,this.config):{},this.perf.age=Math.trunc(ct()-n)),this.analyze("Start Gender:"),this.config.async?a=this.config.face.gender.enabled?p2(f.image,this.config):{}:(this.state="run:gender",n=ct(),a=this.config.face.gender.enabled?await p2(f.image,this.config):{},this.perf.gender=Math.trunc(ct()-n)),this.analyze("Start Emotion:"),this.config.async?s=this.config.face.emotion.enabled?g2(f.image,this.config):{}:(this.state="run:emotion",n=ct(),s=this.config.face.emotion.enabled?await g2(f.image,this.config):{},this.perf.emotion=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?i=this.config.face.embedding.enabled?w2(f.image,this.config):[]:(this.state="run:embedding",n=ct(),i=this.config.face.embedding.enabled?await w2(f.image,this.config):[],this.perf.embedding=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.config.async&&([r,a,s,i]=await Promise.all([r,a,s,i])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((c=f==null?void 0:f.annotations)==null?void 0:c.leftEyeIris)&&((h=f==null?void 0:f.annotations)==null?void 0:h.rightEyeIris)&&(delete f.annotations.leftEyeIris,delete f.annotations.rightEyeIris);let y=((d=f.annotations)==null?void 0:d.leftEyeIris)&&((p=f.annotations)==null?void 0:p.rightEyeIris)?11.7*Math.max(Math.abs(f.annotations.leftEyeIris[3][0]-f.annotations.leftEyeIris[1][0]),Math.abs(f.annotations.rightEyeIris[4][1]-f.annotations.rightEyeIris[2][1])):0;o.push({confidence:f.confidence,faceConfidence:f.faceConfidence,boxConfidence:f.boxConfidence,box:f.box,mesh:f.mesh,boxRaw:f.boxRaw,meshRaw:f.meshRaw,annotations:f.annotations,age:r.age,gender:a.gender,genderConfidence:a.confidence,emotion:s,embedding:i,iris:y!==0?Math.trunc(y)/100:0,angle:A}),(m=f.image)==null||m.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),o}async detect(t,n={}){return new Promise(async r=>{var d,p,m,f;this.state="config";let a;this.config=Cc(this.config,n),this.state="check";let s=this.sanity(t);s&&(Se(s,t),r({error:s}));let i=ct();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),a=ct();let o=G2(t,this.config);if(!o||!o.tensor){Se("could not convert input to tensor"),r({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(ct()-a),this.analyze("Get Image:");let l,u,c;this.config.async?(c=this.config.face.enabled?this.detectFace(o.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",a=ct(),c=this.config.face.enabled?await this.detectFace(o.tensor):[],this.perf.face=Math.trunc(ct()-a)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?(d=this.models.posenet)==null?void 0:d.estimatePoses(o.tensor,this.config):[]:l=this.config.body.enabled?j2(o.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",a=ct(),this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?await((p=this.models.posenet)==null?void 0:p.estimatePoses(o.tensor,this.config)):[]:l=this.config.body.enabled?await j2(o.tensor,this.config):[],this.perf.body=Math.trunc(ct()-a)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(u=this.config.hand.enabled?(m=this.models.handpose)==null?void 0:m.estimateHands(o.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",a=ct(),u=this.config.hand.enabled?await((f=this.models.handpose)==null?void 0:f.estimateHands(o.tensor,this.config)):[],this.perf.hand=Math.trunc(ct()-a)),this.analyze("End Hand:"),this.config.async&&([c,l,u]=await Promise.all([c,l,u])),o.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let h=[];this.config.gesture.enabled&&(a=ct(),h=[...T6(c),...S6(l),...C6(u),...E6(c)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(ct()-a)),this.perf.total=Math.trunc(ct()-i),this.state="idle",r({face:c,body:l,hand:u,gesture:h,performance:this.perf,canvas:o.canvas})})}async warmupBitmap(){let t=(a,s="application/octet-stream")=>fetch(`data:${s};base64,${a}`).then(i=>i.blob()),n,r;switch(this.config.warmup){case"face":n=await t(o0);break;case"full":n=await t(l0);break;default:n=null}if(n){let a=await createImageBitmap(n);r=await this.detect(a,this.config),a.close()}return r}async warmupCanvas(){return new Promise(t=>{let n,r=0;switch(this.config.warmup){case"face":r=256,n="data:image/jpeg;base64,"+o0;break;case"full":case"body":r=1200,n="data:image/jpeg;base64,"+l0;break;default:n=null}let a=new Image;a.onload=async()=>{let s=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(r,r):document.createElement("canvas");s.width=a.naturalWidth,s.height=a.naturalHeight;let i=s.getContext("2d");i==null||i.drawImage(a,0,0);let o=await this.detect(s,this.config);t(o)},n?a.src=n:t(null)})}async warmupNode(){let t=i=>Buffer.from(i,"base64"),n=this.config.warmup==="face"?t(o0):t(l0),r=(void 0).decodeJpeg(n),a=r.expandDims(0);this.tf.dispose(r);let s=await this.detect(a,this.config);return this.tf.dispose(a),s}async warmup(t){let n=ct();t&&(this.config=Cc(this.config,t));let r=this.config.videoOptimized;this.config.videoOptimized=!1;let a;typeof createImageBitmap=="function"?a=await this.warmupBitmap():typeof Image!="undefined"?a=await this.warmupCanvas():a=await this.warmupNode(),this.config.videoOptimized=r;let s=ct();return this.config.debug&&Se("Warmup",this.config.warmup,Math.round(s-n),"ms",a),a}};export{t4 as default}; +2Q==`;var q2={};Jn(q2,{author:()=>L6,browser:()=>z6,bugs:()=>W6,default:()=>Eae,description:()=>F6,devDependencies:()=>G6,engines:()=>U6,homepage:()=>B6,keywords:()=>X6,license:()=>V6,main:()=>O6,module:()=>D6,name:()=>M6,peerDependencies:()=>j6,repository:()=>H6,scripts:()=>q6,sideEffects:()=>$6,types:()=>P6,version:()=>X2});var M6="@vladmandic/human",X2="1.0.1",F6="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",$6=!1,O6="dist/human.node.js",D6="dist/human.esm.js",z6="dist/human.esm.js",P6="types/human.d.ts",L6="Vladimir Mandic ",W6={url:"https://github.com/vladmandic/human/issues"},B6="https://vladmandic.github.io/human/demo/index.html",V6="MIT",U6={node:">=12.0.0"},H6={type:"git",url:"git+https://github.com/vladmandic/human.git"},j6={},G6={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},q6={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},X6=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Eae={name:M6,version:X2,description:F6,sideEffects:$6,main:O6,module:D6,browser:z6,types:P6,author:L6,bugs:W6,homepage:B6,license:V6,engines:U6,repository:H6,peerDependencies:j6,devDependencies:G6,scripts:q6,keywords:X6};var K2={};Jn(K2,{all:()=>Rae,body:()=>J6,canvas:()=>Cae,face:()=>Y6,gesture:()=>Z6,hand:()=>Q6,options:()=>ce});var ce={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function u0(e,t,n){e.fillStyle=ce.color,e.beginPath(),e.arc(t,n,ce.pointSize,0,2*Math.PI),e.fill()}function K6(e,t,n,r,a){if(e.beginPath(),ce.useCurves){let s=(t+t+r)/2,i=(n+n+a)/2;e.ellipse(s,i,r/2,a/2,0,0,2*Math.PI)}else e.lineWidth=ce.lineWidth,e.moveTo(t+ce.roundRect,n),e.lineTo(t+r-ce.roundRect,n),e.quadraticCurveTo(t+r,n,t+r,n+ce.roundRect),e.lineTo(t+r,n+a-ce.roundRect),e.quadraticCurveTo(t+r,n+a,t+r-ce.roundRect,n+a),e.lineTo(t+ce.roundRect,n+a),e.quadraticCurveTo(t,n+a,t,n+a-ce.roundRect),e.lineTo(t,n+ce.roundRect),e.quadraticCurveTo(t,n,t+ce.roundRect,n),e.closePath();e.stroke()}function Z2(e,t=[]){if(!(t===void 0||t.length===0)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.lineTo(n[0],parseInt(n[1]));e.stroke(),ce.fillPolygons&&(e.closePath(),e.fill())}}function c0(e,t=[]){if(!(t===void 0||t.length===0)){if(!ce.useCurves||t.length<=2){Z2(e,t);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;n1&&i[1].length>0){let o=s[1]>0?`#${s[1]}`:"",l=`${s[0]} ${o}: ${i[1]}`;ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(l,8,2+r*ce.lineHeight)),n.fillStyle=ce.labelColor,n.fillText(l,6,0+r*ce.lineHeight),r+=1}}}async function Y6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n)for(let r of t){n.font=ce.font,n.strokeStyle=ce.color,n.fillStyle=ce.color,ce.drawBoxes&&K6(n,r.box[0],r.box[1],r.box[2],r.box[3]);let a=[];if(a.push(`face confidence: ${Math.trunc(100*r.confidence)}%`),r.genderConfidence&&a.push(`${r.gender||""} ${Math.trunc(100*r.genderConfidence)}% confident`),r.age&&a.push(`age: ${r.age||""}`),r.iris&&a.push(`iris distance: ${r.iris}`),r.emotion&&r.emotion.length>0){let s=r.emotion.map(i=>`${Math.trunc(100*i.score)}% ${i.emotion}`);a.push(s.join(" "))}r.angle&&r.angle.roll&&a.push(`roll: ${Math.trunc(100*r.angle.roll)/100} yaw:${Math.trunc(100*r.angle.yaw)/100} pitch:${Math.trunc(100*r.angle.pitch)/100}`),a.length===0&&a.push("face"),n.fillStyle=ce.color;for(let s=a.length-1;s>=0;s--){let i=Math.max(r.box[0],0),o=s*ce.lineHeight+r.box[1];ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(a[s],i+5,o+16)),n.fillStyle=ce.labelColor,n.fillText(a[s],i+4,o+15)}if(n.lineWidth=1,r.mesh){if(ce.drawPoints)for(let s of r.mesh)n.fillStyle=ce.useDepth?`rgba(${127.5+2*s[2]}, ${127.5-2*s[2]}, 255, 0.5)`:ce.color,u0(n,s[0],s[1]);if(ce.drawPolygons){for(let s=0;sr.mesh[o]);n.strokeStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.fillStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.lineWidth=1,Z2(n,i)}if(r.annotations&&r.annotations.leftEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.leftEyeIris[3][0]-r.annotations.leftEyeIris[1][0])/2,i=Math.abs(r.annotations.leftEyeIris[4][1]-r.annotations.leftEyeIris[2][1])/2;n.ellipse(r.annotations.leftEyeIris[0][0],r.annotations.leftEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}if(r.annotations&&r.annotations.rightEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.rightEyeIris[3][0]-r.annotations.rightEyeIris[1][0])/2,i=Math.abs(r.annotations.rightEyeIris[4][1]-r.annotations.rightEyeIris[2][1])/2;n.ellipse(r.annotations.rightEyeIris[0][0],r.annotations.rightEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}}}}}var ja=[];async function J6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round";for(let r=0;ri.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s.length===5&&Z2(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s)}}}}async function Q6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round",n.font=ce.font;for(let r of t){if(ce.drawBoxes&&(n.strokeStyle=ce.color,n.fillStyle=ce.color,K6(n,r.box[0],r.box[1],r.box[2],r.box[3]),ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText("hand",r.box[0]+3,1+r.box[1]+ce.lineHeight,r.box[2])),n.fillStyle=ce.labelColor,n.fillText("hand",r.box[0]+2,0+r.box[1]+ce.lineHeight,r.box[2]),n.stroke()),ce.drawPoints&&r.landmarks&&r.landmarks.length>0)for(let a of r.landmarks)n.fillStyle=ce.useDepth?`rgba(${127.5+2*a[2]}, ${127.5-2*a[2]}, 255, 0.5)`:ce.color,u0(n,a[0],a[1]);if(ce.drawPolygons){let a=s=>{if(!!s)for(let i=0;i0?i-1:0][0],s[i>0?i-1:0][1]),n.lineTo(s[i][0],s[i][1]),n.stroke()};a(r.annotations.indexFinger),a(r.annotations.middleFinger),a(r.annotations.ringFinger),a(r.annotations.pinky),a(r.annotations.thumb)}}}}async function Cae(e,t){if(!e||!t||!(e instanceof HTMLCanvasElement)||!(t instanceof HTMLCanvasElement))return;let n=e.getContext("2d");n==null||n.drawImage(e,0,0)}async function Rae(e,t){!t||!e||e instanceof HTMLCanvasElement&&(Y6(e,t.face),J6(e,t.body),Q6(e,t.hand),Z6(e,t.gesture))}var ct=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function Cc(...e){let t=n=>n&&typeof n=="object";return e.reduce((n,r)=>(Object.keys(r||{}).forEach(a=>{let s=n[a],i=r[a];Array.isArray(s)&&Array.isArray(i)?n[a]=s.concat(...i):t(s)&&t(i)?n[a]=Cc(s,i):n[a]=i}),n),{})}var t4=class{constructor(t={}){this.calculateFaceAngle=t=>{if(!t||t.length<300)return{};let n=(s,i,o,l)=>Math.atan2(l-i,o-s),r=s=>Math.abs(s*180/Math.PI%360);return{roll:n(t[33][0],t[33][1],t[263][0],t[263][1]),yaw:n(t[33][0],t[33][2],t[263][0],t[263][2]),pitch:n(t[10][1],t[10][2],t[152][1],t[152][2])}};this.tf=nh,this.draw=K2,this.package=q2,this.version=X2,this.config=Cc(pt,t),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=n=>G2(n,this.config),this.facemesh=e4,this.age=s2,this.gender=l2,this.emotion=f2,this.body=this.config.body.modelType.startsWith("posenet")?M2:U2,this.hand=L2,this.sysinfo=cg()}profile(){return this.config.profile?n2:{}}analyze(...t){if(!this.analyzeMemoryLeaks)return;let n=this.tf.engine().state.numTensors,r=this.numTensors;this.numTensors=n;let a=n-r;a!==0&&Se(...t,a)}sanity(t){if(!this.checkSanity)return null;if(!t)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(t instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(n){return"backend not loaded"}return null}simmilarity(t,n){return this.config.face.embedding.enabled?Qv(t,n):0}async load(t=null){this.state="load";let n=ct();t&&(this.config=Cc(this.config,t)),this.firstRun&&(this.config.debug&&Se(`version: ${this.version}`),this.config.debug&&Se(`tfjs version: ${this.tf.version_core}`),this.config.debug&&Se("platform:",this.sysinfo.platform),this.config.debug&&Se("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&Se("configuration:",this.config),this.config.debug&&Se("tf flags:",this.tf.ENV.flags)));let r=this.config.face.detector.modelPath.includes("faceboxes")?r2:e4;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?r.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?i2(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?d2(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?y2(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?x2(this.config):null),this.models.handpose||(this.config.hand.enabled?V2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?$2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?H2(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await r.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await i2(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await d2(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await y2(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await x2(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await V2(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await $2(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await H2(this.config))),this.firstRun&&(this.config.debug&&Se("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let a=Math.trunc(ct()-n);a>(this.perf.load||0)&&(this.perf.load=a)}async checkBackend(t=!1){if(this.config.backend&&this.config.backend!==""&&t||this.tf.getBackend()!==this.config.backend){let n=ct();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&Se("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&Se("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let r=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),a=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&Se(`wasm execution: ${r?"SIMD":"no SIMD"} ${a?"multithreaded":"singlethreaded"}`),r||Se("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&Wv();try{await this.tf.setBackend(this.config.backend)}catch(r){Se("error: cannot set backend:",this.config.backend,r)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(Se("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let r=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&Se(`gl version:${r.getParameter(r.VERSION)} renderer:${r.getParameter(r.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(ct()-n)}}async detectFace(t){var u,c,h,d,p,m;let n,r,a,s,i,o=[];this.state="run:face",n=ct();let l=await((u=this.models.face)==null?void 0:u.estimateFaces(t,this.config));this.perf.face=Math.trunc(ct()-n);for(let f of l){if(this.analyze("Get Face"),!f.image||f.image.isDisposedInternal){Se("Face object is disposed:",f.image);continue}let A=this.calculateFaceAngle(f.mesh);this.analyze("Start Age:"),this.config.async?r=this.config.face.age.enabled?o2(f.image,this.config):{}:(this.state="run:age",n=ct(),r=this.config.face.age.enabled?await o2(f.image,this.config):{},this.perf.age=Math.trunc(ct()-n)),this.analyze("Start Gender:"),this.config.async?a=this.config.face.gender.enabled?p2(f.image,this.config):{}:(this.state="run:gender",n=ct(),a=this.config.face.gender.enabled?await p2(f.image,this.config):{},this.perf.gender=Math.trunc(ct()-n)),this.analyze("Start Emotion:"),this.config.async?s=this.config.face.emotion.enabled?g2(f.image,this.config):{}:(this.state="run:emotion",n=ct(),s=this.config.face.emotion.enabled?await g2(f.image,this.config):{},this.perf.emotion=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?i=this.config.face.embedding.enabled?w2(f.image,this.config):[]:(this.state="run:embedding",n=ct(),i=this.config.face.embedding.enabled?await w2(f.image,this.config):[],this.perf.embedding=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.config.async&&([r,a,s,i]=await Promise.all([r,a,s,i])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((c=f==null?void 0:f.annotations)==null?void 0:c.leftEyeIris)&&((h=f==null?void 0:f.annotations)==null?void 0:h.rightEyeIris)&&(delete f.annotations.leftEyeIris,delete f.annotations.rightEyeIris);let y=((d=f.annotations)==null?void 0:d.leftEyeIris)&&((p=f.annotations)==null?void 0:p.rightEyeIris)?11.7*Math.max(Math.abs(f.annotations.leftEyeIris[3][0]-f.annotations.leftEyeIris[1][0]),Math.abs(f.annotations.rightEyeIris[4][1]-f.annotations.rightEyeIris[2][1])):0;o.push({confidence:f.confidence,faceConfidence:f.faceConfidence,boxConfidence:f.boxConfidence,box:f.box,mesh:f.mesh,boxRaw:f.boxRaw,meshRaw:f.meshRaw,annotations:f.annotations,age:r.age,gender:a.gender,genderConfidence:a.confidence,emotion:s,embedding:i,iris:y!==0?Math.trunc(y)/100:0,angle:A}),(m=f.image)==null||m.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),o}async detect(t,n={}){return new Promise(async r=>{var d,p,m,f;this.state="config";let a;this.config=Cc(this.config,n),this.state="check";let s=this.sanity(t);s&&(Se(s,t),r({error:s}));let i=ct();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),a=ct();let o=G2(t,this.config);if(!o||!o.tensor){Se("could not convert input to tensor"),r({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(ct()-a),this.analyze("Get Image:");let l,u,c;this.config.async?(c=this.config.face.enabled?this.detectFace(o.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",a=ct(),c=this.config.face.enabled?await this.detectFace(o.tensor):[],this.perf.face=Math.trunc(ct()-a)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?(d=this.models.posenet)==null?void 0:d.estimatePoses(o.tensor,this.config):[]:l=this.config.body.enabled?j2(o.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",a=ct(),this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?await((p=this.models.posenet)==null?void 0:p.estimatePoses(o.tensor,this.config)):[]:l=this.config.body.enabled?await j2(o.tensor,this.config):[],this.perf.body=Math.trunc(ct()-a)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(u=this.config.hand.enabled?(m=this.models.handpose)==null?void 0:m.estimateHands(o.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",a=ct(),u=this.config.hand.enabled?await((f=this.models.handpose)==null?void 0:f.estimateHands(o.tensor,this.config)):[],this.perf.hand=Math.trunc(ct()-a)),this.analyze("End Hand:"),this.config.async&&([c,l,u]=await Promise.all([c,l,u])),o.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let h=[];this.config.gesture.enabled&&(a=ct(),h=[...T6(c),...S6(l),...C6(u),...E6(c)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(ct()-a)),this.perf.total=Math.trunc(ct()-i),this.state="idle",r({face:c,body:l,hand:u,gesture:h,performance:this.perf,canvas:o.canvas})})}async warmupBitmap(){let t=(a,s="application/octet-stream")=>fetch(`data:${s};base64,${a}`).then(i=>i.blob()),n,r;switch(this.config.warmup){case"face":n=await t(o0);break;case"full":n=await t(l0);break;default:n=null}if(n){let a=await createImageBitmap(n);r=await this.detect(a,this.config),a.close()}return r}async warmupCanvas(){return new Promise(t=>{let n,r=0;switch(this.config.warmup){case"face":r=256,n="data:image/jpeg;base64,"+o0;break;case"full":case"body":r=1200,n="data:image/jpeg;base64,"+l0;break;default:n=null}let a=new Image;a.onload=async()=>{let s=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(r,r):document.createElement("canvas");s.width=a.naturalWidth,s.height=a.naturalHeight;let i=s.getContext("2d");i==null||i.drawImage(a,0,0);let o=await this.detect(s,this.config);t(o)},n?a.src=n:t(null)})}async warmupNode(){let t=i=>Buffer.from(i,"base64"),n=this.config.warmup==="face"?t(o0):t(l0),r=(void 0).decodeJpeg(n),a=r.expandDims(0);this.tf.dispose(r);let s=await this.detect(a,this.config);return this.tf.dispose(a),s}async warmup(t){let n=ct();t&&(this.config=Cc(this.config,t));let r=this.config.videoOptimized;this.config.videoOptimized=!1;let a;typeof createImageBitmap=="function"?a=await this.warmupBitmap():typeof Image!="undefined"?a=await this.warmupCanvas():a=await this.warmupNode(),this.config.videoOptimized=r;let s=ct();return this.config.debug&&Se("Warmup",this.config.warmup,Math.round(s-n),"ms",a),a}};export{t4 as default}; /** * @license * Copyright 2017 Google LLC. All Rights Reserved. diff --git a/dist/human.node-gpu.js b/dist/human.node-gpu.js index dc9e500e..fef8ee22 100644 --- a/dist/human.node-gpu.js +++ b/dist/human.node-gpu.js @@ -731,5 +731,5 @@ AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ -2Q==`;var F1={};q(F1,{author:()=>nt,browser:()=>et,bugs:()=>rt,default:()=>Wn,description:()=>D0,devDependencies:()=>st,engines:()=>_t,homepage:()=>At,keywords:()=>xt,license:()=>ct,main:()=>Q0,module:()=>$0,name:()=>U0,peerDependencies:()=>ot,repository:()=>ht,scripts:()=>it,sideEffects:()=>G0,types:()=>tt,version:()=>q1});var U0="@vladmandic/human",q1="1.0.0",D0="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",G0=!1,Q0="dist/human.node.js",$0="dist/human.esm.js",et="dist/human.esm.js",tt="types/human.d.ts",nt="Vladimir Mandic ",rt={url:"https://github.com/vladmandic/human/issues"},At="https://vladmandic.github.io/human/demo/index.html",ct="MIT",_t={node:">=12.0.0"},ht={type:"git",url:"git+https://github.com/vladmandic/human.git"},ot={},st={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},it={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},xt=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Wn={name:U0,version:q1,description:D0,sideEffects:G0,main:Q0,module:$0,browser:et,types:tt,author:nt,bugs:rt,homepage:At,license:ct,engines:_t,repository:ht,peerDependencies:ot,devDependencies:st,scripts:it,keywords:xt};var Y1={};q(Y1,{all:()=>jn,body:()=>dt,canvas:()=>Nn,face:()=>wt,gesture:()=>at,hand:()=>lt,options:()=>d});var d={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function Oe(n,e,t){n.fillStyle=d.color,n.beginPath(),n.arc(e,t,d.pointSize,0,2*Math.PI),n.fill()}function yt(n,e,t,A,r){if(n.beginPath(),d.useCurves){let c=(e+e+A)/2,_=(t+t+r)/2;n.ellipse(c,_,A/2,r/2,0,0,2*Math.PI)}else n.lineWidth=d.lineWidth,n.moveTo(e+d.roundRect,t),n.lineTo(e+A-d.roundRect,t),n.quadraticCurveTo(e+A,t,e+A,t+d.roundRect),n.lineTo(e+A,t+r-d.roundRect),n.quadraticCurveTo(e+A,t+r,e+A-d.roundRect,t+r),n.lineTo(e+d.roundRect,t+r),n.quadraticCurveTo(e,t+r,e,t+r-d.roundRect),n.lineTo(e,t+d.roundRect),n.quadraticCurveTo(e,t,e+d.roundRect,t),n.closePath();n.stroke()}function J1(n,e=[]){if(!(e===void 0||e.length===0)){n.beginPath(),n.moveTo(e[0][0],e[0][1]);for(let t of e)n.lineTo(t[0],parseInt(t[1]));n.stroke(),d.fillPolygons&&(n.closePath(),n.fill())}}function Ie(n,e=[]){if(!(e===void 0||e.length===0)){if(!d.useCurves||e.length<=2){J1(n,e);return}n.moveTo(e[0][0],e[0][1]);for(let t=0;t1&&_[1].length>0){let h=c[1]>0?`#${c[1]}`:"",o=`${c[0]} ${h}: ${_[1]}`;d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(o,8,2+A*d.lineHeight)),t.fillStyle=d.labelColor,t.fillText(o,6,0+A*d.lineHeight),A+=1}}}async function wt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t)for(let A of e){t.font=d.font,t.strokeStyle=d.color,t.fillStyle=d.color,d.drawBoxes&&yt(t,A.box[0],A.box[1],A.box[2],A.box[3]);let r=[];if(r.push(`face confidence: ${Math.trunc(100*A.confidence)}%`),A.genderConfidence&&r.push(`${A.gender||""} ${Math.trunc(100*A.genderConfidence)}% confident`),A.age&&r.push(`age: ${A.age||""}`),A.iris&&r.push(`iris distance: ${A.iris}`),A.emotion&&A.emotion.length>0){let c=A.emotion.map(_=>`${Math.trunc(100*_.score)}% ${_.emotion}`);r.push(c.join(" "))}A.angle&&A.angle.roll&&r.push(`roll: ${Math.trunc(100*A.angle.roll)/100} yaw:${Math.trunc(100*A.angle.yaw)/100} pitch:${Math.trunc(100*A.angle.pitch)/100}`),r.length===0&&r.push("face"),t.fillStyle=d.color;for(let c=r.length-1;c>=0;c--){let _=Math.max(A.box[0],0),h=c*d.lineHeight+A.box[1];d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(r[c],_+5,h+16)),t.fillStyle=d.labelColor,t.fillText(r[c],_+4,h+15)}if(t.lineWidth=1,A.mesh){if(d.drawPoints)for(let c of A.mesh)t.fillStyle=d.useDepth?`rgba(${127.5+2*c[2]}, ${127.5-2*c[2]}, 255, 0.5)`:d.color,Oe(t,c[0],c[1]);if(d.drawPolygons){for(let c=0;cA.mesh[h]);t.strokeStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.fillStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.lineWidth=1,J1(t,_)}if(A.annotations&&A.annotations.leftEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.leftEyeIris[3][0]-A.annotations.leftEyeIris[1][0])/2,_=Math.abs(A.annotations.leftEyeIris[4][1]-A.annotations.leftEyeIris[2][1])/2;t.ellipse(A.annotations.leftEyeIris[0][0],A.annotations.leftEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}if(A.annotations&&A.annotations.rightEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.rightEyeIris[3][0]-A.annotations.rightEyeIris[1][0])/2,_=Math.abs(A.annotations.rightEyeIris[4][1]-A.annotations.rightEyeIris[2][1])/2;t.ellipse(A.annotations.rightEyeIris[0][0],A.annotations.rightEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}}}}}var ne=[];async function dt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round";for(let A=0;A_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),c.length===5&&J1(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c)}}}}async function lt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round",t.font=d.font;for(let A of e){if(d.drawBoxes&&(t.strokeStyle=d.color,t.fillStyle=d.color,yt(t,A.box[0],A.box[1],A.box[2],A.box[3]),d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText("hand",A.box[0]+3,1+A.box[1]+d.lineHeight,A.box[2])),t.fillStyle=d.labelColor,t.fillText("hand",A.box[0]+2,0+A.box[1]+d.lineHeight,A.box[2]),t.stroke()),d.drawPoints&&A.landmarks&&A.landmarks.length>0)for(let r of A.landmarks)t.fillStyle=d.useDepth?`rgba(${127.5+2*r[2]}, ${127.5-2*r[2]}, 255, 0.5)`:d.color,Oe(t,r[0],r[1]);if(d.drawPolygons){let r=c=>{if(!!c)for(let _=0;_0?_-1:0][0],c[_>0?_-1:0][1]),t.lineTo(c[_][0],c[_][1]),t.stroke()};r(A.annotations.indexFinger),r(A.annotations.middleFinger),r(A.annotations.ringFinger),r(A.annotations.pinky),r(A.annotations.thumb)}}}}async function Nn(n,e){if(!n||!e||!(n instanceof HTMLCanvasElement)||!(e instanceof HTMLCanvasElement))return;let t=n.getContext("2d");t==null||t.drawImage(n,0,0)}async function jn(n,e){!e||!n||n instanceof HTMLCanvasElement&&(wt(n,e.face),dt(n,e.body),lt(n,e.hand),at(n,e.gesture))}var P=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function we(...n){let e=t=>t&&typeof t=="object";return n.reduce((t,A)=>(Object.keys(A||{}).forEach(r=>{let c=t[r],_=A[r];Array.isArray(c)&&Array.isArray(_)?t[r]=c.concat(..._):e(c)&&e(_)?t[r]=we(c,_):t[r]=_}),t),{})}var mt=class{constructor(e={}){this.calculateFaceAngle=e=>{if(!e||e.length<300)return{};let t=(c,_,h,o)=>Math.atan2(o-_,h-c),A=c=>Math.abs(c*180/Math.PI%360);return{roll:t(e[33][0],e[33][1],e[263][0],e[263][1]),yaw:t(e[33][0],e[33][2],e[263][0],e[263][2]),pitch:t(e[10][1],e[10][2],e[152][1],e[152][2])}};this.tf=ft,this.draw=Y1,this.package=F1,this.version=q1,this.config=we(v,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>X1(t,this.config),this.facemesh=pt,this.age=$e,this.gender=n1,this.emotion=o1,this.body=this.config.body.modelType.startsWith("posenet")?z1:V1,this.hand=j1,this.sysinfo=D1()}profile(){return this.config.profile?De:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,A=this.numTensors;this.numTensors=t;let r=t-A;r!==0&&m(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?a0(e,t):0}async load(e=null){this.state="load";let t=P();e&&(this.config=we(this.config,e)),this.firstRun&&(this.config.debug&&m(`version: ${this.version}`),this.config.debug&&m(`tfjs version: ${this.tf.version_core}`),this.config.debug&&m("platform:",this.sysinfo.platform),this.config.debug&&m("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&m("configuration:",this.config),this.config.debug&&m("tf flags:",this.tf.ENV.flags)));let A=this.config.face.detector.modelPath.includes("faceboxes")?Ge:pt;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?A.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?e1(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?_1(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?x1(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?a1(this.config):null),this.models.handpose||(this.config.hand.enabled?Z1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?M1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?L1(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await A.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await e1(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await _1(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await x1(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await a1(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await Z1(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await M1(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await L1(this.config))),this.firstRun&&(this.config.debug&&m("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(P()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=P();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&m("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&m("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let A=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&m(`wasm execution: ${A?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),A||m("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&$1();try{await this.tf.setBackend(this.config.backend)}catch(A){m("error: cannot set backend:",this.config.backend,A)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(m("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let A=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&m(`gl version:${A.getParameter(A.VERSION)} renderer:${A.getParameter(A.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(P()-t)}}async detectFace(e){var x,y,i,a,l,f;let t,A,r,c,_,h=[];this.state="run:face",t=P();let o=await((x=this.models.face)==null?void 0:x.estimateFaces(e,this.config));this.perf.face=Math.trunc(P()-t);for(let s of o){if(this.analyze("Get Face"),!s.image||s.image.isDisposedInternal){m("Face object is disposed:",s.image);continue}let k=this.calculateFaceAngle(s.mesh);this.analyze("Start Age:"),this.config.async?A=this.config.face.age.enabled?t1(s.image,this.config):{}:(this.state="run:age",t=P(),A=this.config.face.age.enabled?await t1(s.image,this.config):{},this.perf.age=Math.trunc(P()-t)),this.analyze("Start Gender:"),this.config.async?r=this.config.face.gender.enabled?h1(s.image,this.config):{}:(this.state="run:gender",t=P(),r=this.config.face.gender.enabled?await h1(s.image,this.config):{},this.perf.gender=Math.trunc(P()-t)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?y1(s.image,this.config):{}:(this.state="run:emotion",t=P(),c=this.config.face.emotion.enabled?await y1(s.image,this.config):{},this.perf.emotion=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?_=this.config.face.embedding.enabled?w1(s.image,this.config):[]:(this.state="run:embedding",t=P(),_=this.config.face.embedding.enabled?await w1(s.image,this.config):[],this.perf.embedding=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.config.async&&([A,r,c,_]=await Promise.all([A,r,c,_])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((y=s==null?void 0:s.annotations)==null?void 0:y.leftEyeIris)&&((i=s==null?void 0:s.annotations)==null?void 0:i.rightEyeIris)&&(delete s.annotations.leftEyeIris,delete s.annotations.rightEyeIris);let N=((a=s.annotations)==null?void 0:a.leftEyeIris)&&((l=s.annotations)==null?void 0:l.rightEyeIris)?11.7*Math.max(Math.abs(s.annotations.leftEyeIris[3][0]-s.annotations.leftEyeIris[1][0]),Math.abs(s.annotations.rightEyeIris[4][1]-s.annotations.rightEyeIris[2][1])):0;h.push({confidence:s.confidence,faceConfidence:s.faceConfidence,boxConfidence:s.boxConfidence,box:s.box,mesh:s.mesh,boxRaw:s.boxRaw,meshRaw:s.meshRaw,annotations:s.annotations,age:A.age,gender:r.gender,genderConfidence:r.confidence,emotion:c,embedding:_,iris:N!==0?Math.trunc(N)/100:0,angle:k}),(f=s.image)==null||f.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),h}async detect(e,t={}){return new Promise(async A=>{var a,l,f,s;this.state="config";let r;this.config=we(this.config,t),this.state="check";let c=this.sanity(e);c&&(m(c,e),A({error:c}));let _=P();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),r=P();let h=X1(e,this.config);if(!h||!h.tensor){m("could not convert input to tensor"),A({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(P()-r),this.analyze("Get Image:");let o,x,y;this.config.async?(y=this.config.face.enabled?this.detectFace(h.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",r=P(),y=this.config.face.enabled?await this.detectFace(h.tensor):[],this.perf.face=Math.trunc(P()-r)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?(a=this.models.posenet)==null?void 0:a.estimatePoses(h.tensor,this.config):[]:o=this.config.body.enabled?H1(h.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",r=P(),this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?await((l=this.models.posenet)==null?void 0:l.estimatePoses(h.tensor,this.config)):[]:o=this.config.body.enabled?await H1(h.tensor,this.config):[],this.perf.body=Math.trunc(P()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(x=this.config.hand.enabled?(f=this.models.handpose)==null?void 0:f.estimateHands(h.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",r=P(),x=this.config.hand.enabled?await((s=this.models.handpose)==null?void 0:s.estimateHands(h.tensor,this.config)):[],this.perf.hand=Math.trunc(P()-r)),this.analyze("End Hand:"),this.config.async&&([y,o,x]=await Promise.all([y,o,x])),h.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let i=[];this.config.gesture.enabled&&(r=P(),i=[...J0(y),...Y0(o),...C0(x),...B0(y)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(P()-r)),this.perf.total=Math.trunc(P()-_),this.state="idle",A({face:y,body:o,hand:x,gesture:i,performance:this.perf,canvas:h.canvas})})}async warmupBitmap(){let e=(r,c="application/octet-stream")=>fetch(`data:${c};base64,${r}`).then(_=>_.blob()),t,A;switch(this.config.warmup){case"face":t=await e(Ne);break;case"full":t=await e(je);break;default:t=null}if(t){let r=await createImageBitmap(t);A=await this.detect(r,this.config),r.close()}return A}async warmupCanvas(){return new Promise(e=>{let t,A=0;switch(this.config.warmup){case"face":A=256,t="data:image/jpeg;base64,"+Ne;break;case"full":case"body":A=1200,t="data:image/jpeg;base64,"+je;break;default:t=null}let r=new Image;r.onload=async()=>{let c=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(A,A):document.createElement("canvas");c.width=r.naturalWidth,c.height=r.naturalHeight;let _=c.getContext("2d");_==null||_.drawImage(r,0,0);let h=await this.detect(c,this.config);e(h)},t?r.src=t:e(null)})}async warmupNode(){let e=_=>Buffer.from(_,"base64"),t=this.config.warmup==="face"?e(Ne):e(je),A=ft.node.decodeJpeg(t),r=A.expandDims(0);this.tf.dispose(A);let c=await this.detect(r,this.config);return this.tf.dispose(r),c}async warmup(e){let t=P();e&&(this.config=we(this.config,e));let A=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=A;let c=P();return this.config.debug&&m("Warmup",this.config.warmup,Math.round(c-t),"ms",r),r}}; +2Q==`;var F1={};q(F1,{author:()=>nt,browser:()=>et,bugs:()=>rt,default:()=>Wn,description:()=>D0,devDependencies:()=>st,engines:()=>_t,homepage:()=>At,keywords:()=>xt,license:()=>ct,main:()=>Q0,module:()=>$0,name:()=>U0,peerDependencies:()=>ot,repository:()=>ht,scripts:()=>it,sideEffects:()=>G0,types:()=>tt,version:()=>q1});var U0="@vladmandic/human",q1="1.0.1",D0="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",G0=!1,Q0="dist/human.node.js",$0="dist/human.esm.js",et="dist/human.esm.js",tt="types/human.d.ts",nt="Vladimir Mandic ",rt={url:"https://github.com/vladmandic/human/issues"},At="https://vladmandic.github.io/human/demo/index.html",ct="MIT",_t={node:">=12.0.0"},ht={type:"git",url:"git+https://github.com/vladmandic/human.git"},ot={},st={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},it={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},xt=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Wn={name:U0,version:q1,description:D0,sideEffects:G0,main:Q0,module:$0,browser:et,types:tt,author:nt,bugs:rt,homepage:At,license:ct,engines:_t,repository:ht,peerDependencies:ot,devDependencies:st,scripts:it,keywords:xt};var Y1={};q(Y1,{all:()=>jn,body:()=>dt,canvas:()=>Nn,face:()=>wt,gesture:()=>at,hand:()=>lt,options:()=>d});var d={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function Oe(n,e,t){n.fillStyle=d.color,n.beginPath(),n.arc(e,t,d.pointSize,0,2*Math.PI),n.fill()}function yt(n,e,t,A,r){if(n.beginPath(),d.useCurves){let c=(e+e+A)/2,_=(t+t+r)/2;n.ellipse(c,_,A/2,r/2,0,0,2*Math.PI)}else n.lineWidth=d.lineWidth,n.moveTo(e+d.roundRect,t),n.lineTo(e+A-d.roundRect,t),n.quadraticCurveTo(e+A,t,e+A,t+d.roundRect),n.lineTo(e+A,t+r-d.roundRect),n.quadraticCurveTo(e+A,t+r,e+A-d.roundRect,t+r),n.lineTo(e+d.roundRect,t+r),n.quadraticCurveTo(e,t+r,e,t+r-d.roundRect),n.lineTo(e,t+d.roundRect),n.quadraticCurveTo(e,t,e+d.roundRect,t),n.closePath();n.stroke()}function J1(n,e=[]){if(!(e===void 0||e.length===0)){n.beginPath(),n.moveTo(e[0][0],e[0][1]);for(let t of e)n.lineTo(t[0],parseInt(t[1]));n.stroke(),d.fillPolygons&&(n.closePath(),n.fill())}}function Ie(n,e=[]){if(!(e===void 0||e.length===0)){if(!d.useCurves||e.length<=2){J1(n,e);return}n.moveTo(e[0][0],e[0][1]);for(let t=0;t1&&_[1].length>0){let h=c[1]>0?`#${c[1]}`:"",o=`${c[0]} ${h}: ${_[1]}`;d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(o,8,2+A*d.lineHeight)),t.fillStyle=d.labelColor,t.fillText(o,6,0+A*d.lineHeight),A+=1}}}async function wt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t)for(let A of e){t.font=d.font,t.strokeStyle=d.color,t.fillStyle=d.color,d.drawBoxes&&yt(t,A.box[0],A.box[1],A.box[2],A.box[3]);let r=[];if(r.push(`face confidence: ${Math.trunc(100*A.confidence)}%`),A.genderConfidence&&r.push(`${A.gender||""} ${Math.trunc(100*A.genderConfidence)}% confident`),A.age&&r.push(`age: ${A.age||""}`),A.iris&&r.push(`iris distance: ${A.iris}`),A.emotion&&A.emotion.length>0){let c=A.emotion.map(_=>`${Math.trunc(100*_.score)}% ${_.emotion}`);r.push(c.join(" "))}A.angle&&A.angle.roll&&r.push(`roll: ${Math.trunc(100*A.angle.roll)/100} yaw:${Math.trunc(100*A.angle.yaw)/100} pitch:${Math.trunc(100*A.angle.pitch)/100}`),r.length===0&&r.push("face"),t.fillStyle=d.color;for(let c=r.length-1;c>=0;c--){let _=Math.max(A.box[0],0),h=c*d.lineHeight+A.box[1];d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(r[c],_+5,h+16)),t.fillStyle=d.labelColor,t.fillText(r[c],_+4,h+15)}if(t.lineWidth=1,A.mesh){if(d.drawPoints)for(let c of A.mesh)t.fillStyle=d.useDepth?`rgba(${127.5+2*c[2]}, ${127.5-2*c[2]}, 255, 0.5)`:d.color,Oe(t,c[0],c[1]);if(d.drawPolygons){for(let c=0;cA.mesh[h]);t.strokeStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.fillStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.lineWidth=1,J1(t,_)}if(A.annotations&&A.annotations.leftEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.leftEyeIris[3][0]-A.annotations.leftEyeIris[1][0])/2,_=Math.abs(A.annotations.leftEyeIris[4][1]-A.annotations.leftEyeIris[2][1])/2;t.ellipse(A.annotations.leftEyeIris[0][0],A.annotations.leftEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}if(A.annotations&&A.annotations.rightEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.rightEyeIris[3][0]-A.annotations.rightEyeIris[1][0])/2,_=Math.abs(A.annotations.rightEyeIris[4][1]-A.annotations.rightEyeIris[2][1])/2;t.ellipse(A.annotations.rightEyeIris[0][0],A.annotations.rightEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}}}}}var ne=[];async function dt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round";for(let A=0;A_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),c.length===5&&J1(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c)}}}}async function lt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round",t.font=d.font;for(let A of e){if(d.drawBoxes&&(t.strokeStyle=d.color,t.fillStyle=d.color,yt(t,A.box[0],A.box[1],A.box[2],A.box[3]),d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText("hand",A.box[0]+3,1+A.box[1]+d.lineHeight,A.box[2])),t.fillStyle=d.labelColor,t.fillText("hand",A.box[0]+2,0+A.box[1]+d.lineHeight,A.box[2]),t.stroke()),d.drawPoints&&A.landmarks&&A.landmarks.length>0)for(let r of A.landmarks)t.fillStyle=d.useDepth?`rgba(${127.5+2*r[2]}, ${127.5-2*r[2]}, 255, 0.5)`:d.color,Oe(t,r[0],r[1]);if(d.drawPolygons){let r=c=>{if(!!c)for(let _=0;_0?_-1:0][0],c[_>0?_-1:0][1]),t.lineTo(c[_][0],c[_][1]),t.stroke()};r(A.annotations.indexFinger),r(A.annotations.middleFinger),r(A.annotations.ringFinger),r(A.annotations.pinky),r(A.annotations.thumb)}}}}async function Nn(n,e){if(!n||!e||!(n instanceof HTMLCanvasElement)||!(e instanceof HTMLCanvasElement))return;let t=n.getContext("2d");t==null||t.drawImage(n,0,0)}async function jn(n,e){!e||!n||n instanceof HTMLCanvasElement&&(wt(n,e.face),dt(n,e.body),lt(n,e.hand),at(n,e.gesture))}var P=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function we(...n){let e=t=>t&&typeof t=="object";return n.reduce((t,A)=>(Object.keys(A||{}).forEach(r=>{let c=t[r],_=A[r];Array.isArray(c)&&Array.isArray(_)?t[r]=c.concat(..._):e(c)&&e(_)?t[r]=we(c,_):t[r]=_}),t),{})}var mt=class{constructor(e={}){this.calculateFaceAngle=e=>{if(!e||e.length<300)return{};let t=(c,_,h,o)=>Math.atan2(o-_,h-c),A=c=>Math.abs(c*180/Math.PI%360);return{roll:t(e[33][0],e[33][1],e[263][0],e[263][1]),yaw:t(e[33][0],e[33][2],e[263][0],e[263][2]),pitch:t(e[10][1],e[10][2],e[152][1],e[152][2])}};this.tf=ft,this.draw=Y1,this.package=F1,this.version=q1,this.config=we(v,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>X1(t,this.config),this.facemesh=pt,this.age=$e,this.gender=n1,this.emotion=o1,this.body=this.config.body.modelType.startsWith("posenet")?z1:V1,this.hand=j1,this.sysinfo=D1()}profile(){return this.config.profile?De:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,A=this.numTensors;this.numTensors=t;let r=t-A;r!==0&&m(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?a0(e,t):0}async load(e=null){this.state="load";let t=P();e&&(this.config=we(this.config,e)),this.firstRun&&(this.config.debug&&m(`version: ${this.version}`),this.config.debug&&m(`tfjs version: ${this.tf.version_core}`),this.config.debug&&m("platform:",this.sysinfo.platform),this.config.debug&&m("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&m("configuration:",this.config),this.config.debug&&m("tf flags:",this.tf.ENV.flags)));let A=this.config.face.detector.modelPath.includes("faceboxes")?Ge:pt;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?A.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?e1(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?_1(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?x1(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?a1(this.config):null),this.models.handpose||(this.config.hand.enabled?Z1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?M1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?L1(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await A.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await e1(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await _1(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await x1(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await a1(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await Z1(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await M1(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await L1(this.config))),this.firstRun&&(this.config.debug&&m("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(P()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=P();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&m("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&m("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let A=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&m(`wasm execution: ${A?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),A||m("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&$1();try{await this.tf.setBackend(this.config.backend)}catch(A){m("error: cannot set backend:",this.config.backend,A)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(m("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let A=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&m(`gl version:${A.getParameter(A.VERSION)} renderer:${A.getParameter(A.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(P()-t)}}async detectFace(e){var x,y,i,a,l,f;let t,A,r,c,_,h=[];this.state="run:face",t=P();let o=await((x=this.models.face)==null?void 0:x.estimateFaces(e,this.config));this.perf.face=Math.trunc(P()-t);for(let s of o){if(this.analyze("Get Face"),!s.image||s.image.isDisposedInternal){m("Face object is disposed:",s.image);continue}let k=this.calculateFaceAngle(s.mesh);this.analyze("Start Age:"),this.config.async?A=this.config.face.age.enabled?t1(s.image,this.config):{}:(this.state="run:age",t=P(),A=this.config.face.age.enabled?await t1(s.image,this.config):{},this.perf.age=Math.trunc(P()-t)),this.analyze("Start Gender:"),this.config.async?r=this.config.face.gender.enabled?h1(s.image,this.config):{}:(this.state="run:gender",t=P(),r=this.config.face.gender.enabled?await h1(s.image,this.config):{},this.perf.gender=Math.trunc(P()-t)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?y1(s.image,this.config):{}:(this.state="run:emotion",t=P(),c=this.config.face.emotion.enabled?await y1(s.image,this.config):{},this.perf.emotion=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?_=this.config.face.embedding.enabled?w1(s.image,this.config):[]:(this.state="run:embedding",t=P(),_=this.config.face.embedding.enabled?await w1(s.image,this.config):[],this.perf.embedding=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.config.async&&([A,r,c,_]=await Promise.all([A,r,c,_])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((y=s==null?void 0:s.annotations)==null?void 0:y.leftEyeIris)&&((i=s==null?void 0:s.annotations)==null?void 0:i.rightEyeIris)&&(delete s.annotations.leftEyeIris,delete s.annotations.rightEyeIris);let N=((a=s.annotations)==null?void 0:a.leftEyeIris)&&((l=s.annotations)==null?void 0:l.rightEyeIris)?11.7*Math.max(Math.abs(s.annotations.leftEyeIris[3][0]-s.annotations.leftEyeIris[1][0]),Math.abs(s.annotations.rightEyeIris[4][1]-s.annotations.rightEyeIris[2][1])):0;h.push({confidence:s.confidence,faceConfidence:s.faceConfidence,boxConfidence:s.boxConfidence,box:s.box,mesh:s.mesh,boxRaw:s.boxRaw,meshRaw:s.meshRaw,annotations:s.annotations,age:A.age,gender:r.gender,genderConfidence:r.confidence,emotion:c,embedding:_,iris:N!==0?Math.trunc(N)/100:0,angle:k}),(f=s.image)==null||f.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),h}async detect(e,t={}){return new Promise(async A=>{var a,l,f,s;this.state="config";let r;this.config=we(this.config,t),this.state="check";let c=this.sanity(e);c&&(m(c,e),A({error:c}));let _=P();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),r=P();let h=X1(e,this.config);if(!h||!h.tensor){m("could not convert input to tensor"),A({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(P()-r),this.analyze("Get Image:");let o,x,y;this.config.async?(y=this.config.face.enabled?this.detectFace(h.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",r=P(),y=this.config.face.enabled?await this.detectFace(h.tensor):[],this.perf.face=Math.trunc(P()-r)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?(a=this.models.posenet)==null?void 0:a.estimatePoses(h.tensor,this.config):[]:o=this.config.body.enabled?H1(h.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",r=P(),this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?await((l=this.models.posenet)==null?void 0:l.estimatePoses(h.tensor,this.config)):[]:o=this.config.body.enabled?await H1(h.tensor,this.config):[],this.perf.body=Math.trunc(P()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(x=this.config.hand.enabled?(f=this.models.handpose)==null?void 0:f.estimateHands(h.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",r=P(),x=this.config.hand.enabled?await((s=this.models.handpose)==null?void 0:s.estimateHands(h.tensor,this.config)):[],this.perf.hand=Math.trunc(P()-r)),this.analyze("End Hand:"),this.config.async&&([y,o,x]=await Promise.all([y,o,x])),h.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let i=[];this.config.gesture.enabled&&(r=P(),i=[...J0(y),...Y0(o),...C0(x),...B0(y)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(P()-r)),this.perf.total=Math.trunc(P()-_),this.state="idle",A({face:y,body:o,hand:x,gesture:i,performance:this.perf,canvas:h.canvas})})}async warmupBitmap(){let e=(r,c="application/octet-stream")=>fetch(`data:${c};base64,${r}`).then(_=>_.blob()),t,A;switch(this.config.warmup){case"face":t=await e(Ne);break;case"full":t=await e(je);break;default:t=null}if(t){let r=await createImageBitmap(t);A=await this.detect(r,this.config),r.close()}return A}async warmupCanvas(){return new Promise(e=>{let t,A=0;switch(this.config.warmup){case"face":A=256,t="data:image/jpeg;base64,"+Ne;break;case"full":case"body":A=1200,t="data:image/jpeg;base64,"+je;break;default:t=null}let r=new Image;r.onload=async()=>{let c=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(A,A):document.createElement("canvas");c.width=r.naturalWidth,c.height=r.naturalHeight;let _=c.getContext("2d");_==null||_.drawImage(r,0,0);let h=await this.detect(c,this.config);e(h)},t?r.src=t:e(null)})}async warmupNode(){let e=_=>Buffer.from(_,"base64"),t=this.config.warmup==="face"?e(Ne):e(je),A=ft.node.decodeJpeg(t),r=A.expandDims(0);this.tf.dispose(A);let c=await this.detect(r,this.config);return this.tf.dispose(r),c}async warmup(e){let t=P();e&&(this.config=we(this.config,e));let A=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=A;let c=P();return this.config.debug&&m("Warmup",this.config.warmup,Math.round(c-t),"ms",r),r}}; //# sourceMappingURL=human.node-gpu.js.map diff --git a/dist/human.node.js b/dist/human.node.js index 19d92c9b..0f95a7f9 100644 --- a/dist/human.node.js +++ b/dist/human.node.js @@ -731,5 +731,5 @@ AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ -2Q==`;var F1={};q(F1,{author:()=>nt,browser:()=>et,bugs:()=>rt,default:()=>Wn,description:()=>D0,devDependencies:()=>st,engines:()=>_t,homepage:()=>At,keywords:()=>xt,license:()=>ct,main:()=>Q0,module:()=>$0,name:()=>U0,peerDependencies:()=>ot,repository:()=>ht,scripts:()=>it,sideEffects:()=>G0,types:()=>tt,version:()=>q1});var U0="@vladmandic/human",q1="1.0.0",D0="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",G0=!1,Q0="dist/human.node.js",$0="dist/human.esm.js",et="dist/human.esm.js",tt="types/human.d.ts",nt="Vladimir Mandic ",rt={url:"https://github.com/vladmandic/human/issues"},At="https://vladmandic.github.io/human/demo/index.html",ct="MIT",_t={node:">=12.0.0"},ht={type:"git",url:"git+https://github.com/vladmandic/human.git"},ot={},st={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},it={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},xt=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Wn={name:U0,version:q1,description:D0,sideEffects:G0,main:Q0,module:$0,browser:et,types:tt,author:nt,bugs:rt,homepage:At,license:ct,engines:_t,repository:ht,peerDependencies:ot,devDependencies:st,scripts:it,keywords:xt};var Y1={};q(Y1,{all:()=>jn,body:()=>dt,canvas:()=>Nn,face:()=>wt,gesture:()=>at,hand:()=>lt,options:()=>d});var d={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function Oe(n,e,t){n.fillStyle=d.color,n.beginPath(),n.arc(e,t,d.pointSize,0,2*Math.PI),n.fill()}function yt(n,e,t,A,r){if(n.beginPath(),d.useCurves){let c=(e+e+A)/2,_=(t+t+r)/2;n.ellipse(c,_,A/2,r/2,0,0,2*Math.PI)}else n.lineWidth=d.lineWidth,n.moveTo(e+d.roundRect,t),n.lineTo(e+A-d.roundRect,t),n.quadraticCurveTo(e+A,t,e+A,t+d.roundRect),n.lineTo(e+A,t+r-d.roundRect),n.quadraticCurveTo(e+A,t+r,e+A-d.roundRect,t+r),n.lineTo(e+d.roundRect,t+r),n.quadraticCurveTo(e,t+r,e,t+r-d.roundRect),n.lineTo(e,t+d.roundRect),n.quadraticCurveTo(e,t,e+d.roundRect,t),n.closePath();n.stroke()}function J1(n,e=[]){if(!(e===void 0||e.length===0)){n.beginPath(),n.moveTo(e[0][0],e[0][1]);for(let t of e)n.lineTo(t[0],parseInt(t[1]));n.stroke(),d.fillPolygons&&(n.closePath(),n.fill())}}function Ie(n,e=[]){if(!(e===void 0||e.length===0)){if(!d.useCurves||e.length<=2){J1(n,e);return}n.moveTo(e[0][0],e[0][1]);for(let t=0;t1&&_[1].length>0){let h=c[1]>0?`#${c[1]}`:"",o=`${c[0]} ${h}: ${_[1]}`;d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(o,8,2+A*d.lineHeight)),t.fillStyle=d.labelColor,t.fillText(o,6,0+A*d.lineHeight),A+=1}}}async function wt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t)for(let A of e){t.font=d.font,t.strokeStyle=d.color,t.fillStyle=d.color,d.drawBoxes&&yt(t,A.box[0],A.box[1],A.box[2],A.box[3]);let r=[];if(r.push(`face confidence: ${Math.trunc(100*A.confidence)}%`),A.genderConfidence&&r.push(`${A.gender||""} ${Math.trunc(100*A.genderConfidence)}% confident`),A.age&&r.push(`age: ${A.age||""}`),A.iris&&r.push(`iris distance: ${A.iris}`),A.emotion&&A.emotion.length>0){let c=A.emotion.map(_=>`${Math.trunc(100*_.score)}% ${_.emotion}`);r.push(c.join(" "))}A.angle&&A.angle.roll&&r.push(`roll: ${Math.trunc(100*A.angle.roll)/100} yaw:${Math.trunc(100*A.angle.yaw)/100} pitch:${Math.trunc(100*A.angle.pitch)/100}`),r.length===0&&r.push("face"),t.fillStyle=d.color;for(let c=r.length-1;c>=0;c--){let _=Math.max(A.box[0],0),h=c*d.lineHeight+A.box[1];d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(r[c],_+5,h+16)),t.fillStyle=d.labelColor,t.fillText(r[c],_+4,h+15)}if(t.lineWidth=1,A.mesh){if(d.drawPoints)for(let c of A.mesh)t.fillStyle=d.useDepth?`rgba(${127.5+2*c[2]}, ${127.5-2*c[2]}, 255, 0.5)`:d.color,Oe(t,c[0],c[1]);if(d.drawPolygons){for(let c=0;cA.mesh[h]);t.strokeStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.fillStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.lineWidth=1,J1(t,_)}if(A.annotations&&A.annotations.leftEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.leftEyeIris[3][0]-A.annotations.leftEyeIris[1][0])/2,_=Math.abs(A.annotations.leftEyeIris[4][1]-A.annotations.leftEyeIris[2][1])/2;t.ellipse(A.annotations.leftEyeIris[0][0],A.annotations.leftEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}if(A.annotations&&A.annotations.rightEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.rightEyeIris[3][0]-A.annotations.rightEyeIris[1][0])/2,_=Math.abs(A.annotations.rightEyeIris[4][1]-A.annotations.rightEyeIris[2][1])/2;t.ellipse(A.annotations.rightEyeIris[0][0],A.annotations.rightEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}}}}}var ne=[];async function dt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round";for(let A=0;A_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),c.length===5&&J1(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c)}}}}async function lt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round",t.font=d.font;for(let A of e){if(d.drawBoxes&&(t.strokeStyle=d.color,t.fillStyle=d.color,yt(t,A.box[0],A.box[1],A.box[2],A.box[3]),d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText("hand",A.box[0]+3,1+A.box[1]+d.lineHeight,A.box[2])),t.fillStyle=d.labelColor,t.fillText("hand",A.box[0]+2,0+A.box[1]+d.lineHeight,A.box[2]),t.stroke()),d.drawPoints&&A.landmarks&&A.landmarks.length>0)for(let r of A.landmarks)t.fillStyle=d.useDepth?`rgba(${127.5+2*r[2]}, ${127.5-2*r[2]}, 255, 0.5)`:d.color,Oe(t,r[0],r[1]);if(d.drawPolygons){let r=c=>{if(!!c)for(let _=0;_0?_-1:0][0],c[_>0?_-1:0][1]),t.lineTo(c[_][0],c[_][1]),t.stroke()};r(A.annotations.indexFinger),r(A.annotations.middleFinger),r(A.annotations.ringFinger),r(A.annotations.pinky),r(A.annotations.thumb)}}}}async function Nn(n,e){if(!n||!e||!(n instanceof HTMLCanvasElement)||!(e instanceof HTMLCanvasElement))return;let t=n.getContext("2d");t==null||t.drawImage(n,0,0)}async function jn(n,e){!e||!n||n instanceof HTMLCanvasElement&&(wt(n,e.face),dt(n,e.body),lt(n,e.hand),at(n,e.gesture))}var P=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function we(...n){let e=t=>t&&typeof t=="object";return n.reduce((t,A)=>(Object.keys(A||{}).forEach(r=>{let c=t[r],_=A[r];Array.isArray(c)&&Array.isArray(_)?t[r]=c.concat(..._):e(c)&&e(_)?t[r]=we(c,_):t[r]=_}),t),{})}var mt=class{constructor(e={}){this.calculateFaceAngle=e=>{if(!e||e.length<300)return{};let t=(c,_,h,o)=>Math.atan2(o-_,h-c),A=c=>Math.abs(c*180/Math.PI%360);return{roll:t(e[33][0],e[33][1],e[263][0],e[263][1]),yaw:t(e[33][0],e[33][2],e[263][0],e[263][2]),pitch:t(e[10][1],e[10][2],e[152][1],e[152][2])}};this.tf=ft,this.draw=Y1,this.package=F1,this.version=q1,this.config=we(v,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>X1(t,this.config),this.facemesh=pt,this.age=$e,this.gender=n1,this.emotion=o1,this.body=this.config.body.modelType.startsWith("posenet")?z1:V1,this.hand=j1,this.sysinfo=D1()}profile(){return this.config.profile?De:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,A=this.numTensors;this.numTensors=t;let r=t-A;r!==0&&m(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?a0(e,t):0}async load(e=null){this.state="load";let t=P();e&&(this.config=we(this.config,e)),this.firstRun&&(this.config.debug&&m(`version: ${this.version}`),this.config.debug&&m(`tfjs version: ${this.tf.version_core}`),this.config.debug&&m("platform:",this.sysinfo.platform),this.config.debug&&m("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&m("configuration:",this.config),this.config.debug&&m("tf flags:",this.tf.ENV.flags)));let A=this.config.face.detector.modelPath.includes("faceboxes")?Ge:pt;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?A.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?e1(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?_1(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?x1(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?a1(this.config):null),this.models.handpose||(this.config.hand.enabled?Z1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?M1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?L1(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await A.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await e1(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await _1(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await x1(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await a1(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await Z1(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await M1(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await L1(this.config))),this.firstRun&&(this.config.debug&&m("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(P()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=P();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&m("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&m("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let A=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&m(`wasm execution: ${A?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),A||m("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&$1();try{await this.tf.setBackend(this.config.backend)}catch(A){m("error: cannot set backend:",this.config.backend,A)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(m("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let A=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&m(`gl version:${A.getParameter(A.VERSION)} renderer:${A.getParameter(A.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(P()-t)}}async detectFace(e){var x,y,i,a,l,f;let t,A,r,c,_,h=[];this.state="run:face",t=P();let o=await((x=this.models.face)==null?void 0:x.estimateFaces(e,this.config));this.perf.face=Math.trunc(P()-t);for(let s of o){if(this.analyze("Get Face"),!s.image||s.image.isDisposedInternal){m("Face object is disposed:",s.image);continue}let k=this.calculateFaceAngle(s.mesh);this.analyze("Start Age:"),this.config.async?A=this.config.face.age.enabled?t1(s.image,this.config):{}:(this.state="run:age",t=P(),A=this.config.face.age.enabled?await t1(s.image,this.config):{},this.perf.age=Math.trunc(P()-t)),this.analyze("Start Gender:"),this.config.async?r=this.config.face.gender.enabled?h1(s.image,this.config):{}:(this.state="run:gender",t=P(),r=this.config.face.gender.enabled?await h1(s.image,this.config):{},this.perf.gender=Math.trunc(P()-t)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?y1(s.image,this.config):{}:(this.state="run:emotion",t=P(),c=this.config.face.emotion.enabled?await y1(s.image,this.config):{},this.perf.emotion=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?_=this.config.face.embedding.enabled?w1(s.image,this.config):[]:(this.state="run:embedding",t=P(),_=this.config.face.embedding.enabled?await w1(s.image,this.config):[],this.perf.embedding=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.config.async&&([A,r,c,_]=await Promise.all([A,r,c,_])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((y=s==null?void 0:s.annotations)==null?void 0:y.leftEyeIris)&&((i=s==null?void 0:s.annotations)==null?void 0:i.rightEyeIris)&&(delete s.annotations.leftEyeIris,delete s.annotations.rightEyeIris);let N=((a=s.annotations)==null?void 0:a.leftEyeIris)&&((l=s.annotations)==null?void 0:l.rightEyeIris)?11.7*Math.max(Math.abs(s.annotations.leftEyeIris[3][0]-s.annotations.leftEyeIris[1][0]),Math.abs(s.annotations.rightEyeIris[4][1]-s.annotations.rightEyeIris[2][1])):0;h.push({confidence:s.confidence,faceConfidence:s.faceConfidence,boxConfidence:s.boxConfidence,box:s.box,mesh:s.mesh,boxRaw:s.boxRaw,meshRaw:s.meshRaw,annotations:s.annotations,age:A.age,gender:r.gender,genderConfidence:r.confidence,emotion:c,embedding:_,iris:N!==0?Math.trunc(N)/100:0,angle:k}),(f=s.image)==null||f.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),h}async detect(e,t={}){return new Promise(async A=>{var a,l,f,s;this.state="config";let r;this.config=we(this.config,t),this.state="check";let c=this.sanity(e);c&&(m(c,e),A({error:c}));let _=P();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),r=P();let h=X1(e,this.config);if(!h||!h.tensor){m("could not convert input to tensor"),A({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(P()-r),this.analyze("Get Image:");let o,x,y;this.config.async?(y=this.config.face.enabled?this.detectFace(h.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",r=P(),y=this.config.face.enabled?await this.detectFace(h.tensor):[],this.perf.face=Math.trunc(P()-r)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?(a=this.models.posenet)==null?void 0:a.estimatePoses(h.tensor,this.config):[]:o=this.config.body.enabled?H1(h.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",r=P(),this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?await((l=this.models.posenet)==null?void 0:l.estimatePoses(h.tensor,this.config)):[]:o=this.config.body.enabled?await H1(h.tensor,this.config):[],this.perf.body=Math.trunc(P()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(x=this.config.hand.enabled?(f=this.models.handpose)==null?void 0:f.estimateHands(h.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",r=P(),x=this.config.hand.enabled?await((s=this.models.handpose)==null?void 0:s.estimateHands(h.tensor,this.config)):[],this.perf.hand=Math.trunc(P()-r)),this.analyze("End Hand:"),this.config.async&&([y,o,x]=await Promise.all([y,o,x])),h.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let i=[];this.config.gesture.enabled&&(r=P(),i=[...J0(y),...Y0(o),...C0(x),...B0(y)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(P()-r)),this.perf.total=Math.trunc(P()-_),this.state="idle",A({face:y,body:o,hand:x,gesture:i,performance:this.perf,canvas:h.canvas})})}async warmupBitmap(){let e=(r,c="application/octet-stream")=>fetch(`data:${c};base64,${r}`).then(_=>_.blob()),t,A;switch(this.config.warmup){case"face":t=await e(Ne);break;case"full":t=await e(je);break;default:t=null}if(t){let r=await createImageBitmap(t);A=await this.detect(r,this.config),r.close()}return A}async warmupCanvas(){return new Promise(e=>{let t,A=0;switch(this.config.warmup){case"face":A=256,t="data:image/jpeg;base64,"+Ne;break;case"full":case"body":A=1200,t="data:image/jpeg;base64,"+je;break;default:t=null}let r=new Image;r.onload=async()=>{let c=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(A,A):document.createElement("canvas");c.width=r.naturalWidth,c.height=r.naturalHeight;let _=c.getContext("2d");_==null||_.drawImage(r,0,0);let h=await this.detect(c,this.config);e(h)},t?r.src=t:e(null)})}async warmupNode(){let e=_=>Buffer.from(_,"base64"),t=this.config.warmup==="face"?e(Ne):e(je),A=ft.node.decodeJpeg(t),r=A.expandDims(0);this.tf.dispose(A);let c=await this.detect(r,this.config);return this.tf.dispose(r),c}async warmup(e){let t=P();e&&(this.config=we(this.config,e));let A=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=A;let c=P();return this.config.debug&&m("Warmup",this.config.warmup,Math.round(c-t),"ms",r),r}}; +2Q==`;var F1={};q(F1,{author:()=>nt,browser:()=>et,bugs:()=>rt,default:()=>Wn,description:()=>D0,devDependencies:()=>st,engines:()=>_t,homepage:()=>At,keywords:()=>xt,license:()=>ct,main:()=>Q0,module:()=>$0,name:()=>U0,peerDependencies:()=>ot,repository:()=>ht,scripts:()=>it,sideEffects:()=>G0,types:()=>tt,version:()=>q1});var U0="@vladmandic/human",q1="1.0.1",D0="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",G0=!1,Q0="dist/human.node.js",$0="dist/human.esm.js",et="dist/human.esm.js",tt="types/human.d.ts",nt="Vladimir Mandic ",rt={url:"https://github.com/vladmandic/human/issues"},At="https://vladmandic.github.io/human/demo/index.html",ct="MIT",_t={node:">=12.0.0"},ht={type:"git",url:"git+https://github.com/vladmandic/human.git"},ot={},st={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},it={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},xt=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Wn={name:U0,version:q1,description:D0,sideEffects:G0,main:Q0,module:$0,browser:et,types:tt,author:nt,bugs:rt,homepage:At,license:ct,engines:_t,repository:ht,peerDependencies:ot,devDependencies:st,scripts:it,keywords:xt};var Y1={};q(Y1,{all:()=>jn,body:()=>dt,canvas:()=>Nn,face:()=>wt,gesture:()=>at,hand:()=>lt,options:()=>d});var d={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function Oe(n,e,t){n.fillStyle=d.color,n.beginPath(),n.arc(e,t,d.pointSize,0,2*Math.PI),n.fill()}function yt(n,e,t,A,r){if(n.beginPath(),d.useCurves){let c=(e+e+A)/2,_=(t+t+r)/2;n.ellipse(c,_,A/2,r/2,0,0,2*Math.PI)}else n.lineWidth=d.lineWidth,n.moveTo(e+d.roundRect,t),n.lineTo(e+A-d.roundRect,t),n.quadraticCurveTo(e+A,t,e+A,t+d.roundRect),n.lineTo(e+A,t+r-d.roundRect),n.quadraticCurveTo(e+A,t+r,e+A-d.roundRect,t+r),n.lineTo(e+d.roundRect,t+r),n.quadraticCurveTo(e,t+r,e,t+r-d.roundRect),n.lineTo(e,t+d.roundRect),n.quadraticCurveTo(e,t,e+d.roundRect,t),n.closePath();n.stroke()}function J1(n,e=[]){if(!(e===void 0||e.length===0)){n.beginPath(),n.moveTo(e[0][0],e[0][1]);for(let t of e)n.lineTo(t[0],parseInt(t[1]));n.stroke(),d.fillPolygons&&(n.closePath(),n.fill())}}function Ie(n,e=[]){if(!(e===void 0||e.length===0)){if(!d.useCurves||e.length<=2){J1(n,e);return}n.moveTo(e[0][0],e[0][1]);for(let t=0;t1&&_[1].length>0){let h=c[1]>0?`#${c[1]}`:"",o=`${c[0]} ${h}: ${_[1]}`;d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(o,8,2+A*d.lineHeight)),t.fillStyle=d.labelColor,t.fillText(o,6,0+A*d.lineHeight),A+=1}}}async function wt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t)for(let A of e){t.font=d.font,t.strokeStyle=d.color,t.fillStyle=d.color,d.drawBoxes&&yt(t,A.box[0],A.box[1],A.box[2],A.box[3]);let r=[];if(r.push(`face confidence: ${Math.trunc(100*A.confidence)}%`),A.genderConfidence&&r.push(`${A.gender||""} ${Math.trunc(100*A.genderConfidence)}% confident`),A.age&&r.push(`age: ${A.age||""}`),A.iris&&r.push(`iris distance: ${A.iris}`),A.emotion&&A.emotion.length>0){let c=A.emotion.map(_=>`${Math.trunc(100*_.score)}% ${_.emotion}`);r.push(c.join(" "))}A.angle&&A.angle.roll&&r.push(`roll: ${Math.trunc(100*A.angle.roll)/100} yaw:${Math.trunc(100*A.angle.yaw)/100} pitch:${Math.trunc(100*A.angle.pitch)/100}`),r.length===0&&r.push("face"),t.fillStyle=d.color;for(let c=r.length-1;c>=0;c--){let _=Math.max(A.box[0],0),h=c*d.lineHeight+A.box[1];d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText(r[c],_+5,h+16)),t.fillStyle=d.labelColor,t.fillText(r[c],_+4,h+15)}if(t.lineWidth=1,A.mesh){if(d.drawPoints)for(let c of A.mesh)t.fillStyle=d.useDepth?`rgba(${127.5+2*c[2]}, ${127.5-2*c[2]}, 255, 0.5)`:d.color,Oe(t,c[0],c[1]);if(d.drawPolygons){for(let c=0;cA.mesh[h]);t.strokeStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.fillStyle=d.useDepth?`rgba(${127.5+2*_[0][2]}, ${127.5-2*_[0][2]}, 255, 0.3)`:d.color,t.lineWidth=1,J1(t,_)}if(A.annotations&&A.annotations.leftEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.leftEyeIris[3][0]-A.annotations.leftEyeIris[1][0])/2,_=Math.abs(A.annotations.leftEyeIris[4][1]-A.annotations.leftEyeIris[2][1])/2;t.ellipse(A.annotations.leftEyeIris[0][0],A.annotations.leftEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}if(A.annotations&&A.annotations.rightEyeIris){t.strokeStyle=d.useDepth?"rgba(255, 200, 255, 0.3)":d.color,t.beginPath();let c=Math.abs(A.annotations.rightEyeIris[3][0]-A.annotations.rightEyeIris[1][0])/2,_=Math.abs(A.annotations.rightEyeIris[4][1]-A.annotations.rightEyeIris[2][1])/2;t.ellipse(A.annotations.rightEyeIris[0][0],A.annotations.rightEyeIris[0][1],c,_,0,0,2*Math.PI),t.stroke(),d.fillPolygons&&(t.fillStyle=d.useDepth?"rgba(255, 255, 200, 0.3)":d.color,t.fill())}}}}}var ne=[];async function dt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round";for(let A=0;A_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),c.length===5&&J1(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightHip"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightKnee"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightAnkle"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightHeel"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightFoot"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="leftShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="leftPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c),c.length=0,r=e[A].keypoints.find(_=>_.part==="rightShoulder"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightElbow"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightWrist"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),r=e[A].keypoints.find(_=>_.part==="rightPalm"),r&&r.score>v.body.scoreThreshold&&c.push([r.position.x,r.position.y]),Ie(t,c)}}}}async function lt(n,e){if(!e||!n||!(n instanceof HTMLCanvasElement))return;let t=n.getContext("2d");if(!!t){t.lineJoin="round",t.font=d.font;for(let A of e){if(d.drawBoxes&&(t.strokeStyle=d.color,t.fillStyle=d.color,yt(t,A.box[0],A.box[1],A.box[2],A.box[3]),d.shadowColor&&d.shadowColor!==""&&(t.fillStyle=d.shadowColor,t.fillText("hand",A.box[0]+3,1+A.box[1]+d.lineHeight,A.box[2])),t.fillStyle=d.labelColor,t.fillText("hand",A.box[0]+2,0+A.box[1]+d.lineHeight,A.box[2]),t.stroke()),d.drawPoints&&A.landmarks&&A.landmarks.length>0)for(let r of A.landmarks)t.fillStyle=d.useDepth?`rgba(${127.5+2*r[2]}, ${127.5-2*r[2]}, 255, 0.5)`:d.color,Oe(t,r[0],r[1]);if(d.drawPolygons){let r=c=>{if(!!c)for(let _=0;_0?_-1:0][0],c[_>0?_-1:0][1]),t.lineTo(c[_][0],c[_][1]),t.stroke()};r(A.annotations.indexFinger),r(A.annotations.middleFinger),r(A.annotations.ringFinger),r(A.annotations.pinky),r(A.annotations.thumb)}}}}async function Nn(n,e){if(!n||!e||!(n instanceof HTMLCanvasElement)||!(e instanceof HTMLCanvasElement))return;let t=n.getContext("2d");t==null||t.drawImage(n,0,0)}async function jn(n,e){!e||!n||n instanceof HTMLCanvasElement&&(wt(n,e.face),dt(n,e.body),lt(n,e.hand),at(n,e.gesture))}var P=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function we(...n){let e=t=>t&&typeof t=="object";return n.reduce((t,A)=>(Object.keys(A||{}).forEach(r=>{let c=t[r],_=A[r];Array.isArray(c)&&Array.isArray(_)?t[r]=c.concat(..._):e(c)&&e(_)?t[r]=we(c,_):t[r]=_}),t),{})}var mt=class{constructor(e={}){this.calculateFaceAngle=e=>{if(!e||e.length<300)return{};let t=(c,_,h,o)=>Math.atan2(o-_,h-c),A=c=>Math.abs(c*180/Math.PI%360);return{roll:t(e[33][0],e[33][1],e[263][0],e[263][1]),yaw:t(e[33][0],e[33][2],e[263][0],e[263][2]),pitch:t(e[10][1],e[10][2],e[152][1],e[152][2])}};this.tf=ft,this.draw=Y1,this.package=F1,this.version=q1,this.config=we(v,e),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=t=>X1(t,this.config),this.facemesh=pt,this.age=$e,this.gender=n1,this.emotion=o1,this.body=this.config.body.modelType.startsWith("posenet")?z1:V1,this.hand=j1,this.sysinfo=D1()}profile(){return this.config.profile?De:{}}analyze(...e){if(!this.analyzeMemoryLeaks)return;let t=this.tf.engine().state.numTensors,A=this.numTensors;this.numTensors=t;let r=t-A;r!==0&&m(...e,r)}sanity(e){if(!this.checkSanity)return null;if(!e)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(e instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(t){return"backend not loaded"}return null}simmilarity(e,t){return this.config.face.embedding.enabled?a0(e,t):0}async load(e=null){this.state="load";let t=P();e&&(this.config=we(this.config,e)),this.firstRun&&(this.config.debug&&m(`version: ${this.version}`),this.config.debug&&m(`tfjs version: ${this.tf.version_core}`),this.config.debug&&m("platform:",this.sysinfo.platform),this.config.debug&&m("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&m("configuration:",this.config),this.config.debug&&m("tf flags:",this.tf.ENV.flags)));let A=this.config.face.detector.modelPath.includes("faceboxes")?Ge:pt;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?A.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?e1(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?_1(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?x1(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?a1(this.config):null),this.models.handpose||(this.config.hand.enabled?Z1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?M1(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?L1(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await A.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await e1(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await _1(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await x1(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await a1(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await Z1(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await M1(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await L1(this.config))),this.firstRun&&(this.config.debug&&m("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let r=Math.trunc(P()-t);r>(this.perf.load||0)&&(this.perf.load=r)}async checkBackend(e=!1){if(this.config.backend&&this.config.backend!==""&&e||this.tf.getBackend()!==this.config.backend){let t=P();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&m("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&m("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let A=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),r=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&m(`wasm execution: ${A?"SIMD":"no SIMD"} ${r?"multithreaded":"singlethreaded"}`),A||m("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&$1();try{await this.tf.setBackend(this.config.backend)}catch(A){m("error: cannot set backend:",this.config.backend,A)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(m("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let A=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&m(`gl version:${A.getParameter(A.VERSION)} renderer:${A.getParameter(A.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(P()-t)}}async detectFace(e){var x,y,i,a,l,f;let t,A,r,c,_,h=[];this.state="run:face",t=P();let o=await((x=this.models.face)==null?void 0:x.estimateFaces(e,this.config));this.perf.face=Math.trunc(P()-t);for(let s of o){if(this.analyze("Get Face"),!s.image||s.image.isDisposedInternal){m("Face object is disposed:",s.image);continue}let k=this.calculateFaceAngle(s.mesh);this.analyze("Start Age:"),this.config.async?A=this.config.face.age.enabled?t1(s.image,this.config):{}:(this.state="run:age",t=P(),A=this.config.face.age.enabled?await t1(s.image,this.config):{},this.perf.age=Math.trunc(P()-t)),this.analyze("Start Gender:"),this.config.async?r=this.config.face.gender.enabled?h1(s.image,this.config):{}:(this.state="run:gender",t=P(),r=this.config.face.gender.enabled?await h1(s.image,this.config):{},this.perf.gender=Math.trunc(P()-t)),this.analyze("Start Emotion:"),this.config.async?c=this.config.face.emotion.enabled?y1(s.image,this.config):{}:(this.state="run:emotion",t=P(),c=this.config.face.emotion.enabled?await y1(s.image,this.config):{},this.perf.emotion=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?_=this.config.face.embedding.enabled?w1(s.image,this.config):[]:(this.state="run:embedding",t=P(),_=this.config.face.embedding.enabled?await w1(s.image,this.config):[],this.perf.embedding=Math.trunc(P()-t)),this.analyze("End Emotion:"),this.config.async&&([A,r,c,_]=await Promise.all([A,r,c,_])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((y=s==null?void 0:s.annotations)==null?void 0:y.leftEyeIris)&&((i=s==null?void 0:s.annotations)==null?void 0:i.rightEyeIris)&&(delete s.annotations.leftEyeIris,delete s.annotations.rightEyeIris);let N=((a=s.annotations)==null?void 0:a.leftEyeIris)&&((l=s.annotations)==null?void 0:l.rightEyeIris)?11.7*Math.max(Math.abs(s.annotations.leftEyeIris[3][0]-s.annotations.leftEyeIris[1][0]),Math.abs(s.annotations.rightEyeIris[4][1]-s.annotations.rightEyeIris[2][1])):0;h.push({confidence:s.confidence,faceConfidence:s.faceConfidence,boxConfidence:s.boxConfidence,box:s.box,mesh:s.mesh,boxRaw:s.boxRaw,meshRaw:s.meshRaw,annotations:s.annotations,age:A.age,gender:r.gender,genderConfidence:r.confidence,emotion:c,embedding:_,iris:N!==0?Math.trunc(N)/100:0,angle:k}),(f=s.image)==null||f.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),h}async detect(e,t={}){return new Promise(async A=>{var a,l,f,s;this.state="config";let r;this.config=we(this.config,t),this.state="check";let c=this.sanity(e);c&&(m(c,e),A({error:c}));let _=P();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),r=P();let h=X1(e,this.config);if(!h||!h.tensor){m("could not convert input to tensor"),A({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(P()-r),this.analyze("Get Image:");let o,x,y;this.config.async?(y=this.config.face.enabled?this.detectFace(h.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",r=P(),y=this.config.face.enabled?await this.detectFace(h.tensor):[],this.perf.face=Math.trunc(P()-r)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?(a=this.models.posenet)==null?void 0:a.estimatePoses(h.tensor,this.config):[]:o=this.config.body.enabled?H1(h.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",r=P(),this.config.body.modelType.startsWith("posenet")?o=this.config.body.enabled?await((l=this.models.posenet)==null?void 0:l.estimatePoses(h.tensor,this.config)):[]:o=this.config.body.enabled?await H1(h.tensor,this.config):[],this.perf.body=Math.trunc(P()-r)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(x=this.config.hand.enabled?(f=this.models.handpose)==null?void 0:f.estimateHands(h.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",r=P(),x=this.config.hand.enabled?await((s=this.models.handpose)==null?void 0:s.estimateHands(h.tensor,this.config)):[],this.perf.hand=Math.trunc(P()-r)),this.analyze("End Hand:"),this.config.async&&([y,o,x]=await Promise.all([y,o,x])),h.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let i=[];this.config.gesture.enabled&&(r=P(),i=[...J0(y),...Y0(o),...C0(x),...B0(y)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(P()-r)),this.perf.total=Math.trunc(P()-_),this.state="idle",A({face:y,body:o,hand:x,gesture:i,performance:this.perf,canvas:h.canvas})})}async warmupBitmap(){let e=(r,c="application/octet-stream")=>fetch(`data:${c};base64,${r}`).then(_=>_.blob()),t,A;switch(this.config.warmup){case"face":t=await e(Ne);break;case"full":t=await e(je);break;default:t=null}if(t){let r=await createImageBitmap(t);A=await this.detect(r,this.config),r.close()}return A}async warmupCanvas(){return new Promise(e=>{let t,A=0;switch(this.config.warmup){case"face":A=256,t="data:image/jpeg;base64,"+Ne;break;case"full":case"body":A=1200,t="data:image/jpeg;base64,"+je;break;default:t=null}let r=new Image;r.onload=async()=>{let c=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(A,A):document.createElement("canvas");c.width=r.naturalWidth,c.height=r.naturalHeight;let _=c.getContext("2d");_==null||_.drawImage(r,0,0);let h=await this.detect(c,this.config);e(h)},t?r.src=t:e(null)})}async warmupNode(){let e=_=>Buffer.from(_,"base64"),t=this.config.warmup==="face"?e(Ne):e(je),A=ft.node.decodeJpeg(t),r=A.expandDims(0);this.tf.dispose(A);let c=await this.detect(r,this.config);return this.tf.dispose(r),c}async warmup(e){let t=P();e&&(this.config=we(this.config,e));let A=this.config.videoOptimized;this.config.videoOptimized=!1;let r;typeof createImageBitmap=="function"?r=await this.warmupBitmap():typeof Image!="undefined"?r=await this.warmupCanvas():r=await this.warmupNode(),this.config.videoOptimized=A;let c=P();return this.config.debug&&m("Warmup",this.config.warmup,Math.round(c-t),"ms",r),r}}; //# sourceMappingURL=human.node.js.map diff --git a/dist/human.ts b/dist/human.ts index ef507ae3..040051da 100644 --- a/dist/human.ts +++ b/dist/human.ts @@ -4771,7 +4771,7 @@ AAAAAAJAAAAAAAAAAAAAABAJEAAAAAAAAAAAAAAAIEoBKAAAAAAAAAAAAAAABAlAAAAAAAIAAAAA BAkBAkBAkBAlACEgMZjdjbFW8bWrEx8YWANb6Fp+bfwab+vLDKMFK9qxH5L0bAr8OPRPKz2AY7J2 SbAjYZAI2E7AIEgIEgIEgMdkSy2NgY7MdlmyNoBXsxmFuyNgVTVjNV3KjlBRNTlXTVHKCrlIqt5T lBhEMohlFerLlBjEMohMVTEARDKCITsAk2AEgAAAkAAAAAAAAAAAAAAAAAAAAAAAASAAAAAAAAD/ -2Q==`;var q2={};Un(q2,{author:()=>W6,browser:()=>P6,bugs:()=>B6,default:()=>Eae,description:()=>$6,devDependencies:()=>q6,engines:()=>H6,homepage:()=>V6,keywords:()=>K6,license:()=>U6,main:()=>D6,module:()=>z6,name:()=>F6,peerDependencies:()=>G6,repository:()=>j6,scripts:()=>X6,sideEffects:()=>O6,types:()=>L6,version:()=>X2});var F6="@vladmandic/human",X2="1.0.0",$6="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",O6=!1,D6="dist/human.node.js",z6="dist/human.esm.js",P6="dist/human.esm.js",L6="types/human.d.ts",W6="Vladimir Mandic ",B6={url:"https://github.com/vladmandic/human/issues"},V6="https://vladmandic.github.io/human/demo/index.html",U6="MIT",H6={node:">=12.0.0"},j6={type:"git",url:"git+https://github.com/vladmandic/human.git"},G6={},q6={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},X6={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},K6=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Eae={name:F6,version:X2,description:$6,sideEffects:O6,main:D6,module:z6,browser:P6,types:L6,author:W6,bugs:B6,homepage:V6,license:U6,engines:H6,repository:j6,peerDependencies:G6,devDependencies:q6,scripts:X6,keywords:K6};var K2={};Un(K2,{all:()=>Rae,body:()=>Q6,canvas:()=>Cae,face:()=>J6,gesture:()=>Y6,hand:()=>e4,options:()=>ce});var ce={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function u0(e,t,n){e.fillStyle=ce.color,e.beginPath(),e.arc(t,n,ce.pointSize,0,2*Math.PI),e.fill()}function Z6(e,t,n,r,a){if(e.beginPath(),ce.useCurves){let s=(t+t+r)/2,i=(n+n+a)/2;e.ellipse(s,i,r/2,a/2,0,0,2*Math.PI)}else e.lineWidth=ce.lineWidth,e.moveTo(t+ce.roundRect,n),e.lineTo(t+r-ce.roundRect,n),e.quadraticCurveTo(t+r,n,t+r,n+ce.roundRect),e.lineTo(t+r,n+a-ce.roundRect),e.quadraticCurveTo(t+r,n+a,t+r-ce.roundRect,n+a),e.lineTo(t+ce.roundRect,n+a),e.quadraticCurveTo(t,n+a,t,n+a-ce.roundRect),e.lineTo(t,n+ce.roundRect),e.quadraticCurveTo(t,n,t+ce.roundRect,n),e.closePath();e.stroke()}function Z2(e,t=[]){if(!(t===void 0||t.length===0)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.lineTo(n[0],parseInt(n[1]));e.stroke(),ce.fillPolygons&&(e.closePath(),e.fill())}}function c0(e,t=[]){if(!(t===void 0||t.length===0)){if(!ce.useCurves||t.length<=2){Z2(e,t);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;n1&&i[1].length>0){let o=s[1]>0?`#${s[1]}`:"",l=`${s[0]} ${o}: ${i[1]}`;ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(l,8,2+r*ce.lineHeight)),n.fillStyle=ce.labelColor,n.fillText(l,6,0+r*ce.lineHeight),r+=1}}}async function J6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n)for(let r of t){n.font=ce.font,n.strokeStyle=ce.color,n.fillStyle=ce.color,ce.drawBoxes&&Z6(n,r.box[0],r.box[1],r.box[2],r.box[3]);let a=[];if(a.push(`face confidence: ${Math.trunc(100*r.confidence)}%`),r.genderConfidence&&a.push(`${r.gender||""} ${Math.trunc(100*r.genderConfidence)}% confident`),r.age&&a.push(`age: ${r.age||""}`),r.iris&&a.push(`iris distance: ${r.iris}`),r.emotion&&r.emotion.length>0){let s=r.emotion.map(i=>`${Math.trunc(100*i.score)}% ${i.emotion}`);a.push(s.join(" "))}r.angle&&r.angle.roll&&a.push(`roll: ${Math.trunc(100*r.angle.roll)/100} yaw:${Math.trunc(100*r.angle.yaw)/100} pitch:${Math.trunc(100*r.angle.pitch)/100}`),a.length===0&&a.push("face"),n.fillStyle=ce.color;for(let s=a.length-1;s>=0;s--){let i=Math.max(r.box[0],0),o=s*ce.lineHeight+r.box[1];ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(a[s],i+5,o+16)),n.fillStyle=ce.labelColor,n.fillText(a[s],i+4,o+15)}if(n.lineWidth=1,r.mesh){if(ce.drawPoints)for(let s of r.mesh)n.fillStyle=ce.useDepth?`rgba(${127.5+2*s[2]}, ${127.5-2*s[2]}, 255, 0.5)`:ce.color,u0(n,s[0],s[1]);if(ce.drawPolygons){for(let s=0;sr.mesh[o]);n.strokeStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.fillStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.lineWidth=1,Z2(n,i)}if(r.annotations&&r.annotations.leftEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.leftEyeIris[3][0]-r.annotations.leftEyeIris[1][0])/2,i=Math.abs(r.annotations.leftEyeIris[4][1]-r.annotations.leftEyeIris[2][1])/2;n.ellipse(r.annotations.leftEyeIris[0][0],r.annotations.leftEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}if(r.annotations&&r.annotations.rightEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.rightEyeIris[3][0]-r.annotations.rightEyeIris[1][0])/2,i=Math.abs(r.annotations.rightEyeIris[4][1]-r.annotations.rightEyeIris[2][1])/2;n.ellipse(r.annotations.rightEyeIris[0][0],r.annotations.rightEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}}}}}var ja=[];async function Q6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round";for(let r=0;ri.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s.length===5&&Z2(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s)}}}}async function e4(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round",n.font=ce.font;for(let r of t){if(ce.drawBoxes&&(n.strokeStyle=ce.color,n.fillStyle=ce.color,Z6(n,r.box[0],r.box[1],r.box[2],r.box[3]),ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText("hand",r.box[0]+3,1+r.box[1]+ce.lineHeight,r.box[2])),n.fillStyle=ce.labelColor,n.fillText("hand",r.box[0]+2,0+r.box[1]+ce.lineHeight,r.box[2]),n.stroke()),ce.drawPoints&&r.landmarks&&r.landmarks.length>0)for(let a of r.landmarks)n.fillStyle=ce.useDepth?`rgba(${127.5+2*a[2]}, ${127.5-2*a[2]}, 255, 0.5)`:ce.color,u0(n,a[0],a[1]);if(ce.drawPolygons){let a=s=>{if(!!s)for(let i=0;i0?i-1:0][0],s[i>0?i-1:0][1]),n.lineTo(s[i][0],s[i][1]),n.stroke()};a(r.annotations.indexFinger),a(r.annotations.middleFinger),a(r.annotations.ringFinger),a(r.annotations.pinky),a(r.annotations.thumb)}}}}async function Cae(e,t){if(!e||!t||!(e instanceof HTMLCanvasElement)||!(t instanceof HTMLCanvasElement))return;let n=e.getContext("2d");n==null||n.drawImage(e,0,0)}async function Rae(e,t){!t||!e||e instanceof HTMLCanvasElement&&(J6(e,t.face),Q6(e,t.body),e4(e,t.hand),Y6(e,t.gesture))}var ct=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function Cc(...e){let t=n=>n&&typeof n=="object";return e.reduce((n,r)=>(Object.keys(r||{}).forEach(a=>{let s=n[a],i=r[a];Array.isArray(s)&&Array.isArray(i)?n[a]=s.concat(...i):t(s)&&t(i)?n[a]=Cc(s,i):n[a]=i}),n),{})}var Y2=class{constructor(t={}){this.calculateFaceAngle=t=>{if(!t||t.length<300)return{};let n=(s,i,o,l)=>Math.atan2(l-i,o-s),r=s=>Math.abs(s*180/Math.PI%360);return{roll:n(t[33][0],t[33][1],t[263][0],t[263][1]),yaw:n(t[33][0],t[33][2],t[263][0],t[263][2]),pitch:n(t[10][1],t[10][2],t[152][1],t[152][2])}};this.tf=nh,this.draw=K2,this.package=q2,this.version=X2,this.config=Cc(pt,t),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=n=>G2(n,this.config),this.facemesh=t4,this.age=s2,this.gender=l2,this.emotion=f2,this.body=this.config.body.modelType.startsWith("posenet")?M2:U2,this.hand=L2,this.sysinfo=hg()}profile(){return this.config.profile?n2:{}}analyze(...t){if(!this.analyzeMemoryLeaks)return;let n=this.tf.engine().state.numTensors,r=this.numTensors;this.numTensors=n;let a=n-r;a!==0&&Se(...t,a)}sanity(t){if(!this.checkSanity)return null;if(!t)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(t instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(n){return"backend not loaded"}return null}simmilarity(t,n){return this.config.face.embedding.enabled?e6(t,n):0}async load(t=null){this.state="load";let n=ct();t&&(this.config=Cc(this.config,t)),this.firstRun&&(this.config.debug&&Se(`version: ${this.version}`),this.config.debug&&Se(`tfjs version: ${this.tf.version_core}`),this.config.debug&&Se("platform:",this.sysinfo.platform),this.config.debug&&Se("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&Se("configuration:",this.config),this.config.debug&&Se("tf flags:",this.tf.ENV.flags)));let r=this.config.face.detector.modelPath.includes("faceboxes")?r2:t4;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?r.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?i2(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?d2(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?y2(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?x2(this.config):null),this.models.handpose||(this.config.hand.enabled?V2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?$2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?H2(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await r.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await i2(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await d2(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await y2(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await x2(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await V2(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await $2(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await H2(this.config))),this.firstRun&&(this.config.debug&&Se("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let a=Math.trunc(ct()-n);a>(this.perf.load||0)&&(this.perf.load=a)}async checkBackend(t=!1){if(this.config.backend&&this.config.backend!==""&&t||this.tf.getBackend()!==this.config.backend){let n=ct();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&Se("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&Se("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let r=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),a=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&Se(`wasm execution: ${r?"SIMD":"no SIMD"} ${a?"multithreaded":"singlethreaded"}`),r||Se("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&Bv();try{await this.tf.setBackend(this.config.backend)}catch(r){Se("error: cannot set backend:",this.config.backend,r)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(Se("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let r=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&Se(`gl version:${r.getParameter(r.VERSION)} renderer:${r.getParameter(r.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(ct()-n)}}async detectFace(t){var u,c,h,d,p,m;let n,r,a,s,i,o=[];this.state="run:face",n=ct();let l=await((u=this.models.face)==null?void 0:u.estimateFaces(t,this.config));this.perf.face=Math.trunc(ct()-n);for(let f of l){if(this.analyze("Get Face"),!f.image||f.image.isDisposedInternal){Se("Face object is disposed:",f.image);continue}let A=this.calculateFaceAngle(f.mesh);this.analyze("Start Age:"),this.config.async?r=this.config.face.age.enabled?o2(f.image,this.config):{}:(this.state="run:age",n=ct(),r=this.config.face.age.enabled?await o2(f.image,this.config):{},this.perf.age=Math.trunc(ct()-n)),this.analyze("Start Gender:"),this.config.async?a=this.config.face.gender.enabled?p2(f.image,this.config):{}:(this.state="run:gender",n=ct(),a=this.config.face.gender.enabled?await p2(f.image,this.config):{},this.perf.gender=Math.trunc(ct()-n)),this.analyze("Start Emotion:"),this.config.async?s=this.config.face.emotion.enabled?g2(f.image,this.config):{}:(this.state="run:emotion",n=ct(),s=this.config.face.emotion.enabled?await g2(f.image,this.config):{},this.perf.emotion=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?i=this.config.face.embedding.enabled?w2(f.image,this.config):[]:(this.state="run:embedding",n=ct(),i=this.config.face.embedding.enabled?await w2(f.image,this.config):[],this.perf.embedding=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.config.async&&([r,a,s,i]=await Promise.all([r,a,s,i])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((c=f==null?void 0:f.annotations)==null?void 0:c.leftEyeIris)&&((h=f==null?void 0:f.annotations)==null?void 0:h.rightEyeIris)&&(delete f.annotations.leftEyeIris,delete f.annotations.rightEyeIris);let y=((d=f.annotations)==null?void 0:d.leftEyeIris)&&((p=f.annotations)==null?void 0:p.rightEyeIris)?11.7*Math.max(Math.abs(f.annotations.leftEyeIris[3][0]-f.annotations.leftEyeIris[1][0]),Math.abs(f.annotations.rightEyeIris[4][1]-f.annotations.rightEyeIris[2][1])):0;o.push({confidence:f.confidence,faceConfidence:f.faceConfidence,boxConfidence:f.boxConfidence,box:f.box,mesh:f.mesh,boxRaw:f.boxRaw,meshRaw:f.meshRaw,annotations:f.annotations,age:r.age,gender:a.gender,genderConfidence:a.confidence,emotion:s,embedding:i,iris:y!==0?Math.trunc(y)/100:0,angle:A}),(m=f.image)==null||m.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),o}async detect(t,n={}){return new Promise(async r=>{var d,p,m,f;this.state="config";let a;this.config=Cc(this.config,n),this.state="check";let s=this.sanity(t);s&&(Se(s,t),r({error:s}));let i=ct();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),a=ct();let o=G2(t,this.config);if(!o||!o.tensor){Se("could not convert input to tensor"),r({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(ct()-a),this.analyze("Get Image:");let l,u,c;this.config.async?(c=this.config.face.enabled?this.detectFace(o.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",a=ct(),c=this.config.face.enabled?await this.detectFace(o.tensor):[],this.perf.face=Math.trunc(ct()-a)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?(d=this.models.posenet)==null?void 0:d.estimatePoses(o.tensor,this.config):[]:l=this.config.body.enabled?j2(o.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",a=ct(),this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?await((p=this.models.posenet)==null?void 0:p.estimatePoses(o.tensor,this.config)):[]:l=this.config.body.enabled?await j2(o.tensor,this.config):[],this.perf.body=Math.trunc(ct()-a)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(u=this.config.hand.enabled?(m=this.models.handpose)==null?void 0:m.estimateHands(o.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",a=ct(),u=this.config.hand.enabled?await((f=this.models.handpose)==null?void 0:f.estimateHands(o.tensor,this.config)):[],this.perf.hand=Math.trunc(ct()-a)),this.analyze("End Hand:"),this.config.async&&([c,l,u]=await Promise.all([c,l,u])),o.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let h=[];this.config.gesture.enabled&&(a=ct(),h=[...E6(c),...T6(l),...R6(u),...C6(c)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(ct()-a)),this.perf.total=Math.trunc(ct()-i),this.state="idle",r({face:c,body:l,hand:u,gesture:h,performance:this.perf,canvas:o.canvas})})}async warmupBitmap(){let t=(a,s="application/octet-stream")=>fetch(`data:${s};base64,${a}`).then(i=>i.blob()),n,r;switch(this.config.warmup){case"face":n=await t(o0);break;case"full":n=await t(l0);break;default:n=null}if(n){let a=await createImageBitmap(n);r=await this.detect(a,this.config),a.close()}return r}async warmupCanvas(){return new Promise(t=>{let n,r=0;switch(this.config.warmup){case"face":r=256,n="data:image/jpeg;base64,"+o0;break;case"full":case"body":r=1200,n="data:image/jpeg;base64,"+l0;break;default:n=null}let a=new Image;a.onload=async()=>{let s=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(r,r):document.createElement("canvas");s.width=a.naturalWidth,s.height=a.naturalHeight;let i=s.getContext("2d");i==null||i.drawImage(a,0,0);let o=await this.detect(s,this.config);t(o)},n?a.src=n:t(null)})}async warmupNode(){let t=i=>Buffer.from(i,"base64"),n=this.config.warmup==="face"?t(o0):t(l0),r=(void 0).decodeJpeg(n),a=r.expandDims(0);this.tf.dispose(r);let s=await this.detect(a,this.config);return this.tf.dispose(a),s}async warmup(t){let n=ct();t&&(this.config=Cc(this.config,t));let r=this.config.videoOptimized;this.config.videoOptimized=!1;let a;typeof createImageBitmap=="function"?a=await this.warmupBitmap():typeof Image!="undefined"?a=await this.warmupCanvas():a=await this.warmupNode(),this.config.videoOptimized=r;let s=ct();return this.config.debug&&Se("Warmup",this.config.warmup,Math.round(s-n),"ms",a),a}};return Mae;})(); +2Q==`;var q2={};Un(q2,{author:()=>W6,browser:()=>P6,bugs:()=>B6,default:()=>Eae,description:()=>$6,devDependencies:()=>q6,engines:()=>H6,homepage:()=>V6,keywords:()=>K6,license:()=>U6,main:()=>D6,module:()=>z6,name:()=>F6,peerDependencies:()=>G6,repository:()=>j6,scripts:()=>X6,sideEffects:()=>O6,types:()=>L6,version:()=>X2});var F6="@vladmandic/human",X2="1.0.1",$6="Human: AI-powered 3D Face Detection, Face Embedding & Recognition, Body Pose Tracking, Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction & Gesture Recognition",O6=!1,D6="dist/human.node.js",z6="dist/human.esm.js",P6="dist/human.esm.js",L6="types/human.d.ts",W6="Vladimir Mandic ",B6={url:"https://github.com/vladmandic/human/issues"},V6="https://vladmandic.github.io/human/demo/index.html",U6="MIT",H6={node:">=12.0.0"},j6={type:"git",url:"git+https://github.com/vladmandic/human.git"},G6={},q6={"@tensorflow/tfjs":"^3.2.0","@tensorflow/tfjs-backend-cpu":"^3.2.0","@tensorflow/tfjs-backend-wasm":"^3.2.0","@tensorflow/tfjs-backend-webgl":"^3.2.0","@tensorflow/tfjs-converter":"^3.2.0","@tensorflow/tfjs-core":"^3.2.0","@tensorflow/tfjs-data":"^3.2.0","@tensorflow/tfjs-layers":"^3.2.0","@tensorflow/tfjs-node":"^3.2.0","@tensorflow/tfjs-node-gpu":"^3.2.0","@types/node":"^14.14.32","@typescript-eslint/eslint-plugin":"^4.16.1","@typescript-eslint/parser":"^4.16.1","@vladmandic/pilogger":"^0.2.14",chokidar:"^3.5.1",dayjs:"^1.10.4",esbuild:"^0.8.57",eslint:"^7.21.0","eslint-config-airbnb-base":"^14.2.1","eslint-plugin-import":"^2.22.1","eslint-plugin-json":"^2.1.2","eslint-plugin-node":"^11.1.0","eslint-plugin-promise":"^4.3.1",rimraf:"^3.0.2",seedrandom:"^3.0.5","simple-git":"^2.36.1",tslib:"^2.1.0",typescript:"^4.2.3"},X6={start:"node --trace-warnings --unhandled-rejections=strict --trace-uncaught --no-deprecation src/node.js",lint:"eslint src demo server",test:"eslint src demo server",dev:"npm install && node server/serve.js",build:"rimraf dist/* && rimraf types/* && node server/build.js && node server/changelog.js",update:"npm update --depth 20 --force && npm dedupe && npm prune && npm audit"},K6=["tensorflowjs","face-detection","face-geometry","face-embedding","face-recognition","body-tracking","hand-tracking","iris-tracking","age-estimation","emotion-detection","gender-prediction","gesture-recognition","blazeface","blazepose"],Eae={name:F6,version:X2,description:$6,sideEffects:O6,main:D6,module:z6,browser:P6,types:L6,author:W6,bugs:B6,homepage:V6,license:U6,engines:H6,repository:j6,peerDependencies:G6,devDependencies:q6,scripts:X6,keywords:K6};var K2={};Un(K2,{all:()=>Rae,body:()=>Q6,canvas:()=>Cae,face:()=>J6,gesture:()=>Y6,hand:()=>e4,options:()=>ce});var ce={color:"rgba(173, 216, 230, 0.3)",labelColor:"rgba(173, 216, 230, 1)",shadowColor:"black",font:'small-caps 16px "Segoe UI"',lineHeight:20,lineWidth:6,pointSize:2,roundRect:28,drawPoints:!1,drawLabels:!0,drawBoxes:!0,drawPolygons:!0,fillPolygons:!1,useDepth:!0,useCurves:!1,bufferedOutput:!1};function u0(e,t,n){e.fillStyle=ce.color,e.beginPath(),e.arc(t,n,ce.pointSize,0,2*Math.PI),e.fill()}function Z6(e,t,n,r,a){if(e.beginPath(),ce.useCurves){let s=(t+t+r)/2,i=(n+n+a)/2;e.ellipse(s,i,r/2,a/2,0,0,2*Math.PI)}else e.lineWidth=ce.lineWidth,e.moveTo(t+ce.roundRect,n),e.lineTo(t+r-ce.roundRect,n),e.quadraticCurveTo(t+r,n,t+r,n+ce.roundRect),e.lineTo(t+r,n+a-ce.roundRect),e.quadraticCurveTo(t+r,n+a,t+r-ce.roundRect,n+a),e.lineTo(t+ce.roundRect,n+a),e.quadraticCurveTo(t,n+a,t,n+a-ce.roundRect),e.lineTo(t,n+ce.roundRect),e.quadraticCurveTo(t,n,t+ce.roundRect,n),e.closePath();e.stroke()}function Z2(e,t=[]){if(!(t===void 0||t.length===0)){e.beginPath(),e.moveTo(t[0][0],t[0][1]);for(let n of t)e.lineTo(n[0],parseInt(n[1]));e.stroke(),ce.fillPolygons&&(e.closePath(),e.fill())}}function c0(e,t=[]){if(!(t===void 0||t.length===0)){if(!ce.useCurves||t.length<=2){Z2(e,t);return}e.moveTo(t[0][0],t[0][1]);for(let n=0;n1&&i[1].length>0){let o=s[1]>0?`#${s[1]}`:"",l=`${s[0]} ${o}: ${i[1]}`;ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(l,8,2+r*ce.lineHeight)),n.fillStyle=ce.labelColor,n.fillText(l,6,0+r*ce.lineHeight),r+=1}}}async function J6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n)for(let r of t){n.font=ce.font,n.strokeStyle=ce.color,n.fillStyle=ce.color,ce.drawBoxes&&Z6(n,r.box[0],r.box[1],r.box[2],r.box[3]);let a=[];if(a.push(`face confidence: ${Math.trunc(100*r.confidence)}%`),r.genderConfidence&&a.push(`${r.gender||""} ${Math.trunc(100*r.genderConfidence)}% confident`),r.age&&a.push(`age: ${r.age||""}`),r.iris&&a.push(`iris distance: ${r.iris}`),r.emotion&&r.emotion.length>0){let s=r.emotion.map(i=>`${Math.trunc(100*i.score)}% ${i.emotion}`);a.push(s.join(" "))}r.angle&&r.angle.roll&&a.push(`roll: ${Math.trunc(100*r.angle.roll)/100} yaw:${Math.trunc(100*r.angle.yaw)/100} pitch:${Math.trunc(100*r.angle.pitch)/100}`),a.length===0&&a.push("face"),n.fillStyle=ce.color;for(let s=a.length-1;s>=0;s--){let i=Math.max(r.box[0],0),o=s*ce.lineHeight+r.box[1];ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText(a[s],i+5,o+16)),n.fillStyle=ce.labelColor,n.fillText(a[s],i+4,o+15)}if(n.lineWidth=1,r.mesh){if(ce.drawPoints)for(let s of r.mesh)n.fillStyle=ce.useDepth?`rgba(${127.5+2*s[2]}, ${127.5-2*s[2]}, 255, 0.5)`:ce.color,u0(n,s[0],s[1]);if(ce.drawPolygons){for(let s=0;sr.mesh[o]);n.strokeStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.fillStyle=ce.useDepth?`rgba(${127.5+2*i[0][2]}, ${127.5-2*i[0][2]}, 255, 0.3)`:ce.color,n.lineWidth=1,Z2(n,i)}if(r.annotations&&r.annotations.leftEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.leftEyeIris[3][0]-r.annotations.leftEyeIris[1][0])/2,i=Math.abs(r.annotations.leftEyeIris[4][1]-r.annotations.leftEyeIris[2][1])/2;n.ellipse(r.annotations.leftEyeIris[0][0],r.annotations.leftEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}if(r.annotations&&r.annotations.rightEyeIris){n.strokeStyle=ce.useDepth?"rgba(255, 200, 255, 0.3)":ce.color,n.beginPath();let s=Math.abs(r.annotations.rightEyeIris[3][0]-r.annotations.rightEyeIris[1][0])/2,i=Math.abs(r.annotations.rightEyeIris[4][1]-r.annotations.rightEyeIris[2][1])/2;n.ellipse(r.annotations.rightEyeIris[0][0],r.annotations.rightEyeIris[0][1],s,i,0,0,2*Math.PI),n.stroke(),ce.fillPolygons&&(n.fillStyle=ce.useDepth?"rgba(255, 255, 200, 0.3)":ce.color,n.fill())}}}}}var ja=[];async function Q6(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round";for(let r=0;ri.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),s.length===5&&Z2(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightHip"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightKnee"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightAnkle"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightHeel"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightFoot"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="leftShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="leftPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s),s.length=0,a=t[r].keypoints.find(i=>i.part==="rightShoulder"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightElbow"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightWrist"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),a=t[r].keypoints.find(i=>i.part==="rightPalm"),a&&a.score>pt.body.scoreThreshold&&s.push([a.position.x,a.position.y]),c0(n,s)}}}}async function e4(e,t){if(!t||!e||!(e instanceof HTMLCanvasElement))return;let n=e.getContext("2d");if(!!n){n.lineJoin="round",n.font=ce.font;for(let r of t){if(ce.drawBoxes&&(n.strokeStyle=ce.color,n.fillStyle=ce.color,Z6(n,r.box[0],r.box[1],r.box[2],r.box[3]),ce.shadowColor&&ce.shadowColor!==""&&(n.fillStyle=ce.shadowColor,n.fillText("hand",r.box[0]+3,1+r.box[1]+ce.lineHeight,r.box[2])),n.fillStyle=ce.labelColor,n.fillText("hand",r.box[0]+2,0+r.box[1]+ce.lineHeight,r.box[2]),n.stroke()),ce.drawPoints&&r.landmarks&&r.landmarks.length>0)for(let a of r.landmarks)n.fillStyle=ce.useDepth?`rgba(${127.5+2*a[2]}, ${127.5-2*a[2]}, 255, 0.5)`:ce.color,u0(n,a[0],a[1]);if(ce.drawPolygons){let a=s=>{if(!!s)for(let i=0;i0?i-1:0][0],s[i>0?i-1:0][1]),n.lineTo(s[i][0],s[i][1]),n.stroke()};a(r.annotations.indexFinger),a(r.annotations.middleFinger),a(r.annotations.ringFinger),a(r.annotations.pinky),a(r.annotations.thumb)}}}}async function Cae(e,t){if(!e||!t||!(e instanceof HTMLCanvasElement)||!(t instanceof HTMLCanvasElement))return;let n=e.getContext("2d");n==null||n.drawImage(e,0,0)}async function Rae(e,t){!t||!e||e instanceof HTMLCanvasElement&&(J6(e,t.face),Q6(e,t.body),e4(e,t.hand),Y6(e,t.gesture))}var ct=()=>typeof performance!="undefined"?performance.now():parseInt((Number(process.hrtime.bigint())/1e3/1e3).toString());function Cc(...e){let t=n=>n&&typeof n=="object";return e.reduce((n,r)=>(Object.keys(r||{}).forEach(a=>{let s=n[a],i=r[a];Array.isArray(s)&&Array.isArray(i)?n[a]=s.concat(...i):t(s)&&t(i)?n[a]=Cc(s,i):n[a]=i}),n),{})}var Y2=class{constructor(t={}){this.calculateFaceAngle=t=>{if(!t||t.length<300)return{};let n=(s,i,o,l)=>Math.atan2(l-i,o-s),r=s=>Math.abs(s*180/Math.PI%360);return{roll:n(t[33][0],t[33][1],t[263][0],t[263][1]),yaw:n(t[33][0],t[33][2],t[263][0],t[263][2]),pitch:n(t[10][1],t[10][2],t[152][1],t[152][2])}};this.tf=nh,this.draw=K2,this.package=q2,this.version=X2,this.config=Cc(pt,t),this.fx=null,this.state="idle",this.numTensors=0,this.analyzeMemoryLeaks=!1,this.checkSanity=!1,this.firstRun=!0,this.perf={},this.models={facemesh:null,posenet:null,blazepose:null,handpose:null,iris:null,age:null,gender:null,emotion:null},this.image=n=>G2(n,this.config),this.facemesh=t4,this.age=s2,this.gender=l2,this.emotion=f2,this.body=this.config.body.modelType.startsWith("posenet")?M2:U2,this.hand=L2,this.sysinfo=hg()}profile(){return this.config.profile?n2:{}}analyze(...t){if(!this.analyzeMemoryLeaks)return;let n=this.tf.engine().state.numTensors,r=this.numTensors;this.numTensors=n;let a=n-r;a!==0&&Se(...t,a)}sanity(t){if(!this.checkSanity)return null;if(!t)return"input is not defined";if(this.tf.ENV.flags.IS_NODE&&!(t instanceof this.tf.Tensor))return"input must be a tensor";try{this.tf.getBackend()}catch(n){return"backend not loaded"}return null}simmilarity(t,n){return this.config.face.embedding.enabled?e6(t,n):0}async load(t=null){this.state="load";let n=ct();t&&(this.config=Cc(this.config,t)),this.firstRun&&(this.config.debug&&Se(`version: ${this.version}`),this.config.debug&&Se(`tfjs version: ${this.tf.version_core}`),this.config.debug&&Se("platform:",this.sysinfo.platform),this.config.debug&&Se("agent:",this.sysinfo.agent),await this.checkBackend(!0),this.tf.ENV.flags.IS_BROWSER&&(this.config.debug&&Se("configuration:",this.config),this.config.debug&&Se("tf flags:",this.tf.ENV.flags)));let r=this.config.face.detector.modelPath.includes("faceboxes")?r2:t4;this.config.async?[this.models.face,this.models.age,this.models.gender,this.models.emotion,this.models.embedding,this.models.handpose,this.models.posenet,this.models.blazepose]=await Promise.all([this.models.face||(this.config.face.enabled?r.load(this.config):null),this.models.age||(this.config.face.enabled&&this.config.face.age.enabled?i2(this.config):null),this.models.gender||(this.config.face.enabled&&this.config.face.gender.enabled?d2(this.config):null),this.models.emotion||(this.config.face.enabled&&this.config.face.emotion.enabled?y2(this.config):null),this.models.embedding||(this.config.face.enabled&&this.config.face.embedding.enabled?x2(this.config):null),this.models.handpose||(this.config.hand.enabled?V2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("posenet")?$2(this.config):null),this.models.posenet||(this.config.body.enabled&&this.config.body.modelType.startsWith("blazepose")?H2(this.config):null)]):(this.config.face.enabled&&!this.models.face&&(this.models.face=await r.load(this.config)),this.config.face.enabled&&this.config.face.age.enabled&&!this.models.age&&(this.models.age=await i2(this.config)),this.config.face.enabled&&this.config.face.gender.enabled&&!this.models.gender&&(this.models.gender=await d2(this.config)),this.config.face.enabled&&this.config.face.emotion.enabled&&!this.models.emotion&&(this.models.emotion=await y2(this.config)),this.config.face.enabled&&this.config.face.embedding.enabled&&!this.models.embedding&&(this.models.embedding=await x2(this.config)),this.config.hand.enabled&&!this.models.handpose&&(this.models.handpose=await V2(this.config)),this.config.body.enabled&&!this.models.posenet&&this.config.body.modelType.startsWith("posenet")&&(this.models.posenet=await $2(this.config)),this.config.body.enabled&&!this.models.blazepose&&this.config.body.modelType.startsWith("blazepose")&&(this.models.blazepose=await H2(this.config))),this.firstRun&&(this.config.debug&&Se("tf engine state:",this.tf.engine().state.numBytes,"bytes",this.tf.engine().state.numTensors,"tensors"),this.firstRun=!1);let a=Math.trunc(ct()-n);a>(this.perf.load||0)&&(this.perf.load=a)}async checkBackend(t=!1){if(this.config.backend&&this.config.backend!==""&&t||this.tf.getBackend()!==this.config.backend){let n=ct();if(this.state="backend",this.config.backend&&this.config.backend!==""){if(this.config.debug&&Se("setting backend:",this.config.backend),this.config.backend==="wasm"){this.config.debug&&Se("wasm path:",this.config.wasmPath),this.tf.setWasmPaths(this.config.wasmPath);let r=await this.tf.env().getAsync("WASM_HAS_SIMD_SUPPORT"),a=await this.tf.env().getAsync("WASM_HAS_MULTITHREAD_SUPPORT");this.config.debug&&Se(`wasm execution: ${r?"SIMD":"no SIMD"} ${a?"multithreaded":"singlethreaded"}`),r||Se("warning: wasm simd support is not enabled")}this.config.backend==="humangl"&&Bv();try{await this.tf.setBackend(this.config.backend)}catch(r){Se("error: cannot set backend:",this.config.backend,r)}}if(this.tf.enableProdMode(),this.tf.getBackend()==="webgl"){this.config.deallocate&&(Se("changing webgl: WEBGL_DELETE_TEXTURE_THRESHOLD:",this.config.deallocate),this.tf.ENV.set("WEBGL_DELETE_TEXTURE_THRESHOLD",this.config.deallocate?0:-1));let r=await this.tf.backend().getGPGPUContext().gl;this.config.debug&&Se(`gl version:${r.getParameter(r.VERSION)} renderer:${r.getParameter(r.RENDERER)}`)}await this.tf.ready(),this.perf.backend=Math.trunc(ct()-n)}}async detectFace(t){var u,c,h,d,p,m;let n,r,a,s,i,o=[];this.state="run:face",n=ct();let l=await((u=this.models.face)==null?void 0:u.estimateFaces(t,this.config));this.perf.face=Math.trunc(ct()-n);for(let f of l){if(this.analyze("Get Face"),!f.image||f.image.isDisposedInternal){Se("Face object is disposed:",f.image);continue}let A=this.calculateFaceAngle(f.mesh);this.analyze("Start Age:"),this.config.async?r=this.config.face.age.enabled?o2(f.image,this.config):{}:(this.state="run:age",n=ct(),r=this.config.face.age.enabled?await o2(f.image,this.config):{},this.perf.age=Math.trunc(ct()-n)),this.analyze("Start Gender:"),this.config.async?a=this.config.face.gender.enabled?p2(f.image,this.config):{}:(this.state="run:gender",n=ct(),a=this.config.face.gender.enabled?await p2(f.image,this.config):{},this.perf.gender=Math.trunc(ct()-n)),this.analyze("Start Emotion:"),this.config.async?s=this.config.face.emotion.enabled?g2(f.image,this.config):{}:(this.state="run:emotion",n=ct(),s=this.config.face.emotion.enabled?await g2(f.image,this.config):{},this.perf.emotion=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.analyze("Start Embedding:"),this.config.async?i=this.config.face.embedding.enabled?w2(f.image,this.config):[]:(this.state="run:embedding",n=ct(),i=this.config.face.embedding.enabled?await w2(f.image,this.config):[],this.perf.embedding=Math.trunc(ct()-n)),this.analyze("End Emotion:"),this.config.async&&([r,a,s,i]=await Promise.all([r,a,s,i])),this.analyze("Finish Face:"),!this.config.face.iris.enabled&&((c=f==null?void 0:f.annotations)==null?void 0:c.leftEyeIris)&&((h=f==null?void 0:f.annotations)==null?void 0:h.rightEyeIris)&&(delete f.annotations.leftEyeIris,delete f.annotations.rightEyeIris);let y=((d=f.annotations)==null?void 0:d.leftEyeIris)&&((p=f.annotations)==null?void 0:p.rightEyeIris)?11.7*Math.max(Math.abs(f.annotations.leftEyeIris[3][0]-f.annotations.leftEyeIris[1][0]),Math.abs(f.annotations.rightEyeIris[4][1]-f.annotations.rightEyeIris[2][1])):0;o.push({confidence:f.confidence,faceConfidence:f.faceConfidence,boxConfidence:f.boxConfidence,box:f.box,mesh:f.mesh,boxRaw:f.boxRaw,meshRaw:f.meshRaw,annotations:f.annotations,age:r.age,gender:a.gender,genderConfidence:a.confidence,emotion:s,embedding:i,iris:y!==0?Math.trunc(y)/100:0,angle:A}),(m=f.image)==null||m.dispose(),this.analyze("End Face")}return this.analyze("End FaceMesh:"),this.config.async&&(this.perf.face&&delete this.perf.face,this.perf.age&&delete this.perf.age,this.perf.gender&&delete this.perf.gender,this.perf.emotion&&delete this.perf.emotion),o}async detect(t,n={}){return new Promise(async r=>{var d,p,m,f;this.state="config";let a;this.config=Cc(this.config,n),this.state="check";let s=this.sanity(t);s&&(Se(s,t),r({error:s}));let i=ct();await this.checkBackend(),await this.load(),this.config.scoped&&this.tf.engine().startScope(),this.analyze("Start Scope:"),a=ct();let o=G2(t,this.config);if(!o||!o.tensor){Se("could not convert input to tensor"),r({error:"could not convert input to tensor"});return}this.perf.image=Math.trunc(ct()-a),this.analyze("Get Image:");let l,u,c;this.config.async?(c=this.config.face.enabled?this.detectFace(o.tensor):[],this.perf.face&&delete this.perf.face):(this.state="run:face",a=ct(),c=this.config.face.enabled?await this.detectFace(o.tensor):[],this.perf.face=Math.trunc(ct()-a)),this.analyze("Start Body:"),this.config.async?(this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?(d=this.models.posenet)==null?void 0:d.estimatePoses(o.tensor,this.config):[]:l=this.config.body.enabled?j2(o.tensor,this.config):[],this.perf.body&&delete this.perf.body):(this.state="run:body",a=ct(),this.config.body.modelType.startsWith("posenet")?l=this.config.body.enabled?await((p=this.models.posenet)==null?void 0:p.estimatePoses(o.tensor,this.config)):[]:l=this.config.body.enabled?await j2(o.tensor,this.config):[],this.perf.body=Math.trunc(ct()-a)),this.analyze("End Body:"),this.analyze("Start Hand:"),this.config.async?(u=this.config.hand.enabled?(m=this.models.handpose)==null?void 0:m.estimateHands(o.tensor,this.config):[],this.perf.hand&&delete this.perf.hand):(this.state="run:hand",a=ct(),u=this.config.hand.enabled?await((f=this.models.handpose)==null?void 0:f.estimateHands(o.tensor,this.config)):[],this.perf.hand=Math.trunc(ct()-a)),this.analyze("End Hand:"),this.config.async&&([c,l,u]=await Promise.all([c,l,u])),o.tensor.dispose(),this.config.scoped&&this.tf.engine().endScope(),this.analyze("End Scope:");let h=[];this.config.gesture.enabled&&(a=ct(),h=[...E6(c),...T6(l),...R6(u),...C6(c)],this.config.async?this.perf.gesture&&delete this.perf.gesture:this.perf.gesture=Math.trunc(ct()-a)),this.perf.total=Math.trunc(ct()-i),this.state="idle",r({face:c,body:l,hand:u,gesture:h,performance:this.perf,canvas:o.canvas})})}async warmupBitmap(){let t=(a,s="application/octet-stream")=>fetch(`data:${s};base64,${a}`).then(i=>i.blob()),n,r;switch(this.config.warmup){case"face":n=await t(o0);break;case"full":n=await t(l0);break;default:n=null}if(n){let a=await createImageBitmap(n);r=await this.detect(a,this.config),a.close()}return r}async warmupCanvas(){return new Promise(t=>{let n,r=0;switch(this.config.warmup){case"face":r=256,n="data:image/jpeg;base64,"+o0;break;case"full":case"body":r=1200,n="data:image/jpeg;base64,"+l0;break;default:n=null}let a=new Image;a.onload=async()=>{let s=typeof OffscreenCanvas!="undefined"?new OffscreenCanvas(r,r):document.createElement("canvas");s.width=a.naturalWidth,s.height=a.naturalHeight;let i=s.getContext("2d");i==null||i.drawImage(a,0,0);let o=await this.detect(s,this.config);t(o)},n?a.src=n:t(null)})}async warmupNode(){let t=i=>Buffer.from(i,"base64"),n=this.config.warmup==="face"?t(o0):t(l0),r=(void 0).decodeJpeg(n),a=r.expandDims(0);this.tf.dispose(r);let s=await this.detect(a,this.config);return this.tf.dispose(a),s}async warmup(t){let n=ct();t&&(this.config=Cc(this.config,t));let r=this.config.videoOptimized;this.config.videoOptimized=!1;let a;typeof createImageBitmap=="function"?a=await this.warmupBitmap():typeof Image!="undefined"?a=await this.warmupCanvas():a=await this.warmupNode(),this.config.videoOptimized=r;let s=ct();return this.config.debug&&Se("Warmup",this.config.warmup,Math.round(s-n),"ms",a),a}};return Mae;})(); /** * @license * Copyright 2017 Google LLC. All Rights Reserved.