1+ const video4 = document . getElementsByClassName ( 'input_video4' ) [ 0 ] ;
2+ const out4 = document . getElementsByClassName ( 'output4' ) [ 0 ] ;
3+ const controlsElement4 = document . getElementsByClassName ( 'control4' ) [ 0 ] ;
4+ const canvasCtx4 = out4 . 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 removeElements ( landmarks , elements ) {
13+ for ( const element of elements ) {
14+ delete landmarks [ element ] ;
15+ }
16+ }
17+
18+ function removeLandmarks ( results ) {
19+ if ( results . poseLandmarks ) {
20+ removeElements (
21+ results . poseLandmarks ,
22+ [ 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 15 , 16 , 17 , 18 , 19 , 20 , 21 , 22 ] ) ;
23+ }
24+ }
25+
26+ function connect ( ctx , connectors ) {
27+ const canvas = ctx . canvas ;
28+ for ( const connector of connectors ) {
29+ const from = connector [ 0 ] ;
30+ const to = connector [ 1 ] ;
31+ if ( from && to ) {
32+ if ( from . visibility && to . visibility &&
33+ ( from . visibility < 0.1 || to . visibility < 0.1 ) ) {
34+ continue ;
35+ }
36+ ctx . beginPath ( ) ;
37+ ctx . moveTo ( from . x * canvas . width , from . y * canvas . height ) ;
38+ ctx . lineTo ( to . x * canvas . width , to . y * canvas . height ) ;
39+ ctx . stroke ( ) ;
40+ }
41+ }
42+ }
43+
44+ function onResultsHolistic ( results ) {
45+ document . body . classList . add ( 'loaded' ) ;
46+ removeLandmarks ( results ) ;
47+ fpsControl . tick ( ) ;
48+
49+ canvasCtx4 . save ( ) ;
50+ canvasCtx4 . clearRect ( 0 , 0 , out4 . width , out4 . height ) ;
51+ canvasCtx4 . drawImage (
52+ results . image , 0 , 0 , out4 . width , out4 . height ) ;
53+ canvasCtx4 . lineWidth = 5 ;
54+ if ( results . poseLandmarks ) {
55+ if ( results . rightHandLandmarks ) {
56+ canvasCtx4 . strokeStyle = '#00FF00' ;
57+ connect ( canvasCtx4 , [ [
58+ results . poseLandmarks [ POSE_LANDMARKS . RIGHT_ELBOW ] ,
59+ results . rightHandLandmarks [ 0 ]
60+ ] ] ) ;
61+ }
62+ if ( results . leftHandLandmarks ) {
63+ canvasCtx4 . strokeStyle = '#FF0000' ;
64+ connect ( canvasCtx4 , [ [
65+ results . poseLandmarks [ POSE_LANDMARKS . LEFT_ELBOW ] ,
66+ results . leftHandLandmarks [ 0 ]
67+ ] ] ) ;
68+ }
69+ }
70+ drawConnectors (
71+ canvasCtx4 , results . poseLandmarks , POSE_CONNECTIONS ,
72+ { color : '#00FF00' } ) ;
73+ drawLandmarks (
74+ canvasCtx4 , results . poseLandmarks ,
75+ { color : '#00FF00' , fillColor : '#FF0000' } ) ;
76+ drawConnectors (
77+ canvasCtx4 , results . rightHandLandmarks , HAND_CONNECTIONS ,
78+ { color : '#00CC00' } ) ;
79+ drawLandmarks (
80+ canvasCtx4 , results . rightHandLandmarks , {
81+ color : '#00FF00' ,
82+ fillColor : '#FF0000' ,
83+ lineWidth : 2 ,
84+ radius : ( data ) => {
85+ return lerp ( data . from . z , - 0.15 , .1 , 10 , 1 ) ;
86+ }
87+ } ) ;
88+ drawConnectors (
89+ canvasCtx4 , results . leftHandLandmarks , HAND_CONNECTIONS ,
90+ { color : '#CC0000' } ) ;
91+ drawLandmarks (
92+ canvasCtx4 , results . leftHandLandmarks , {
93+ color : '#FF0000' ,
94+ fillColor : '#00FF00' ,
95+ lineWidth : 2 ,
96+ radius : ( data ) => {
97+ return lerp ( data . from . z , - 0.15 , .1 , 10 , 1 ) ;
98+ }
99+ } ) ;
100+ drawConnectors (
101+ canvasCtx4 , results . faceLandmarks , FACEMESH_TESSELATION ,
102+ { color : '#C0C0C070' , lineWidth : 1 } ) ;
103+ drawConnectors (
104+ canvasCtx4 , results . faceLandmarks , FACEMESH_RIGHT_EYE ,
105+ { color : '#FF3030' } ) ;
106+ drawConnectors (
107+ canvasCtx4 , results . faceLandmarks , FACEMESH_RIGHT_EYEBROW ,
108+ { color : '#FF3030' } ) ;
109+ drawConnectors (
110+ canvasCtx4 , results . faceLandmarks , FACEMESH_LEFT_EYE ,
111+ { color : '#30FF30' } ) ;
112+ drawConnectors (
113+ canvasCtx4 , results . faceLandmarks , FACEMESH_LEFT_EYEBROW ,
114+ { color : '#30FF30' } ) ;
115+ drawConnectors (
116+ canvasCtx4 , results . faceLandmarks , FACEMESH_FACE_OVAL ,
117+ { color : '#E0E0E0' } ) ;
118+ drawConnectors (
119+ canvasCtx4 , results . faceLandmarks , FACEMESH_LIPS ,
120+ { color : '#E0E0E0' } ) ;
121+
122+ canvasCtx4 . restore ( ) ;
123+ }
124+
125+ const holistic = new Holistic ( { locateFile : ( file ) => {
126+ return `https://cdn.jsdelivr.net/npm/@mediapipe/[email protected] /${ file } ` ; 127+ } } ) ;
128+ holistic . onResults ( onResultsHolistic ) ;
129+
130+ const camera = new Camera ( video4 , {
131+ onFrame : async ( ) => {
132+ await holistic . send ( { image : video4 } ) ;
133+ } ,
134+ width : 480 ,
135+ height : 480
136+ } ) ;
137+ camera . start ( ) ;
138+
139+ new ControlPanel ( controlsElement4 , {
140+ selfieMode : true ,
141+ upperBodyOnly : true ,
142+ smoothLandmarks : true ,
143+ minDetectionConfidence : 0.5 ,
144+ minTrackingConfidence : 0.5
145+ } )
146+ . add ( [
147+ new StaticText ( { title : 'MediaPipe Holistic' } ) ,
148+ fpsControl ,
149+ new Toggle ( { title : 'Selfie Mode' , field : 'selfieMode' } ) ,
150+ new Toggle ( { title : 'Upper-body Only' , field : 'upperBodyOnly' } ) ,
151+ new Toggle (
152+ { title : 'Smooth Landmarks' , field : 'smoothLandmarks' } ) ,
153+ new Slider ( {
154+ title : 'Min Detection Confidence' ,
155+ field : 'minDetectionConfidence' ,
156+ range : [ 0 , 1 ] ,
157+ step : 0.01
158+ } ) ,
159+ new Slider ( {
160+ title : 'Min Tracking Confidence' ,
161+ field : 'minTrackingConfidence' ,
162+ range : [ 0 , 1 ] ,
163+ step : 0.01
164+ } ) ,
165+ ] )
166+ . on ( options => {
167+ video4 . classList . toggle ( 'selfie' , options . selfieMode ) ;
168+ holistic . setOptions ( options ) ;
169+ } ) ;
0 commit comments