├── README.md
├── faceapi
├── css
│ └── styles.css
├── index.html
├── js
│ ├── face-api.js
│ └── faceDetectionControls.js
└── models
│ ├── mtcnn_model-shard1
│ ├── mtcnn_model-weights_manifest.json
│ ├── ssd_mobilenetv1_model-shard1
│ ├── ssd_mobilenetv1_model-shard2
│ ├── ssd_mobilenetv1_model-weights_manifest.json
│ ├── tiny_face_detector_model-shard1
│ └── tiny_face_detector_model-weights_manifest.json
├── index.html
├── opencvjs
├── index.css
├── index.html
└── index.js
└── pico
├── index.htm
└── js
├── camvas.js
├── index.js
└── pico.js
/README.md:
--------------------------------------------------------------------------------
1 | # lightweight-webcam-javascript-face-detection
2 |
3 | This is a comparison of different javascript face detection libraries available for real-time webcam analysis in the browser. These are static implementations that do not require processing from the server-side. The aim of this work is to start from the simplest and cleanest implementations that do not require node.js installation. The original demos available on each library have tons of extra styles and libraries that do not add extra value to the main functionality.
4 |
5 | Libraries implemented:
6 |
7 | * pico.js
8 | * opencv.js
9 | * face.api.js
10 |
11 | Demo: https://www.carlostoxtli.com/lightweight-webcam-javascript-face-detection/
12 |
--------------------------------------------------------------------------------
/faceapi/css/styles.css:
--------------------------------------------------------------------------------
1 | #statusContainer {
2 | position: relative;
3 | }
4 |
5 | #statusColor {
6 | background-color: red;
7 | width: 20px;
8 | height: 20px;
9 | display: inline-block;
10 | }
11 |
12 | #statusText {
13 | font-size: 20px;
14 | font-family: Verdana;
15 | display: inline-block;
16 | }
17 |
18 | .page-container {
19 | left: 0;
20 | right: 0;
21 | margin: auto;
22 | margin-top: 20px;
23 | padding-left: 280px;
24 | display: inline-flex !important;
25 | }
26 |
27 | @media only screen and (max-width : 992px) {
28 | .page-container {
29 | padding-left: 0;
30 | display: flex !important;
31 | }
32 | }
33 |
34 | #navbar {
35 | position: absolute;
36 | top: 20px;
37 | left: 20px;
38 | }
39 |
40 | .center-content {
41 | display: flex;
42 | flex-direction: column;
43 | justify-content: center;
44 | align-items: center;
45 | flex-wrap: wrap;
46 | }
47 |
48 | .side-by-side {
49 | display: flex;
50 | justify-content: center;
51 | align-items: center;
52 | }
53 | .side-by-side >* {
54 | margin: 0 5px;
55 | }
56 |
57 | .bold {
58 | font-weight: bold;
59 | }
60 |
61 | .margin-sm {
62 | margin: 5px;
63 | }
64 |
65 | .margin {
66 | margin: 20px;
67 | }
68 |
69 | .button-sm {
70 | padding: 0 10px !important;
71 | }
72 |
73 | .pad-sides-sm {
74 | padding: 0 8px !important;
75 | }
76 |
77 | #github-link {
78 | display: flex !important;
79 | justify-content: center;
80 | align-items: center;
81 | border-bottom: 1px solid;
82 | margin-bottom: 10px;
83 | }
84 |
85 | #overlay, .overlay {
86 | position: absolute;
87 | top: 0;
88 | left: 0;
89 | }
90 |
91 | #facesContainer canvas {
92 | margin: 10px;
93 | }
--------------------------------------------------------------------------------
/faceapi/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
29 |
30 |
31 |
85 |
86 |
--------------------------------------------------------------------------------
/faceapi/js/faceDetectionControls.js:
--------------------------------------------------------------------------------
1 | const SSD_MOBILENETV1 = 'ssd_mobilenetv1'
2 | const TINY_FACE_DETECTOR = 'tiny_face_detector'
3 | const MTCNN = 'mtcnn'
4 |
5 |
6 | let selectedFaceDetector = SSD_MOBILENETV1
7 |
8 | // ssd_mobilenetv1 options
9 | let minConfidence = 0.5
10 |
11 | // tiny_face_detector options
12 | let inputSize = 512
13 | let scoreThreshold = 0.5
14 |
15 | //mtcnn options
16 | let minFaceSize = 20
17 |
18 | function getFaceDetectorOptions() {
19 | return selectedFaceDetector === SSD_MOBILENETV1
20 | ? new faceapi.SsdMobilenetv1Options({ minConfidence })
21 | : (
22 | selectedFaceDetector === TINY_FACE_DETECTOR
23 | ? new faceapi.TinyFaceDetectorOptions({ inputSize, scoreThreshold })
24 | : new faceapi.MtcnnOptions({ minFaceSize })
25 | )
26 | }
27 |
28 | function onIncreaseMinConfidence() {
29 | minConfidence = Math.min(faceapi.round(minConfidence + 0.1), 1.0)
30 | $('#minConfidence').val(minConfidence)
31 | updateResults()
32 | }
33 |
34 | function onDecreaseMinConfidence() {
35 | minConfidence = Math.max(faceapi.round(minConfidence - 0.1), 0.1)
36 | $('#minConfidence').val(minConfidence)
37 | updateResults()
38 | }
39 |
40 | function onInputSizeChanged(e) {
41 | changeInputSize(e.target.value)
42 | updateResults()
43 | }
44 |
45 | function changeInputSize(size) {
46 | inputSize = parseInt(size)
47 |
48 | const inputSizeSelect = $('#inputSize')
49 | inputSizeSelect.val(inputSize)
50 | inputSizeSelect.material_select()
51 | }
52 |
53 | function onIncreaseScoreThreshold() {
54 | scoreThreshold = Math.min(faceapi.round(scoreThreshold + 0.1), 1.0)
55 | $('#scoreThreshold').val(scoreThreshold)
56 | updateResults()
57 | }
58 |
59 | function onDecreaseScoreThreshold() {
60 | scoreThreshold = Math.max(faceapi.round(scoreThreshold - 0.1), 0.1)
61 | $('#scoreThreshold').val(scoreThreshold)
62 | updateResults()
63 | }
64 |
65 | function onIncreaseMinFaceSize() {
66 | minFaceSize = Math.min(faceapi.round(minFaceSize + 20), 300)
67 | $('#minFaceSize').val(minFaceSize)
68 | }
69 |
70 | function onDecreaseMinFaceSize() {
71 | minFaceSize = Math.max(faceapi.round(minFaceSize - 20), 50)
72 | $('#minFaceSize').val(minFaceSize)
73 | }
74 |
75 | function getCurrentFaceDetectionNet() {
76 | if (selectedFaceDetector === SSD_MOBILENETV1) {
77 | return faceapi.nets.ssdMobilenetv1
78 | }
79 | if (selectedFaceDetector === TINY_FACE_DETECTOR) {
80 | return faceapi.nets.tinyFaceDetector
81 | }
82 | if (selectedFaceDetector === MTCNN) {
83 | return faceapi.nets.mtcnn
84 | }
85 | }
86 |
87 | function isFaceDetectionModelLoaded() {
88 | return !!getCurrentFaceDetectionNet().params
89 | }
90 |
91 | async function changeFaceDetector(detector) {
92 | ['#ssd_mobilenetv1_controls', '#tiny_face_detector_controls', '#mtcnn_controls']
93 | .forEach(id => $(id).hide())
94 |
95 | selectedFaceDetector = detector
96 | const faceDetectorSelect = $('#selectFaceDetector')
97 | faceDetectorSelect.val(detector)
98 | faceDetectorSelect.material_select()
99 |
100 | $('#loader').show()
101 | if (!isFaceDetectionModelLoaded()) {
102 | await getCurrentFaceDetectionNet().load('models/')
103 | }
104 |
105 | $(`#${detector}_controls`).show()
106 | $('#loader').hide()
107 | }
108 |
109 | async function onSelectedFaceDetectorChanged(e) {
110 | selectedFaceDetector = e.target.value
111 |
112 | await changeFaceDetector(e.target.value)
113 | updateResults()
114 | }
115 |
116 | function initFaceDetectionControls() {
117 | const faceDetectorSelect = $('#selectFaceDetector')
118 | faceDetectorSelect.val(selectedFaceDetector)
119 | faceDetectorSelect.on('change', onSelectedFaceDetectorChanged)
120 | faceDetectorSelect.material_select()
121 |
122 | const inputSizeSelect = $('#inputSize')
123 | inputSizeSelect.val(inputSize)
124 | inputSizeSelect.on('change', onInputSizeChanged)
125 | inputSizeSelect.material_select()
126 | }
--------------------------------------------------------------------------------
/faceapi/models/mtcnn_model-shard1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toxtli/lightweight-webcam-javascript-face-detection/a5e2862dc839897f39308b8f72c1c4897ce3d427/faceapi/models/mtcnn_model-shard1
--------------------------------------------------------------------------------
/faceapi/models/mtcnn_model-weights_manifest.json:
--------------------------------------------------------------------------------
1 | [{"paths":["mtcnn_model-shard1"],"weights":[{"dtype":"float32","name":"pnet/conv1/weights","shape":[3,3,3,10]},{"dtype":"float32","name":"pnet/conv1/bias","shape":[10]},{"dtype":"float32","name":"pnet/prelu1_alpha","shape":[10]},{"dtype":"float32","name":"pnet/conv2/weights","shape":[3,3,10,16]},{"dtype":"float32","name":"pnet/conv2/bias","shape":[16]},{"dtype":"float32","name":"pnet/prelu2_alpha","shape":[16]},{"dtype":"float32","name":"pnet/conv3/weights","shape":[3,3,16,32]},{"dtype":"float32","name":"pnet/conv3/bias","shape":[32]},{"dtype":"float32","name":"pnet/prelu3_alpha","shape":[32]},{"dtype":"float32","name":"pnet/conv4_1/weights","shape":[1,1,32,2]},{"dtype":"float32","name":"pnet/conv4_1/bias","shape":[2]},{"dtype":"float32","name":"pnet/conv4_2/weights","shape":[1,1,32,4]},{"dtype":"float32","name":"pnet/conv4_2/bias","shape":[4]},{"dtype":"float32","name":"rnet/conv1/weights","shape":[3,3,3,28]},{"dtype":"float32","name":"rnet/conv1/bias","shape":[28]},{"dtype":"float32","name":"rnet/prelu1_alpha","shape":[28]},{"dtype":"float32","name":"rnet/conv2/weights","shape":[3,3,28,48]},{"dtype":"float32","name":"rnet/conv2/bias","shape":[48]},{"dtype":"float32","name":"rnet/prelu2_alpha","shape":[48]},{"dtype":"float32","name":"rnet/conv3/weights","shape":[2,2,48,64]},{"dtype":"float32","name":"rnet/conv3/bias","shape":[64]},{"dtype":"float32","name":"rnet/prelu3_alpha","shape":[64]},{"dtype":"float32","name":"rnet/fc1/weights","shape":[576,128]},{"dtype":"float32","name":"rnet/fc1/bias","shape":[128]},{"dtype":"float32","name":"rnet/prelu4_alpha","shape":[128]},{"dtype":"float32","name":"rnet/fc2_1/weights","shape":[128,2]},{"dtype":"float32","name":"rnet/fc2_1/bias","shape":[2]},{"dtype":"float32","name":"rnet/fc2_2/weights","shape":[128,4]},{"dtype":"float32","name":"rnet/fc2_2/bias","shape":[4]},{"dtype":"float32","name":"onet/conv1/weights","shape":[3,3,3,32]},{"dtype":"float32","name":"onet/conv1/bias","shape":[32]},{"dtype":"float32","name":"onet/prelu1_alpha","shape":[32]},{"dtype":"float32","name":"onet/conv2/weights","shape":[3,3,32,64]},{"dtype":"float32","name":"onet/conv2/bias","shape":[64]},{"dtype":"float32","name":"onet/prelu2_alpha","shape":[64]},{"dtype":"float32","name":"onet/conv3/weights","shape":[3,3,64,64]},{"dtype":"float32","name":"onet/conv3/bias","shape":[64]},{"dtype":"float32","name":"onet/prelu3_alpha","shape":[64]},{"dtype":"float32","name":"onet/conv4/weights","shape":[2,2,64,128]},{"dtype":"float32","name":"onet/conv4/bias","shape":[128]},{"dtype":"float32","name":"onet/prelu4_alpha","shape":[128]},{"dtype":"float32","name":"onet/fc1/weights","shape":[1152,256]},{"dtype":"float32","name":"onet/fc1/bias","shape":[256]},{"dtype":"float32","name":"onet/prelu5_alpha","shape":[256]},{"dtype":"float32","name":"onet/fc2_1/weights","shape":[256,2]},{"dtype":"float32","name":"onet/fc2_1/bias","shape":[2]},{"dtype":"float32","name":"onet/fc2_2/weights","shape":[256,4]},{"dtype":"float32","name":"onet/fc2_2/bias","shape":[4]},{"dtype":"float32","name":"onet/fc2_3/weights","shape":[256,10]},{"dtype":"float32","name":"onet/fc2_3/bias","shape":[10]}]}]
--------------------------------------------------------------------------------
/faceapi/models/ssd_mobilenetv1_model-shard1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toxtli/lightweight-webcam-javascript-face-detection/a5e2862dc839897f39308b8f72c1c4897ce3d427/faceapi/models/ssd_mobilenetv1_model-shard1
--------------------------------------------------------------------------------
/faceapi/models/ssd_mobilenetv1_model-shard2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toxtli/lightweight-webcam-javascript-face-detection/a5e2862dc839897f39308b8f72c1c4897ce3d427/faceapi/models/ssd_mobilenetv1_model-shard2
--------------------------------------------------------------------------------
/faceapi/models/ssd_mobilenetv1_model-weights_manifest.json:
--------------------------------------------------------------------------------
1 | [{"paths":["ssd_mobilenetv1_model-shard1","ssd_mobilenetv1_model-shard2"],"weights":[{"dtype":"float32","shape":[1,1,512,9],"quantization":{"scale":0.0026856216729856004,"min":-0.34107395246917127,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/ClassPredictor/weights"},{"dtype":"float32","shape":[9],"quantization":{"scale":0.00198518248165355,"min":-0.32159956202787515,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,1024,18],"quantization":{"scale":0.003060340296988394,"min":-0.489654447518143,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.0008040678851744708,"min":-0.12221831854651957,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,512,18],"quantization":{"scale":0.0012513800578958848,"min":-0.16017664741067325,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.000338070518245884,"min":-0.05510549447407909,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,256,18],"quantization":{"scale":0.0011819932975021064,"min":-0.1453851755927591,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.00015985782386041154,"min":-0.026536398760828316,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,256,18],"quantization":{"scale":0.0007035591438704846,"min":-0.08513065640832863,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.00008793946574716008,"min":-0.013190919862074012,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/ClassPredictor/biases"},{"dtype":"float32","shape":[1,1,128,18],"quantization":{"scale":0.00081320781918133,"min":-0.11059626340866088,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/ClassPredictor/weights"},{"dtype":"float32","shape":[18],"quantization":{"scale":0.0000980533805547976,"min":-0.014609953702664841,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/ClassPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":3,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/stack_1/2"},{"dtype":"int32","shape":[3],"quantization":{"scale":0.00392156862745098,"min":0,"dtype":"uint8"},"name":"Postprocessor/Slice/begin"},{"dtype":"int32","shape":[3],"quantization":{"scale":1,"min":-1,"dtype":"uint8"},"name":"Postprocessor/Slice/size"},{"dtype":"float32","shape":[1,1,512,12],"quantization":{"scale":0.003730384859384275,"min":-0.4327246436885759,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[12],"quantization":{"scale":0.0018744708568442102,"min":-0.3917644090804399,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":3072,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/stack_1/1"},{"dtype":"float32","shape":[1,1,1024,24],"quantization":{"scale":0.00157488017689948,"min":-0.20000978246623397,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.0002823906713256649,"min":-0.043488163384152394,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":1536,"dtype":"uint8"},"name":"Prediction/BoxPredictor_1/stack_1/1"},{"dtype":"float32","shape":[1,1,512,24],"quantization":{"scale":0.0007974451663447361,"min":-0.11004743295557358,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.0001350417988849621,"min":-0.02039131163162928,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":384,"dtype":"uint8"},"name":"Prediction/BoxPredictor_2/stack_1/1"},{"dtype":"float32","shape":[1,1,256,24],"quantization":{"scale":0.0007113990246080885,"min":-0.0860792819775787,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.000050115815418608046,"min":-0.007617603943628423,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":96,"dtype":"uint8"},"name":"Prediction/BoxPredictor_3/stack_1/1"},{"dtype":"float32","shape":[1,1,256,24],"quantization":{"scale":0.000590049314732645,"min":-0.06903576982371946,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.00003513663861097074,"min":-0.006359731588585704,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/BoxEncodingPredictor/biases"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":24,"dtype":"uint8"},"name":"Prediction/BoxPredictor_4/stack_1/1"},{"dtype":"float32","shape":[1,1,128,24],"quantization":{"scale":0.0005990567744946948,"min":-0.07907549423329971,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/BoxEncodingPredictor/weights"},{"dtype":"float32","shape":[24],"quantization":{"scale":0.00003392884288640583,"min":-0.006039334033780238,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/BoxEncodingPredictor/biases"},{"dtype":"float32","shape":[],"quantization":{"scale":1,"min":0.007843137718737125,"dtype":"uint8"},"name":"Preprocessor/mul/x"},{"dtype":"int32","shape":[2],"quantization":{"scale":1,"min":512,"dtype":"uint8"},"name":"Preprocessor/ResizeImage/size"},{"dtype":"float32","shape":[],"quantization":{"scale":1,"min":1,"dtype":"uint8"},"name":"Preprocessor/sub/y"},{"dtype":"float32","shape":[3,3,3,32],"quantization":{"scale":0.03948551065781537,"min":-5.014659853542552,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_0_pointwise/weights"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.0498106133704092,"min":-7.371970778820562,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_0_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,32,1],"quantization":{"scale":0.036833542468501075,"min":-4.714693435968138,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/depthwise_weights"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.012173276705046495,"min":-0.012173276705046495,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.032182769214405736,"min":-2.4780732295092416,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.028287527607936486,"min":-3.366215785344442,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[32],"quantization":{"scale":0.04716738532571232,"min":3.9071404665769224e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,32,64],"quantization":{"scale":0.04010109433940812,"min":-4.290817094316669,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_pointwise/weights"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.2212210038129021,"min":-34.51047659481273,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_1_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,64,1],"quantization":{"scale":0.010024750933927648,"min":-1.343316625146305,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/depthwise_weights"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.006120916675118839,"min":0.5227176547050476,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.02317035385206634,"min":-0.7646216771181892,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.04980821422502106,"min":-5.8275610643274645,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.051751047022202436,"min":3.916113799002297e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,64,128],"quantization":{"scale":0.021979344124887504,"min":-2.1319963801140878,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.09958663267247816,"min":-11.054116226645077,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_2_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,1],"quantization":{"scale":0.01943492702409333,"min":-2.6237151482525993,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/depthwise_weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.017852897737540452,"min":0.40204083919525146,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.029888209174661076,"min":-1.972621805527631,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.029319268581913967,"min":-5.130872001834945,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.014018708584355373,"min":3.9083178263362604e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,128,128],"quantization":{"scale":0.020776657964669022,"min":-2.5347522716896207,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.14383157094319662,"min":-9.636715253194174,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_3_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,1],"quantization":{"scale":0.004463558571011412,"min":-0.5981168485155293,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/depthwise_weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.006487431245691636,"min":0.47910428047180176,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.026542164297664865,"min":-1.2209395576925839,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.05119945675719018,"min":-8.60150873520795,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.03081628388049556,"min":3.911508751095344e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,128,256],"quantization":{"scale":0.010758659886378868,"min":-1.0328313490923713,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.08058219610476026,"min":-9.34753474815219,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_4_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,256,1],"quantization":{"scale":0.01145936741548426,"min":-1.3292866201961742,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/depthwise_weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.0083988838336047,"min":0.36280909180641174,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.02858148649627087,"min":-3.6584302715226715,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.03988401375564874,"min":-7.099354448505476,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.009090481683904049,"min":0.020878996700048447,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,256,256],"quantization":{"scale":0.008951201625898773,"min":-1.1189002032373465,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.051758006974762565,"min":-5.745138774198645,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_5_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,256,1],"quantization":{"scale":0.004110433190476661,"min":-0.6042336790000691,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/depthwise_weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.013170199768216002,"min":0.3386639356613159,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.03599378548416437,"min":-3.70735990486893,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.026967673208199296,"min":-3.748506575939702,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.012615410486857097,"min":3.9111388979838637e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,256,512],"quantization":{"scale":0.00822840648538926,"min":-1.1848905338960536,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.06608965817619772,"min":-7.468131373910342,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_6_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.008801074355256323,"min":-0.9593171047229393,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.030577416513480393,"min":0.3285980224609375,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04778536441279393,"min":-8.935863145192464,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04331884945140165,"min":-9.660103427662568,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04126455444367785,"min":0.000604183878749609,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.009305818408143287,"min":-1.1446156642016243,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04640720217835669,"min":-4.733534622192383,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_7_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.008138792655047248,"min":-0.9766551186056698,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.027351748358969596,"min":0.34030041098594666,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04415061053107767,"min":-7.019947074441349,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.02476683784933651,"min":-2.9224868662217083,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.02547598832684076,"min":0.00026032101595774293,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.01083052625843123,"min":-1.2563410459780227,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.06360894371481503,"min":-7.951117964351878,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_8_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.006704086883395326,"min":-0.8648272079579971,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.015343831567203297,"min":0.2711026668548584,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.03378283930759804,"min":-4.797163181678922,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.021910778213949763,"min":-3.987761634938857,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.009284070410007296,"min":0.000021581046894425526,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.012783036979974485,"min":-1.9046725100161983,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.07273082733154297,"min":-9.52773838043213,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_9_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.006126228033327589,"min":-0.7351473639993107,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.029703759212119908,"min":0.28687000274658203,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.04394429898729511,"min":-6.3279790541704966,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.016566915605582443,"min":-2.7501079905266854,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.012152872833551145,"min":3.913338286370366e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.01354524388032801,"min":-1.7473364605623134,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.08566816367355047,"min":-9.937506986131854,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_10_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.006012305558896532,"min":-0.7876120282154457,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.01469323155926723,"min":0.29223933815956116,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.030889174517463234,"min":-3.2433633243336395,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.014836942448335536,"min":-2.047498057870304,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.007234466105343445,"min":0.00013165915152058005,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,512],"quantization":{"scale":0.016261722527298274,"min":-1.4798167499841428,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.091437328563017,"min":-14.172785927267636,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_11_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,512,1],"quantization":{"scale":0.004750356487199372,"min":-0.650798838746314,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/depthwise_weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.008174965545242907,"min":0.3120670020580292,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.030133422215779623,"min":-2.41067377726237,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.006088157261119169,"min":-0.7853722866843729,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.003668997334498985,"min":3.9124486300013356e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,512,1024],"quantization":{"scale":0.010959514449624454,"min":-1.4028178495519301,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_pointwise/weights"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.10896045834410424,"min":-14.818622334798176,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_12_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,1024,1],"quantization":{"scale":0.004633033509347953,"min":-0.5652300881404502,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/depthwise_weights"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.022285057224479377,"min":0.23505790531635284,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/gamma"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.0324854850769043,"min":-3.9957146644592285,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/beta"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.014760061806323482,"min":-2.125448900110581,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/moving_mean"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.0036057423142825855,"min":3.9067056828997994e-36,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_depthwise/BatchNorm/moving_variance"},{"dtype":"float32","shape":[1,1,1024,1024],"quantization":{"scale":0.017311988157384536,"min":-2.094750567043529,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_pointwise/weights"},{"dtype":"float32","shape":[1024],"quantization":{"scale":0.16447528764313343,"min":-25.658144872328815,"dtype":"uint8"},"name":"MobilenetV1/Conv2d_13_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,1024,256],"quantization":{"scale":0.0026493051472832175,"min":-0.36825341547236723,"dtype":"uint8"},"name":"Prediction/Conv2d_0_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.012474596734140433,"min":-2.3078003958159803,"dtype":"uint8"},"name":"Prediction/Conv2d_0_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,256,512],"quantization":{"scale":0.014533351449405445,"min":-1.8166689311756807,"dtype":"uint8"},"name":"Prediction/Conv2d_1_pointwise/weights"},{"dtype":"float32","shape":[512],"quantization":{"scale":0.024268776762719248,"min":-2.4754152297973633,"dtype":"uint8"},"name":"Prediction/Conv2d_1_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,512,128],"quantization":{"scale":0.002208403746287028,"min":-0.28709248701731366,"dtype":"uint8"},"name":"Prediction/Conv2d_2_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.012451349052728392,"min":-1.5937726787492341,"dtype":"uint8"},"name":"Prediction/Conv2d_2_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,256],"quantization":{"scale":0.026334229637594783,"min":-2.8967652601354263,"dtype":"uint8"},"name":"Prediction/Conv2d_3_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.02509917792151956,"min":-1.4055539636050953,"dtype":"uint8"},"name":"Prediction/Conv2d_3_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,256,128],"quantization":{"scale":0.004565340046789132,"min":-0.3971845840706545,"dtype":"uint8"},"name":"Prediction/Conv2d_4_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.017302456556581983,"min":-2.5953684834872974,"dtype":"uint8"},"name":"Prediction/Conv2d_4_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,128,256],"quantization":{"scale":0.025347338470758176,"min":-3.8527954475552426,"dtype":"uint8"},"name":"Prediction/Conv2d_5_pointwise/weights"},{"dtype":"float32","shape":[256],"quantization":{"scale":0.033134659598855414,"min":-2.9158500446992766,"dtype":"uint8"},"name":"Prediction/Conv2d_5_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[1,1,256,64],"quantization":{"scale":0.002493104397081861,"min":-0.2817207968702503,"dtype":"uint8"},"name":"Prediction/Conv2d_6_pointwise/weights"},{"dtype":"float32","shape":[64],"quantization":{"scale":0.011383360974928912,"min":-1.2749364291920382,"dtype":"uint8"},"name":"Prediction/Conv2d_6_pointwise/convolution_bn_offset"},{"dtype":"float32","shape":[3,3,64,128],"quantization":{"scale":0.020821522731407017,"min":-2.7484410005457263,"dtype":"uint8"},"name":"Prediction/Conv2d_7_pointwise/weights"},{"dtype":"float32","shape":[128],"quantization":{"scale":0.052144218893612135,"min":-3.5979511036592373,"dtype":"uint8"},"name":"Prediction/Conv2d_7_pointwise/convolution_bn_offset"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":6,"dtype":"uint8"},"name":"Prediction/BoxPredictor_5/stack_1/1"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":1,"dtype":"uint8"},"name":"concat_1/axis"},{"dtype":"int32","shape":[1],"quantization":{"scale":1,"min":0,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/strided_slice/stack"},{"dtype":"int32","shape":[1],"quantization":{"scale":1,"min":1,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/strided_slice/stack_1"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":5118,"dtype":"uint8"},"name":"Postprocessor/stack/1"},{"dtype":"int32","shape":[],"quantization":{"scale":1,"min":4,"dtype":"uint8"},"name":"Prediction/BoxPredictor_0/stack/3"},{"dtype":"float32","shape":[1, 5118, 4],"name":"Output/extra_dim"}]}]
--------------------------------------------------------------------------------
/faceapi/models/tiny_face_detector_model-shard1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toxtli/lightweight-webcam-javascript-face-detection/a5e2862dc839897f39308b8f72c1c4897ce3d427/faceapi/models/tiny_face_detector_model-shard1
--------------------------------------------------------------------------------
/faceapi/models/tiny_face_detector_model-weights_manifest.json:
--------------------------------------------------------------------------------
1 | [{"weights":[{"name":"conv0/filters","shape":[3,3,3,16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009007044399485869,"min":-1.2069439495311063}},{"name":"conv0/bias","shape":[16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005263455241334205,"min":-0.9211046672334858}},{"name":"conv1/depthwise_filter","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004001977630690033,"min":-0.5042491814669441}},{"name":"conv1/pointwise_filter","shape":[1,1,16,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013836609615999109,"min":-1.411334180831909}},{"name":"conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0015159862590771096,"min":-0.30926119685173037}},{"name":"conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002666276225856706,"min":-0.317286870876948}},{"name":"conv2/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015265831292844286,"min":-1.6792414422128714}},{"name":"conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0020280554598453,"min":-0.37113414915168985}},{"name":"conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006100742489683862,"min":-0.8907084034938438}},{"name":"conv3/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016276211832083907,"min":-2.0508026908425725}},{"name":"conv3/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003394414279975143,"min":-0.7637432129944072}},{"name":"conv4/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006716050119961009,"min":-0.8059260143953211}},{"name":"conv4/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021875603993733724,"min":-2.8875797271728514}},{"name":"conv4/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0041141652009066415,"min":-0.8187188749804216}},{"name":"conv5/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008423839597141042,"min":-0.9013508368940915}},{"name":"conv5/pointwise_filter","shape":[1,1,256,512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.030007277283014035,"min":-3.8709387695088107}},{"name":"conv5/bias","shape":[512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008402082966823203,"min":-1.4871686851277068}},{"name":"conv8/filters","shape":[1,1,512,25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.028336129469030042,"min":-4.675461362389957}},{"name":"conv8/bias","shape":[25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002268134028303857,"min":-0.41053225912299807}}],"paths":["tiny_face_detector_model-shard1"]}]
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
--------------------------------------------------------------------------------
/opencvjs/index.css:
--------------------------------------------------------------------------------
1 | canvas {
2 | border: 1px solid black;
3 | }
4 | .invisible {
5 | display: none;
6 | }
7 | .text-center {
8 | text-align: center;
9 | }
10 | div {
11 | margin: 10px;
12 | }
13 | .center-block {
14 | display: block;
15 | margin: auto;
16 | }
17 | label {
18 | padding-right: 10px;
19 | width: 25%;
20 | vertical-align: top;
21 | font: 16px 'Lucida Grande', sans-serif;
22 | }
--------------------------------------------------------------------------------
/opencvjs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/opencvjs/index.js:
--------------------------------------------------------------------------------
1 | let videoWidth, videoHeight;
2 |
3 | // whether streaming video from the camera.
4 | let streaming = false;
5 |
6 | let video = document.getElementById('video');
7 | let canvasOutput = document.getElementById('canvasOutput');
8 | let canvasOutputCtx = canvasOutput.getContext('2d');
9 | let stream = null;
10 |
11 | let detectFace = document.getElementById('face');
12 | let detectEye = document.getElementById('eye');
13 |
14 | function startCamera() {
15 | if (streaming) return;
16 | navigator.mediaDevices.getUserMedia({video: true, audio: false})
17 | .then(function(s) {
18 | stream = s;
19 | video.srcObject = s;
20 | video.play();
21 | })
22 | .catch(function(err) {
23 | console.log("An error occured! " + err);
24 | });
25 |
26 | video.addEventListener("canplay", function(ev){
27 | if (!streaming) {
28 | videoWidth = video.videoWidth;
29 | videoHeight = video.videoHeight;
30 | video.setAttribute("width", videoWidth);
31 | video.setAttribute("height", videoHeight);
32 | canvasOutput.width = videoWidth;
33 | canvasOutput.height = videoHeight;
34 | streaming = true;
35 | }
36 | startVideoProcessing();
37 | }, false);
38 | }
39 |
40 | let faceClassifier = null;
41 | let eyeClassifier = null;
42 |
43 | let src = null;
44 | let dstC1 = null;
45 | let dstC3 = null;
46 | let dstC4 = null;
47 |
48 | let canvasInput = null;
49 | let canvasInputCtx = null;
50 |
51 | let canvasBuffer = null;
52 | let canvasBufferCtx = null;
53 |
54 | function startVideoProcessing() {
55 | if (!streaming) { console.warn("Please startup your webcam"); return; }
56 | stopVideoProcessing();
57 | canvasInput = document.createElement('canvas');
58 | canvasInput.width = videoWidth;
59 | canvasInput.height = videoHeight;
60 | canvasInputCtx = canvasInput.getContext('2d');
61 |
62 | canvasBuffer = document.createElement('canvas');
63 | canvasBuffer.width = videoWidth;
64 | canvasBuffer.height = videoHeight;
65 | canvasBufferCtx = canvasBuffer.getContext('2d');
66 |
67 | srcMat = new cv.Mat(videoHeight, videoWidth, cv.CV_8UC4);
68 | grayMat = new cv.Mat(videoHeight, videoWidth, cv.CV_8UC1);
69 |
70 | faceClassifier = new cv.CascadeClassifier();
71 | faceClassifier.load('haarcascade_frontalface_default.xml');
72 |
73 | eyeClassifier = new cv.CascadeClassifier();
74 | eyeClassifier.load('haarcascade_eye.xml');
75 |
76 | requestAnimationFrame(processVideo);
77 | }
78 |
79 | function processVideo() {
80 | stats.begin();
81 | canvasInputCtx.drawImage(video, 0, 0, videoWidth, videoHeight);
82 | let imageData = canvasInputCtx.getImageData(0, 0, videoWidth, videoHeight);
83 | srcMat.data.set(imageData.data);
84 | cv.cvtColor(srcMat, grayMat, cv.COLOR_RGBA2GRAY);
85 | let faces = [];
86 | let eyes = [];
87 | let size;
88 | if (detectFace.checked) {
89 | let faceVect = new cv.RectVector();
90 | let faceMat = new cv.Mat();
91 | if (detectEye.checked) {
92 | cv.pyrDown(grayMat, faceMat);
93 | size = faceMat.size();
94 | } else {
95 | cv.pyrDown(grayMat, faceMat);
96 | cv.pyrDown(faceMat, faceMat);
97 | size = faceMat.size();
98 | }
99 | faceClassifier.detectMultiScale(faceMat, faceVect);
100 | for (let i = 0; i < faceVect.size(); i++) {
101 | let face = faceVect.get(i);
102 | faces.push(new cv.Rect(face.x, face.y, face.width, face.height));
103 | if (detectEye.checked) {
104 | let eyeVect = new cv.RectVector();
105 | let eyeMat = faceMat.getRoiRect(face);
106 | eyeClassifier.detectMultiScale(eyeMat, eyeVect);
107 | for (let i = 0; i < eyeVect.size(); i++) {
108 | let eye = eyeVect.get(i);
109 | eyes.push(new cv.Rect(face.x + eye.x, face.y + eye.y, eye.width, eye.height));
110 | }
111 | eyeMat.delete();
112 | eyeVect.delete();
113 | }
114 | }
115 | faceMat.delete();
116 | faceVect.delete();
117 | } else {
118 | if (detectEye.checked) {
119 | let eyeVect = new cv.RectVector();
120 | let eyeMat = new cv.Mat();
121 | cv.pyrDown(grayMat, eyeMat);
122 | size = eyeMat.size();
123 | eyeClassifier.detectMultiScale(eyeMat, eyeVect);
124 | for (let i = 0; i < eyeVect.size(); i++) {
125 | let eye = eyeVect.get(i);
126 | eyes.push(new cv.Rect(eye.x, eye.y, eye.width, eye.height));
127 | }
128 | eyeMat.delete();
129 | eyeVect.delete();
130 | }
131 | }
132 | canvasOutputCtx.drawImage(canvasInput, 0, 0, videoWidth, videoHeight);
133 | drawResults(canvasOutputCtx, faces, 'red', size);
134 | drawResults(canvasOutputCtx, eyes, 'yellow', size);
135 | stats.end();
136 | requestAnimationFrame(processVideo);
137 | }
138 |
139 | function drawResults(ctx, results, color, size) {
140 | for (let i = 0; i < results.length; ++i) {
141 | let rect = results[i];
142 | let xRatio = videoWidth/size.width;
143 | let yRatio = videoHeight/size.height;
144 | ctx.lineWidth = 3;
145 | ctx.strokeStyle = color;
146 | ctx.strokeRect(rect.x*xRatio, rect.y*yRatio, rect.width*xRatio, rect.height*yRatio);
147 | }
148 | }
149 |
150 | function stopVideoProcessing() {
151 | if (src != null && !src.isDeleted()) src.delete();
152 | if (dstC1 != null && !dstC1.isDeleted()) dstC1.delete();
153 | if (dstC3 != null && !dstC3.isDeleted()) dstC3.delete();
154 | if (dstC4 != null && !dstC4.isDeleted()) dstC4.delete();
155 | }
156 |
157 | function stopCamera() {
158 | if (!streaming) return;
159 | stopVideoProcessing();
160 | document.getElementById("canvasOutput").getContext("2d").clearRect(0, 0, width, height);
161 | video.pause();
162 | video.srcObject=null;
163 | stream.getVideoTracks()[0].stop();
164 | streaming = false;
165 | }
166 |
167 | function initUI() {
168 | stats = new Stats();
169 | stats.showPanel(0);
170 | document.getElementById('container').appendChild(stats.dom);
171 | }
172 |
173 | function opencvIsReady() {
174 | console.log('OpenCV.js is ready');
175 | initUI();
176 | startCamera();
177 | }
--------------------------------------------------------------------------------
/pico/index.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Face detection
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/pico/js/camvas.js:
--------------------------------------------------------------------------------
1 | /*
2 | The code here was taken from https://github.com/cbrandolino/camvas and modified to suit the needs of our project
3 | */
4 | /*
5 | Copyright (c) 2012 Claudio Brandolino
6 |
7 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 |
9 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 |
11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 | */
13 | // The function takes a canvas context and a `drawFunc` function.
14 | // `drawFunc` receives two parameters, the video and the time since
15 | // the last time it was called.
16 | function camvas(ctx, callback) {
17 | var self = this
18 | this.ctx = ctx
19 | this.callback = callback
20 |
21 | // We can't `new Video()` yet, so we'll resort to the vintage
22 | // "hidden div" hack for dynamic loading.
23 | var streamContainer = document.createElement('div')
24 | this.video = document.createElement('video')
25 |
26 | // If we don't do this, the stream will not be played.
27 | // By the way, the play and pause controls work as usual
28 | // for streamed videos.
29 | this.video.setAttribute('autoplay', '1')
30 | this.video.setAttribute('playsinline', '1')
31 |
32 | // The video should fill out all of the canvas
33 | this.video.setAttribute('width', 1)
34 | this.video.setAttribute('height', 1)
35 |
36 | streamContainer.appendChild(this.video)
37 | document.body.appendChild(streamContainer)
38 |
39 | // The callback happens when we are starting to stream the video.
40 | navigator.mediaDevices.getUserMedia({video: true, audio: false}).then(function(stream) {
41 | // Yay, now our webcam input is treated as a normal video and
42 | // we can start having fun
43 | self.video.srcObject = stream
44 | // Let's start drawing the canvas!
45 | self.update()
46 | }, function(err) {
47 | throw err
48 | })
49 |
50 | // As soon as we can draw a new frame on the canvas, we call the `draw` function
51 | // we passed as a parameter.
52 | this.update = function() {
53 | var self = this
54 | var last = Date.now()
55 | var loop = function() {
56 | // For some effects, you might want to know how much time is passed
57 | // since the last frame; that's why we pass along a Delta time `dt`
58 | // variable (expressed in milliseconds)
59 | var dt = Date.now - last
60 | self.callback(self.video, dt)
61 | last = Date.now()
62 | requestAnimationFrame(loop)
63 | }
64 | requestAnimationFrame(loop)
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/pico/js/index.js:
--------------------------------------------------------------------------------
1 | var initialized = false;
2 |
3 | function button_callback() {
4 | /*
5 | (0) check whether we're already running face detection
6 | */
7 | if(initialized)
8 | return; // if yes, then do not initialize everything again
9 | /*
10 | (1) prepare the pico.js face detector
11 | */
12 | var update_memory = pico.instantiate_detection_memory(5); // we will use the detecions of the last 5 frames
13 | var facefinder_classify_region = function(r, c, s, pixels, ldim) {return -1.0;};
14 | var cascadeurl = 'https://raw.githubusercontent.com/nenadmarkus/pico/c2e81f9d23cc11d1a612fd21e4f9de0921a5d0d9/rnt/cascades/facefinder';
15 | fetch(cascadeurl).then(function(response) {
16 | response.arrayBuffer().then(function(buffer) {
17 | var bytes = new Int8Array(buffer);
18 | facefinder_classify_region = pico.unpack_cascade(bytes);
19 | console.log('* cascade loaded');
20 | })
21 | })
22 | /*
23 | (2) get the drawing context on the canvas and define a function to transform an RGBA image to grayscale
24 | */
25 | var ctx = document.getElementsByTagName('canvas')[0].getContext('2d');
26 | function rgba_to_grayscale(rgba, nrows, ncols) {
27 | var gray = new Uint8Array(nrows*ncols);
28 | for(var r=0; r50.0)
66 | {
67 | ctx.beginPath();
68 | ctx.arc(dets[i][1], dets[i][0], dets[i][2]/2, 0, 2*Math.PI, false);
69 | ctx.lineWidth = 3;
70 | ctx.strokeStyle = 'red';
71 | ctx.stroke();
72 | }
73 | }
74 | /*
75 | (4) instantiate camera handling (see https://github.com/cbrandolino/camvas)
76 | */
77 | var mycamvas = new camvas(ctx, processfn);
78 | /*
79 | (5) it seems that everything went well
80 | */
81 | initialized = true;
82 |
83 | }
84 | setTimeout(button_callback,1000);
--------------------------------------------------------------------------------
/pico/js/pico.js:
--------------------------------------------------------------------------------
1 | /* This library is released under the MIT license, see https://github.com/tehnokv/picojs */
2 | pico = {}
3 |
4 | pico.unpack_cascade = function(bytes)
5 | {
6 | //
7 | const dview = new DataView(new ArrayBuffer(4));
8 | /*
9 | we skip the first 8 bytes of the cascade file
10 | (cascade version number and some data used during the learning process)
11 | */
12 | let p = 8;
13 | /*
14 | read the depth (size) of each tree first: a 32-bit signed integer
15 | */
16 | dview.setUint8(0, bytes[p+0]), dview.setUint8(1, bytes[p+1]), dview.setUint8(2, bytes[p+2]), dview.setUint8(3, bytes[p+3]);
17 | const tdepth = dview.getInt32(0, true);
18 | p = p + 4
19 | /*
20 | next, read the number of trees in the cascade: another 32-bit signed integer
21 | */
22 | dview.setUint8(0, bytes[p+0]), dview.setUint8(1, bytes[p+1]), dview.setUint8(2, bytes[p+2]), dview.setUint8(3, bytes[p+3]);
23 | const ntrees = dview.getInt32(0, true);
24 | p = p + 4
25 | /*
26 | read the actual trees and cascade thresholds
27 | */
28 | const tcodes_ls = [];
29 | const tpreds_ls = [];
30 | const thresh_ls = [];
31 | for(let t=0; t> 0; // '>>0' transforms this number to int
62 |
63 | for(let i=0; i> 8' here to perform an integer division: this seems important for performance
68 | idx = 2*idx + (pixels[((r+tcodes[root + 4*idx + 0]*s) >> 8)*ldim+((c+tcodes[root + 4*idx + 1]*s) >> 8)]<=pixels[((r+tcodes[root + 4*idx + 2]*s) >> 8)*ldim+((c+tcodes[root + 4*idx + 3]*s) >> 8)]);
69 |
70 | o = o + tpreds[pow2tdepth*i + idx-pow2tdepth];
71 |
72 | if(o<=thresh[i])
73 | return -1;
74 |
75 | root += 4*pow2tdepth;
76 | }
77 | return o - thresh[ntrees-1];
78 | }
79 | /*
80 | we're done
81 | */
82 | return classify_region;
83 | }
84 |
85 | pico.run_cascade = function(image, classify_region, params)
86 | {
87 | const pixels = image.pixels;
88 | const nrows = image.nrows;
89 | const ncols = image.ncols;
90 | const ldim = image.ldim;
91 |
92 | const shiftfactor = params.shiftfactor;
93 | const minsize = params.minsize;
94 | const maxsize = params.maxsize;
95 | const scalefactor = params.scalefactor;
96 |
97 | let scale = minsize;
98 | const detections = [];
99 |
100 | while(scale<=maxsize)
101 | {
102 | const step = Math.max(shiftfactor*scale, 1) >> 0; // '>>0' transforms this number to int
103 | const offset = (scale/2 + 1) >> 0;
104 |
105 | for(let r=offset; r<=nrows-offset; r+=step)
106 | for(let c=offset; c<=ncols-offset; c+=step)
107 | {
108 | const q = classify_region(r, c, scale, pixels, ldim);
109 | if (q > 0.0)
110 | detections.push([r, c, scale, q]);
111 | }
112 |
113 | scale = scale*scalefactor;
114 | }
115 |
116 | return detections;
117 | }
118 |
119 | pico.cluster_detections = function(dets, iouthreshold)
120 | {
121 | /*
122 | sort detections by their score
123 | */
124 | dets = dets.sort(function(a, b) {
125 | return b[3] - a[3];
126 | });
127 | /*
128 | this helper function calculates the intersection over union for two detections
129 | */
130 | function calculate_iou(det1, det2)
131 | {
132 | // unpack the position and size of each detection
133 | const r1=det1[0], c1=det1[1], s1=det1[2];
134 | const r2=det2[0], c2=det2[1], s2=det2[2];
135 | // calculate detection overlap in each dimension
136 | const overr = Math.max(0, Math.min(r1+s1/2, r2+s2/2) - Math.max(r1-s1/2, r2-s2/2));
137 | const overc = Math.max(0, Math.min(c1+s1/2, c2+s2/2) - Math.max(c1-s1/2, c2-s2/2));
138 | // calculate and return IoU
139 | return overr*overc/(s1*s1+s2*s2-overr*overc);
140 | }
141 | /*
142 | do clustering through non-maximum suppression
143 | */
144 | const assignments = new Array(dets.length).fill(0);
145 | const clusters = [];
146 | for(let i=0; iiouthreshold)
156 | {
157 | assignments[j] = 1;
158 | r = r + dets[j][0];
159 | c = c + dets[j][1];
160 | s = s + dets[j][2];
161 | q = q + dets[j][3];
162 | n = n + 1;
163 | }
164 | // make a cluster representative
165 | clusters.push([r/n, c/n, s/n, q]);
166 | }
167 | }
168 |
169 | return clusters;
170 | }
171 |
172 | pico.instantiate_detection_memory = function(size)
173 | {
174 | /*
175 | initialize a circular buffer of `size` elements
176 | */
177 | let n = 0;
178 | const memory = [];
179 | for(let i=0; i