human/demo/faceid/index.js

10 lines
7.6 KiB
JavaScript

/*
Human
homepage: <https://github.com/vladmandic/human>
author: <https://github.com/vladmandic>'
*/
import*as I from"../../dist/human.esm.js";var l,z="human",g="person",p=(...t)=>console.log("indexdb",...t);async function v(){return l?!0:new Promise(t=>{let n=indexedDB.open(z,1);n.onerror=r=>p("error:",r),n.onupgradeneeded=r=>{p("create:",r.target),l=r.target.result,l.createObjectStore(g,{keyPath:"id",autoIncrement:!0})},n.onsuccess=r=>{l=r.target.result,p("open:",l),t(!0)}})}async function D(){let t=[];return l||await v(),new Promise(n=>{let r=l.transaction([g],"readwrite").objectStore(g).openCursor(null,"next");r.onerror=i=>p("load error:",i),r.onsuccess=i=>{i.target.result?(t.push(i.target.result.value),i.target.result.continue()):n(t)}})}async function y(){return l||await v(),new Promise(t=>{let n=l.transaction([g],"readwrite").objectStore(g).count();n.onerror=r=>p("count error:",r),n.onsuccess=()=>t(n.result)})}async function M(t){l||await v();let n={name:t.name,descriptor:t.descriptor,image:t.image};l.transaction([g],"readwrite").objectStore(g).put(n),p("save:",n)}async function B(t){l||await v(),l.transaction([g],"readwrite").objectStore(g).delete(t.id),p("delete:",t)}var b={modelBasePath:"../../models",filter:{equalization:!0},face:{enabled:!0,detector:{rotation:!0,return:!0,cropFactor:1.6,mask:!1},description:{enabled:!0},iris:{enabled:!0},emotion:{enabled:!1},antispoof:{enabled:!0},liveness:{enabled:!0}},body:{enabled:!1},hand:{enabled:!1},object:{enabled:!1},gesture:{enabled:!0}},S={order:2,multiplier:25,min:.2,max:.8},c={minConfidence:.6,minSize:224,maxTime:1e4,blinkMin:10,blinkMax:800,threshold:.5,mask:b.face.detector.mask,rotation:b.face.detector.rotation,cropFactor:b.face.detector.cropFactor,...S},o={faceCount:!1,faceConfidence:!1,facingCenter:!1,lookingCenter:!1,blinkDetected:!1,faceSize:!1,antispoofCheck:!1,livenessCheck:!1,elapsedMs:0},H=()=>o.faceCount&&o.faceSize&&o.blinkDetected&&o.facingCenter&&o.lookingCenter&&o.faceConfidence&&o.antispoofCheck&&o.livenessCheck,s={face:null,record:null},f={start:0,end:0,time:0},a=new I.Human(b);a.env.perfadd=!1;a.draw.options.font='small-caps 18px "Lato"';a.draw.options.lineHeight=20;var e={video:document.getElementById("video"),canvas:document.getElementById("canvas"),log:document.getElementById("log"),fps:document.getElementById("fps"),match:document.getElementById("match"),name:document.getElementById("name"),save:document.getElementById("save"),delete:document.getElementById("delete"),retry:document.getElementById("retry"),source:document.getElementById("source"),ok:document.getElementById("ok")},w={detect:0,draw:0},h={detect:0,draw:0},T=0,u=(...t)=>{e.log.innerText+=t.join(" ")+`
`,console.log(...t)},k=t=>e.fps.innerText=t;async function L(){k("starting webcam...");let t={audio:!1,video:{facingMode:"user",resizeMode:"none",width:{ideal:document.body.clientWidth}}},n=await navigator.mediaDevices.getUserMedia(t),r=new Promise(i=>{e.video.onloadeddata=()=>i(!0)});e.video.srcObject=n,e.video.play(),await r,e.canvas.width=e.video.videoWidth,e.canvas.height=e.video.videoHeight,a.env.initial&&u("video:",e.video.videoWidth,e.video.videoHeight,"|",n.getVideoTracks()[0].label),e.canvas.onclick=()=>{e.video.paused?e.video.play():e.video.pause()}}async function R(){var t;if(!e.video.paused){(t=s.face)!=null&&t.tensor&&a.tf.dispose(s.face.tensor),await a.detect(e.video);let n=a.now();h.detect=1e3/(n-w.detect),w.detect=n,requestAnimationFrame(R)}}async function F(){let t=a.next(a.result);a.draw.canvas(e.video,e.canvas),await a.draw.all(e.canvas,t);let n=a.now();if(h.draw=1e3/(n-w.draw),w.draw=n,k(`fps: ${h.detect.toFixed(1).padStart(5," ")} detect | ${h.draw.toFixed(1).padStart(5," ")} draw`),o.faceCount=a.result.face.length===1,o.faceCount){let i=Object.values(a.result.gesture).map(m=>m.gesture);(i.includes("blink left eye")||i.includes("blink right eye"))&&(f.start=a.now()),f.start>0&&!i.includes("blink left eye")&&!i.includes("blink right eye")&&(f.end=a.now()),o.blinkDetected=o.blinkDetected||Math.abs(f.end-f.start)>c.blinkMin&&Math.abs(f.end-f.start)<c.blinkMax,o.blinkDetected&&f.time===0&&(f.time=Math.trunc(f.end-f.start)),o.facingCenter=i.includes("facing center"),o.lookingCenter=i.includes("looking center"),o.faceConfidence=(a.result.face[0].boxScore||0)>c.minConfidence&&(a.result.face[0].faceScore||0)>c.minConfidence,o.antispoofCheck=(a.result.face[0].real||0)>c.minConfidence,o.livenessCheck=(a.result.face[0].live||0)>c.minConfidence,o.faceSize=a.result.face[0].box[2]>=c.minSize&&a.result.face[0].box[3]>=c.minSize}let r=32;for(let[i,m]of Object.entries(o)){let d=document.getElementById(`ok-${i}`);d||(d=document.createElement("div"),d.innerText=i,d.className="ok",d.style.top=`${r}px`,e.ok.appendChild(d)),typeof m=="boolean"?d.style.backgroundColor=m?"lightgreen":"lightcoral":d.innerText=`${i}:${m}`,r+=28}return H()||o.elapsedMs>c.maxTime?(e.video.pause(),a.result.face[0]):(o.elapsedMs=Math.trunc(a.now()-T),new Promise(i=>{setTimeout(async()=>{await F(),i(a.result.face[0])},30)}))}async function j(){var t,n,r,i;if(e.name.value.length>0){let m=(t=e.canvas.getContext("2d"))==null?void 0:t.getImageData(0,0,e.canvas.width,e.canvas.height),d={id:0,name:e.name.value,descriptor:(n=s.face)==null?void 0:n.embedding,image:m};await M(d),u("saved face record:",d.name,"descriptor length:",(i=(r=s.face)==null?void 0:r.embedding)==null?void 0:i.length),u("known face records:",await y())}else u("invalid name")}async function q(){s.record&&s.record.id>0&&await B(s.record)}async function O(){var i,m,d,C;if((i=e.canvas.getContext("2d"))==null||i.clearRect(0,0,c.minSize,c.minSize),!((m=s==null?void 0:s.face)!=null&&m.tensor)||!((d=s==null?void 0:s.face)!=null&&d.embedding))return!1;if(console.log("face record:",s.face),a.tf.browser.toPixels(s.face.tensor,e.canvas),await y()===0)return u("face database is empty"),document.body.style.background="black",e.delete.style.display="none",!1;let t=await D(),n=t.map(x=>x.descriptor).filter(x=>x.length>0),r=a.match(s.face.embedding,n,S);return s.record=t[r.index]||null,s.record&&(u(`best match: ${s.record.name} | id: ${s.record.id} | similarity: ${Math.round(1e3*r.similarity)/10}%`),e.name.value=s.record.name,e.source.style.display="",(C=e.source.getContext("2d"))==null||C.putImageData(s.record.image,0,0)),document.body.style.background=r.similarity>c.threshold?"darkgreen":"maroon",r.similarity>c.threshold}async function E(){var t,n;return o.faceCount=!1,o.faceConfidence=!1,o.facingCenter=!1,o.blinkDetected=!1,o.faceSize=!1,o.antispoofCheck=!1,o.livenessCheck=!1,o.elapsedMs=0,e.match.style.display="none",e.retry.style.display="none",e.source.style.display="none",document.body.style.background="black",await L(),await R(),T=a.now(),s.face=await F(),e.canvas.width=((t=s.face.tensor)==null?void 0:t.shape[1])||c.minSize,e.canvas.height=((n=s.face.tensor)==null?void 0:n.shape[0])||c.minSize,e.source.width=e.canvas.width,e.source.height=e.canvas.height,e.canvas.style.width="",e.match.style.display="flex",e.save.style.display="flex",e.delete.style.display="flex",e.retry.style.display="block",H()?O():(u("did not find valid face"),!1)}async function $(){var t,n;u("human version:",a.version,"| tfjs version:",a.tf.version["tfjs-core"]),u("face embedding model:",b.face.description.enabled?"faceres":"",(t=b.face.mobilefacenet)!=null&&t.enabled?"mobilefacenet":"",(n=b.face.insightface)!=null&&n.enabled?"insightface":""),u("options:",JSON.stringify(c).replace(/{|}|"|\[|\]/g,"").replace(/,/g," ")),k("loading..."),u("known face records:",await y()),await L(),await a.load(),k("initializing..."),e.retry.addEventListener("click",E),e.save.addEventListener("click",j),e.delete.addEventListener("click",q),await a.warmup(),await E()}window.onload=$;
//# sourceMappingURL=index.js.map