1
+ <!DOCTYPE html>
2
+ < html >
3
+ < head >
4
+ < script src ="face-api.js "> </ script >
5
+ < script src ="js/commons.js "> </ script >
6
+ < script src ="js/faceDetectionControls.js "> </ script >
7
+ < link rel ="stylesheet " href ="styles.css ">
8
+ < link rel ="stylesheet " href ="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css ">
9
+ < script type ="text/javascript " src ="https://code.jquery.com/jquery-2.1.1.min.js "> </ script >
10
+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js "> </ script >
11
+ </ head >
12
+ < body >
13
+ < div id ="navbar "> </ div >
14
+ < div class ="center-content page-container ">
15
+
16
+ < div class ="progress " id ="loader ">
17
+ < div class ="indeterminate "> </ div >
18
+ </ div >
19
+ < div style ="position: relative " class ="margin ">
20
+ < video onloadedmetadata ="onPlay(this) " id ="inputVideo " autoplay muted > </ video >
21
+ < canvas id ="overlay " />
22
+ </ div >
23
+
24
+ < div class ="row side-by-side ">
25
+
26
+ <!-- face_detector_selection_control -->
27
+ < div id ="face_detector_selection_control " class ="row input-field " style ="margin-right: 20px; ">
28
+ < select id ="selectFaceDetector ">
29
+ < option value ="ssd_mobilenetv1 "> SSD Mobilenet V1</ option >
30
+ < option value ="tiny_face_detector "> Tiny Face Detector</ option >
31
+ < option value ="mtcnn "> MTCNN</ option >
32
+ </ select >
33
+ < label > Select Face Detector</ label >
34
+ </ div >
35
+ <!-- face_detector_selection_control -->
36
+
37
+ <!-- check boxes -->
38
+ < div class ="row " style ="width: 220px; ">
39
+ < input type ="checkbox " id ="hideBoundingBoxesCheckbox " onchange ="onChangeHideBoundingBoxes(event) " />
40
+ < label for ="hideBoundingBoxesCheckbox "> Hide Bounding Boxes</ label >
41
+ </ div >
42
+ <!-- check boxes -->
43
+
44
+ <!-- fps_meter -->
45
+ < div id ="fps_meter " class ="row side-by-side ">
46
+ < div >
47
+ < label for ="time "> Time:</ label >
48
+ < input disabled value ="- " id ="time " type ="text " class ="bold ">
49
+ < label for ="fps "> Estimated Fps:</ label >
50
+ < input disabled value ="- " id ="fps " type ="text " class ="bold ">
51
+ </ div >
52
+ </ div >
53
+ <!-- fps_meter -->
54
+
55
+ </ div >
56
+
57
+
58
+ <!-- ssd_mobilenetv1_controls -->
59
+ < span id ="ssd_mobilenetv1_controls ">
60
+ < div class ="row side-by-side ">
61
+ < div class ="row ">
62
+ < label for ="minConfidence "> Min Confidence:</ label >
63
+ < input disabled value ="0.5 " id ="minConfidence " type ="text " class ="bold ">
64
+ </ div >
65
+ < button
66
+ class ="waves-effect waves-light btn "
67
+ onclick ="onDecreaseMinConfidence() "
68
+ >
69
+ < i class ="material-icons left "> -</ i >
70
+ </ button >
71
+ < button
72
+ class ="waves-effect waves-light btn "
73
+ onclick ="onIncreaseMinConfidence() "
74
+ >
75
+ < i class ="material-icons left "> +</ i >
76
+ </ button >
77
+ </ div >
78
+ </ span >
79
+ <!-- ssd_mobilenetv1_controls -->
80
+
81
+ <!-- tiny_face_detector_controls -->
82
+ < span id ="tiny_face_detector_controls ">
83
+ < div class ="row side-by-side ">
84
+ < div class ="row input-field " style ="margin-right: 20px; ">
85
+ < select id ="inputSize ">
86
+ < option value ="" disabled selected > Input Size:</ option >
87
+ < option value ="128 "> 128 x 128</ option >
88
+ < option value ="160 "> 160 x 160</ option >
89
+ < option value ="224 "> 224 x 224</ option >
90
+ < option value ="320 "> 320 x 320</ option >
91
+ < option value ="416 "> 416 x 416</ option >
92
+ < option value ="512 "> 512 x 512</ option >
93
+ < option value ="608 "> 608 x 608</ option >
94
+ </ select >
95
+ < label > Input Size</ label >
96
+ </ div >
97
+ < div class ="row ">
98
+ < label for ="scoreThreshold "> Score Threshold:</ label >
99
+ < input disabled value ="0.5 " id ="scoreThreshold " type ="text " class ="bold ">
100
+ </ div >
101
+ < button
102
+ class ="waves-effect waves-light btn "
103
+ onclick ="onDecreaseScoreThreshold() "
104
+ >
105
+ < i class ="material-icons left "> -</ i >
106
+ </ button >
107
+ < button
108
+ class ="waves-effect waves-light btn "
109
+ onclick ="onIncreaseScoreThreshold() "
110
+ >
111
+ < i class ="material-icons left "> +</ i >
112
+ </ button >
113
+ </ div >
114
+ </ span >
115
+ <!-- tiny_face_detector_controls -->
116
+
117
+ <!-- mtcnn_controls -->
118
+ < span id ="mtcnn_controls ">
119
+ < div class ="row side-by-side ">
120
+ < div class ="row ">
121
+ < label for ="minFaceSize "> Minimum Face Size:</ label >
122
+ < input disabled value ="20 " id ="minFaceSize " type ="text " class ="bold ">
123
+ </ div >
124
+ < button
125
+ class ="waves-effect waves-light btn "
126
+ onclick ="onDecreaseMinFaceSize() "
127
+ >
128
+ < i class ="material-icons left "> -</ i >
129
+ </ button >
130
+ < button
131
+ class ="waves-effect waves-light btn "
132
+ onclick ="onIncreaseMinFaceSize() "
133
+ >
134
+ < i class ="material-icons left "> +</ i >
135
+ </ button >
136
+ </ div >
137
+ </ span >
138
+ <!-- mtcnn_controls -->
139
+
140
+ </ body >
141
+
142
+ < script >
143
+ let forwardTimes = [ ]
144
+ let predictedAges = [ ]
145
+ let withBoxes = true
146
+
147
+ function onChangeHideBoundingBoxes ( e ) {
148
+ withBoxes = ! $ ( e . target ) . prop ( 'checked' )
149
+ }
150
+
151
+ function updateTimeStats ( timeInMs ) {
152
+ forwardTimes = [ timeInMs ] . concat ( forwardTimes ) . slice ( 0 , 30 )
153
+ const avgTimeInMs = forwardTimes . reduce ( ( total , t ) => total + t ) / forwardTimes . length
154
+ $ ( '#time' ) . val ( `${ Math . round ( avgTimeInMs ) } ms` )
155
+ $ ( '#fps' ) . val ( `${ faceapi . round ( 1000 / avgTimeInMs ) } ` )
156
+ }
157
+
158
+ function interpolateAgePredictions ( age ) {
159
+ predictedAges = [ age ] . concat ( predictedAges ) . slice ( 0 , 30 )
160
+ const avgPredictedAge = predictedAges . reduce ( ( total , a ) => total + a ) / predictedAges . length
161
+ return avgPredictedAge
162
+ }
163
+
164
+ async function onPlay ( ) {
165
+ const videoEl = $ ( '#inputVideo' ) . get ( 0 )
166
+
167
+ if ( videoEl . paused || videoEl . ended || ! isFaceDetectionModelLoaded ( ) )
168
+ return setTimeout ( ( ) => onPlay ( ) )
169
+
170
+
171
+ const options = getFaceDetectorOptions ( )
172
+
173
+ const ts = Date . now ( )
174
+
175
+ const result = await faceapi . detectSingleFace ( videoEl , options )
176
+ . withAgeAndGender ( )
177
+
178
+ updateTimeStats ( Date . now ( ) - ts )
179
+
180
+ if ( result ) {
181
+ const canvas = $ ( '#overlay' ) . get ( 0 )
182
+ const dims = faceapi . matchDimensions ( canvas , videoEl , true )
183
+
184
+ const resizedResult = faceapi . resizeResults ( result , dims )
185
+ if ( withBoxes ) {
186
+ faceapi . draw . drawDetections ( canvas , resizedResult )
187
+ }
188
+ const { age, gender, genderProbability } = resizedResult
189
+
190
+ // interpolate gender predictions over last 30 frames
191
+ // to make the displayed age more stable
192
+ const interpolatedAge = interpolateAgePredictions ( age )
193
+ new faceapi . draw . DrawTextField (
194
+ [
195
+ `${ faceapi . round ( interpolatedAge , 0 ) } years` ,
196
+ `${ gender } (${ faceapi . round ( genderProbability ) } )`
197
+ ] ,
198
+ result . detection . box . bottomLeft
199
+ ) . draw ( canvas )
200
+ }
201
+
202
+ setTimeout ( ( ) => onPlay ( ) )
203
+ }
204
+
205
+ async function run ( ) {
206
+ // load face detection and face expression recognition models
207
+ await changeFaceDetector ( TINY_FACE_DETECTOR )
208
+ await faceapi . nets . ageGenderNet . load ( '/' )
209
+ changeInputSize ( 224 )
210
+
211
+ // try to access users webcam and stream the images
212
+ // to the video element
213
+ const stream = await navigator . mediaDevices . getUserMedia ( { video : { } } )
214
+ const videoEl = $ ( '#inputVideo' ) . get ( 0 )
215
+ videoEl . srcObject = stream
216
+ }
217
+
218
+ function updateResults ( ) { }
219
+
220
+ $ ( document ) . ready ( function ( ) {
221
+ renderNavBar ( '#navbar' , 'webcam_age_and_gender_recognition' )
222
+ initFaceDetectionControls ( )
223
+ run ( )
224
+ } )
225
+ </ script >
226
+ </ body >
227
+ </ html >
0 commit comments