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