1
+ <!DOCTYPE html>
2
+ < html >
3
+ < head >
4
+ < script src ="face-api.js "> </ script >
5
+ < script src ="commons.js "> </ script >
6
+ < link rel ="stylesheet " href ="styles.css ">
7
+ < link rel ="stylesheet " href ="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css ">
8
+ < script type ="text/javascript " src ="https://code.jquery.com/jquery-2.1.1.min.js "> </ script >
9
+ < script src ="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js "> </ script >
10
+ </ head >
11
+ < body >
12
+ < div id ="navbar "> </ div >
13
+ < div class ="center-content page-container ">
14
+ < div class ="progress " id ="loader ">
15
+ < div class ="indeterminate "> </ div >
16
+ </ div >
17
+ < div style ="position: relative " class ="margin ">
18
+ < img id ="inputImg " src ="" style ="max-width: 800px; " />
19
+ < canvas id ="overlay " />
20
+ </ div >
21
+ < div class ="row side-by-side ">
22
+ < div id ="selectList "> </ div >
23
+ < div class ="row ">
24
+ < label for ="imgUrlInput "> Get image from URL:</ label >
25
+ < input id ="imgUrlInput " type ="text " class ="bold ">
26
+ </ div >
27
+ < button
28
+ class ="waves-effect waves-light btn "
29
+ onclick ="loadImageFromUrl() "
30
+ >
31
+ Ok
32
+ </ button >
33
+ < p >
34
+ < input type ="checkbox " id ="useBatchProcessing " onchange ="onChangeUseBatchProcessing(event) " />
35
+ < label for ="useBatchProcessing "> Use Batch Processing</ label >
36
+ </ p >
37
+ </ div >
38
+ < div class ="row side-by-side ">
39
+ < div class ="row input-field " style ="margin-right: 20px; ">
40
+ < select id ="sizeType ">
41
+ < option value ="" disabled selected > Input Size:</ option >
42
+ < option value ="xs "> XS: 224 x 224</ option >
43
+ < option value ="sm "> SM: 320 x 320</ option >
44
+ < option value ="md "> MD: 416 x 416</ option >
45
+ < option value ="lg "> LG: 608 x 608</ option >
46
+ </ select >
47
+ < label > Input Size</ label >
48
+ </ div >
49
+ < div class ="row ">
50
+ < label for ="scoreThreshold "> Score Threshold:</ label >
51
+ < input disabled value ="0.5 " id ="scoreThreshold " type ="text " class ="bold ">
52
+ </ div >
53
+ < button
54
+ class ="waves-effect waves-light btn "
55
+ onclick ="onDecreaseThreshold() "
56
+ >
57
+ < i class ="material-icons left "> -</ i >
58
+ </ button >
59
+ < button
60
+ class ="waves-effect waves-light btn "
61
+ onclick ="onIncreaseThreshold() "
62
+ >
63
+ < i class ="material-icons left "> +</ i >
64
+ </ button >
65
+ </ div >
66
+ < div class ="row side-by-side ">
67
+ < div class ="row ">
68
+ < label for ="maxDistance "> Max Descriptor Distance:</ label >
69
+ < input disabled value ="0.6 " id ="maxDistance " type ="text " class ="bold ">
70
+ </ div >
71
+ < button
72
+ class ="waves-effect waves-light btn button-sm "
73
+ onclick ="onDecreaseMaxDistance() "
74
+ >
75
+ < i class ="material-icons left "> -</ i >
76
+ </ button >
77
+ < button
78
+ class ="waves-effect waves-light btn button-sm "
79
+ onclick ="onIncreaseMaxDistance() "
80
+ >
81
+ < i class ="material-icons left "> +</ i >
82
+ </ button >
83
+ </ div >
84
+ </ div >
85
+
86
+ < script >
87
+ let maxDistance = 0.6
88
+ let useBatchProcessing = false
89
+ let trainDescriptorsByClass = [ ]
90
+ let scoreThreshold = 0.5
91
+ let sizeType = 'lg'
92
+
93
+ function onIncreaseThreshold ( ) {
94
+ scoreThreshold = Math . min ( faceapi . round ( scoreThreshold + 0.1 ) , 1.0 )
95
+ $ ( '#scoreThreshold' ) . val ( scoreThreshold )
96
+ updateResults ( )
97
+ }
98
+
99
+ function onDecreaseThreshold ( ) {
100
+ scoreThreshold = Math . max ( faceapi . round ( scoreThreshold - 0.1 ) , 0.1 )
101
+ $ ( '#scoreThreshold' ) . val ( scoreThreshold )
102
+ updateResults ( )
103
+ }
104
+
105
+ function onSizeTypeChanged ( e , c ) {
106
+ sizeType = e . target . value
107
+ $ ( '#sizeType' ) . val ( sizeType )
108
+ updateResults ( )
109
+ }
110
+
111
+ function onChangeUseBatchProcessing ( e ) {
112
+ useBatchProcessing = $ ( e . target ) . prop ( 'checked' )
113
+ }
114
+
115
+ function onIncreaseMaxDistance ( ) {
116
+ maxDistance = Math . min ( faceapi . round ( maxDistance + 0.1 ) , 1.0 )
117
+ $ ( '#maxDistance' ) . val ( maxDistance )
118
+ updateResults ( )
119
+ }
120
+
121
+ function onDecreaseMaxDistance ( ) {
122
+ maxDistance = Math . max ( faceapi . round ( maxDistance - 0.1 ) , 0.1 )
123
+ $ ( '#maxDistance' ) . val ( maxDistance )
124
+ updateResults ( )
125
+ }
126
+
127
+ async function loadImageFromUrl ( url ) {
128
+ const img = await requestExternalImage ( $ ( '#imgUrlInput' ) . val ( ) )
129
+ $ ( '#inputImg' ) . get ( 0 ) . src = img . src
130
+ updateResults ( )
131
+ }
132
+
133
+ async function updateResults ( ) {
134
+ const inputImgEl = $ ( '#inputImg' ) . get ( 0 )
135
+ const { width, height } = inputImgEl
136
+ const canvas = $ ( '#overlay' ) . get ( 0 )
137
+ canvas . width = width
138
+ canvas . height = height
139
+
140
+ const forwardParams = {
141
+ inputSize : sizeType ,
142
+ scoreThreshold
143
+ }
144
+
145
+ const fullFaceDescriptions = ( await faceapi . allFacesTinyYolov2 ( inputImgEl , forwardParams , useBatchProcessing ) )
146
+ . map ( fd => fd . forSize ( width , height ) )
147
+
148
+ fullFaceDescriptions . forEach ( ( { detection, descriptor } ) => {
149
+ faceapi . drawDetection ( 'overlay' , [ detection ] , { withScore : false } )
150
+ const bestMatch = getBestMatch ( trainDescriptorsByClass , descriptor )
151
+ const text = `${ bestMatch . distance < maxDistance ? bestMatch . className : 'unkown' } (${ bestMatch . distance } )`
152
+ const { x, y, height : boxHeight } = detection . getBox ( )
153
+ faceapi . drawText (
154
+ canvas . getContext ( '2d' ) ,
155
+ x ,
156
+ y + boxHeight ,
157
+ text ,
158
+ Object . assign ( faceapi . getDefaultDrawOptions ( ) , { color : 'red' , fontSize : 16 } )
159
+ )
160
+ } )
161
+ }
162
+
163
+ async function onSelectionChanged ( uri ) {
164
+ const imgBuf = await fetchImage ( uri )
165
+ $ ( `#inputImg` ) . get ( 0 ) . src = ( await faceapi . bufferToImage ( imgBuf ) ) . src
166
+ updateResults ( )
167
+ }
168
+
169
+ async function run ( ) {
170
+ await faceapi . loadTinyYolov2Model ( '/' )
171
+ await faceapi . loadFaceLandmarkModel ( '/' )
172
+ await faceapi . loadFaceRecognitionModel ( '/' )
173
+ trainDescriptorsByClass = await initTrainDescriptorsByClass ( faceapi . recognitionNet , 1 )
174
+ $ ( '#loader' ) . hide ( )
175
+ onSelectionChanged ( $ ( '#selectList select' ) . val ( ) )
176
+ }
177
+
178
+ $ ( document ) . ready ( function ( ) {
179
+ renderNavBar ( '#navbar' , 'tiny_yolov2_face_recognition' )
180
+ renderImageSelectList (
181
+ '#selectList' ,
182
+ async ( uri ) => {
183
+ await onSelectionChanged ( uri )
184
+ } ,
185
+ 'bbt1.jpg'
186
+ )
187
+
188
+ const sizeTypeSelect = $ ( '#sizeType' )
189
+ sizeTypeSelect . val ( sizeType )
190
+ sizeTypeSelect . on ( 'change' , onSizeTypeChanged )
191
+ sizeTypeSelect . material_select ( )
192
+ run ( )
193
+ } )
194
+ </ script >
195
+ </ body >
196
+ </ html >
0 commit comments