1+ const video2 = document . getElementsByClassName ( 'input_video2' ) [ 0 ] ;
2+ const out2 = document . getElementsByClassName ( 'output2' ) [ 0 ] ;
3+ const controlsElement2 = document . getElementsByClassName ( 'control2' ) [ 0 ] ;
4+ const canvasCtx = out2 . getContext ( '2d' ) ;
5+
6+ const fpsControl = new FPS ( ) ;
7+ const spinner = document . querySelector ( '.loading' ) ;
8+ spinner . ontransitionend = ( ) => {
9+ spinner . style . display = 'none' ;
10+ } ;
11+
12+ function onResultsFaceMesh ( results ) {
13+ document . body . classList . add ( 'loaded' ) ;
14+ fpsControl . tick ( ) ;
15+
16+ canvasCtx . save ( ) ;
17+ canvasCtx . clearRect ( 0 , 0 , out2 . width , out2 . height ) ;
18+ canvasCtx . drawImage (
19+ results . image , 0 , 0 , out2 . width , out2 . height ) ;
20+ if ( results . multiFaceLandmarks ) {
21+ for ( const landmarks of results . multiFaceLandmarks ) {
22+ drawConnectors (
23+ canvasCtx , landmarks , FACEMESH_TESSELATION ,
24+ { color : '#C0C0C070' , lineWidth : 1 } ) ;
25+ drawConnectors (
26+ canvasCtx , landmarks , FACEMESH_RIGHT_EYE ,
27+ { color : '#FF3030' } ) ;
28+ drawConnectors (
29+ canvasCtx , landmarks , FACEMESH_RIGHT_EYEBROW ,
30+ { color : '#FF3030' } ) ;
31+ drawConnectors (
32+ canvasCtx , landmarks , FACEMESH_LEFT_EYE ,
33+ { color : '#30FF30' } ) ;
34+ drawConnectors (
35+ canvasCtx , landmarks , FACEMESH_LEFT_EYEBROW ,
36+ { color : '#30FF30' } ) ;
37+ drawConnectors (
38+ canvasCtx , landmarks , FACEMESH_FACE_OVAL ,
39+ { color : '#E0E0E0' } ) ;
40+ drawConnectors (
41+ canvasCtx , landmarks , FACEMESH_LIPS ,
42+ { color : '#E0E0E0' } ) ;
43+ }
44+ }
45+ canvasCtx . restore ( ) ;
46+ }
47+
48+ const faceMesh = new FaceMesh ( { locateFile : ( file ) => {
49+ return `https://cdn.jsdelivr.net/npm/@mediapipe/[email protected] /${ file } ` ; 50+ } } ) ;
51+ faceMesh . onResults ( onResultsFaceMesh ) ;
52+
53+ const camera = new Camera ( video2 , {
54+ onFrame : async ( ) => {
55+ await faceMesh . send ( { image : video2 } ) ;
56+ } ,
57+ width : 480 ,
58+ height : 480
59+ } ) ;
60+ camera . start ( ) ;
61+
62+ new ControlPanel ( controlsElement2 , {
63+ selfieMode : true ,
64+ maxNumFaces : 1 ,
65+ minDetectionConfidence : 0.5 ,
66+ minTrackingConfidence : 0.5
67+ } )
68+ . add ( [
69+ new StaticText ( { title : 'MediaPipe Face Mesh' } ) ,
70+ fpsControl ,
71+ new Toggle ( { title : 'Selfie Mode' , field : 'selfieMode' } ) ,
72+ new Slider ( {
73+ title : 'Max Number of Faces' ,
74+ field : 'maxNumFaces' ,
75+ range : [ 1 , 4 ] ,
76+ step : 1
77+ } ) ,
78+ new Slider ( {
79+ title : 'Min Detection Confidence' ,
80+ field : 'minDetectionConfidence' ,
81+ range : [ 0 , 1 ] ,
82+ step : 0.01
83+ } ) ,
84+ new Slider ( {
85+ title : 'Min Tracking Confidence' ,
86+ field : 'minTrackingConfidence' ,
87+ range : [ 0 , 1 ] ,
88+ step : 0.01
89+ } ) ,
90+ ] )
91+ . on ( options => {
92+ video2 . classList . toggle ( 'selfie' , options . selfieMode ) ;
93+ faceMesh . setOptions ( options ) ;
94+ } ) ;
0 commit comments