Showing
2 changed files
with
209 additions
and
37 deletions
flask/static/js/utils.js
0 → 100644
1 | +function Utils(errorOutputId) { // eslint-disable-line no-unused-vars | ||
2 | + let self = this; | ||
3 | + this.errorOutput = document.getElementById(errorOutputId); | ||
4 | + | ||
5 | + const OPENCV_URL = 'opencv.js'; | ||
6 | + this.loadOpenCv = function(onloadCallback) { | ||
7 | + let script = document.createElement('script'); | ||
8 | + script.setAttribute('async', ''); | ||
9 | + script.setAttribute('type', 'text/javascript'); | ||
10 | + script.addEventListener('load', () => { | ||
11 | + if (cv.getBuildInformation) | ||
12 | + { | ||
13 | + console.log(cv.getBuildInformation()); | ||
14 | + onloadCallback(); | ||
15 | + } | ||
16 | + else | ||
17 | + { | ||
18 | + // WASM | ||
19 | + cv['onRuntimeInitialized']=()=>{ | ||
20 | + console.log(cv.getBuildInformation()); | ||
21 | + onloadCallback(); | ||
22 | + } | ||
23 | + } | ||
24 | + }); | ||
25 | + script.addEventListener('error', () => { | ||
26 | + self.printError('Failed to load ' + OPENCV_URL); | ||
27 | + }); | ||
28 | + script.src = OPENCV_URL; | ||
29 | + let node = document.getElementsByTagName('script')[0]; | ||
30 | + node.parentNode.insertBefore(script, node); | ||
31 | + }; | ||
32 | + | ||
33 | + this.createFileFromUrl = function(path, url, callback) { | ||
34 | + let request = new XMLHttpRequest(); | ||
35 | + request.open('GET', url, true); | ||
36 | + request.responseType = 'arraybuffer'; | ||
37 | + request.onload = function(ev) { | ||
38 | + if (request.readyState === 4) { | ||
39 | + if (request.status === 200) { | ||
40 | + let data = new Uint8Array(request.response); | ||
41 | + cv.FS_createDataFile('/', path, data, true, false, false); | ||
42 | + callback(); | ||
43 | + } else { | ||
44 | + self.printError('Failed to load ' + url + ' status: ' + request.status); | ||
45 | + } | ||
46 | + } | ||
47 | + }; | ||
48 | + request.send(); | ||
49 | + }; | ||
50 | + | ||
51 | + this.loadImageToCanvas = function(url, cavansId) { | ||
52 | + let canvas = document.getElementById(cavansId); | ||
53 | + let ctx = canvas.getContext('2d'); | ||
54 | + let img = new Image(); | ||
55 | + img.crossOrigin = 'anonymous'; | ||
56 | + img.onload = function() { | ||
57 | + canvas.width = img.width; | ||
58 | + canvas.height = img.height; | ||
59 | + ctx.drawImage(img, 0, 0, img.width, img.height); | ||
60 | + }; | ||
61 | + img.src = url; | ||
62 | + }; | ||
63 | + | ||
64 | + this.executeCode = function(textAreaId) { | ||
65 | + try { | ||
66 | + this.clearError(); | ||
67 | + let code = document.getElementById(textAreaId).value; | ||
68 | + eval(code); | ||
69 | + } catch (err) { | ||
70 | + this.printError(err); | ||
71 | + } | ||
72 | + }; | ||
73 | + | ||
74 | + this.clearError = function() { | ||
75 | + this.errorOutput.innerHTML = ''; | ||
76 | + }; | ||
77 | + | ||
78 | + this.printError = function(err) { | ||
79 | + if (typeof err === 'undefined') { | ||
80 | + err = ''; | ||
81 | + } else if (typeof err === 'number') { | ||
82 | + if (!isNaN(err)) { | ||
83 | + if (typeof cv !== 'undefined') { | ||
84 | + err = 'Exception: ' + cv.exceptionFromPtr(err).msg; | ||
85 | + } | ||
86 | + } | ||
87 | + } else if (typeof err === 'string') { | ||
88 | + let ptr = Number(err.split(' ')[0]); | ||
89 | + if (!isNaN(ptr)) { | ||
90 | + if (typeof cv !== 'undefined') { | ||
91 | + err = 'Exception: ' + cv.exceptionFromPtr(ptr).msg; | ||
92 | + } | ||
93 | + } | ||
94 | + } else if (err instanceof Error) { | ||
95 | + err = err.stack.replace(/\n/g, '<br>'); | ||
96 | + } | ||
97 | + this.errorOutput.innerHTML = err; | ||
98 | + }; | ||
99 | + | ||
100 | + this.loadCode = function(scriptId, textAreaId) { | ||
101 | + let scriptNode = document.getElementById(scriptId); | ||
102 | + let textArea = document.getElementById(textAreaId); | ||
103 | + if (scriptNode.type !== 'text/code-snippet') { | ||
104 | + throw Error('Unknown code snippet type'); | ||
105 | + } | ||
106 | + textArea.value = scriptNode.text.replace(/^\n/, ''); | ||
107 | + }; | ||
108 | + | ||
109 | + this.addFileInputHandler = function(fileInputId, canvasId) { | ||
110 | + let inputElement = document.getElementById(fileInputId); | ||
111 | + inputElement.addEventListener('change', (e) => { | ||
112 | + let files = e.target.files; | ||
113 | + if (files.length > 0) { | ||
114 | + let imgUrl = URL.createObjectURL(files[0]); | ||
115 | + self.loadImageToCanvas(imgUrl, canvasId); | ||
116 | + } | ||
117 | + }, false); | ||
118 | + }; | ||
119 | + | ||
120 | + function onVideoCanPlay() { | ||
121 | + if (self.onCameraStartedCallback) { | ||
122 | + self.onCameraStartedCallback(self.stream, self.video); | ||
123 | + } | ||
124 | + }; | ||
125 | + | ||
126 | + this.startCamera = function(resolution, callback, videoId) { | ||
127 | + const constraints = { | ||
128 | + 'qvga': {width: {exact: 320}, height: {exact: 240}}, | ||
129 | + 'vga': {width: {exact: 640}, height: {exact: 480}}}; | ||
130 | + let video = document.getElementById(videoId); | ||
131 | + if (!video) { | ||
132 | + video = document.createElement('video'); | ||
133 | + } | ||
134 | + | ||
135 | + let videoConstraint = constraints[resolution]; | ||
136 | + if (!videoConstraint) { | ||
137 | + videoConstraint = true; | ||
138 | + } | ||
139 | + | ||
140 | + navigator.mediaDevices.getUserMedia({video: videoConstraint, audio: false}) | ||
141 | + .then(function(stream) { | ||
142 | + video.srcObject = stream; | ||
143 | + video.play(); | ||
144 | + self.video = video; | ||
145 | + self.stream = stream; | ||
146 | + self.onCameraStartedCallback = callback; | ||
147 | + video.addEventListener('canplay', onVideoCanPlay, false); | ||
148 | + }) | ||
149 | + .catch(function(err) { | ||
150 | + self.printError('Camera Error: ' + err.name + ' ' + err.message); | ||
151 | + }); | ||
152 | + }; | ||
153 | + | ||
154 | + this.stopCamera = function() { | ||
155 | + if (this.video) { | ||
156 | + this.video.pause(); | ||
157 | + this.video.srcObject = null; | ||
158 | + this.video.removeEventListener('canplay', onVideoCanPlay); | ||
159 | + } | ||
160 | + if (this.stream) { | ||
161 | + this.stream.getVideoTracks()[0].stop(); | ||
162 | + } | ||
163 | + }; | ||
164 | +}; | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
... | @@ -8,31 +8,29 @@ | ... | @@ -8,31 +8,29 @@ |
8 | #container { | 8 | #container { |
9 | margin: 0px auto; | 9 | margin: 0px auto; |
10 | width: 640px; | 10 | width: 640px; |
11 | - height: 480px; | 11 | + height: 960px; |
12 | border: 10px #333 solid; | 12 | border: 10px #333 solid; |
13 | } | 13 | } |
14 | -#videoElement { | 14 | +#videoInput { |
15 | + width: 640px; | ||
16 | + height: 480px; | ||
17 | + background-color: #666; | ||
18 | +} | ||
19 | +#canvasOutput { | ||
15 | width: 640px; | 20 | width: 640px; |
16 | height: 480px; | 21 | height: 480px; |
17 | background-color: #666; | 22 | background-color: #666; |
18 | } | 23 | } |
19 | - | ||
20 | - | ||
21 | </style> | 24 | </style> |
22 | -</head> | ||
23 | - | ||
24 | -<body> | ||
25 | -<div id="container"> | ||
26 | - <video autoplay="true" id="videoElement"> <!-- style="visibility: hidden"--> | ||
27 | - | ||
28 | - </video> | ||
29 | - <canvas id='canvasOutput' width='640' height='480'> | ||
30 | - | ||
31 | - </canvas> | ||
32 | -</div> | ||
33 | <script type='text/javascript' src="{{url_for('static', filename='js/opencv.js')}}"></script> | 25 | <script type='text/javascript' src="{{url_for('static', filename='js/opencv.js')}}"></script> |
26 | +<script type='text/javascript' src="{{url_for('static', filename='js/utils.js')}}"></script> | ||
34 | <script type='text/javascript'> | 27 | <script type='text/javascript'> |
35 | -var video = document.querySelector("#videoElement"); | 28 | +function main() |
29 | +{ | ||
30 | +let video = document.getElementById("videoInput"); | ||
31 | +let canvasOutput = document.getElementById('canvasOutput'); | ||
32 | +let canvasContext = canvasOutput.getContext('2d'); | ||
33 | + | ||
36 | if (navigator.mediaDevices.getUserMedia){ | 34 | if (navigator.mediaDevices.getUserMedia){ |
37 | navigator.mediaDevices.getUserMedia({ video: true }) | 35 | navigator.mediaDevices.getUserMedia({ video: true }) |
38 | .then(function (stream) { | 36 | .then(function (stream) { |
... | @@ -41,24 +39,22 @@ if (navigator.mediaDevices.getUserMedia){ | ... | @@ -41,24 +39,22 @@ if (navigator.mediaDevices.getUserMedia){ |
41 | console.log("Something went wrong!"); | 39 | console.log("Something went wrong!"); |
42 | }); | 40 | }); |
43 | } | 41 | } |
44 | -</script> | 42 | +let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); |
45 | -<script> | 43 | +let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4); |
46 | -cv['onRuntimeInitialized']=()=>{ | 44 | +let gray = new cv.Mat(); |
47 | - let video = document.getElementById('videoElement'); | 45 | +let cap = new cv.VideoCapture(video); |
48 | - let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); | 46 | +let faces = new cv.RectVector(); |
49 | - let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4); | 47 | +let classifier = new cv.CascadeClassifier(); |
50 | - let gray = new cv.Mat(); | 48 | +var streaming = true; |
51 | - let cap = new cv.VideoCapture(video); | 49 | + |
52 | - let faces = new cv.RectVector(); | 50 | +let utils = new Utils('errorMessage'); //use utils class |
53 | - let classifier = new cv.CascadeClassifier(); | 51 | +let faceCascadeFile = "/static/js/haarcascade_frontalface_default.xml" |
54 | - var streaming = true; | 52 | +utils.createFileFromUrl(faceCascadeFile, faceCascadeFile, () => { |
55 | - if (typeof streaming === 'undefined') | 53 | + alert(faceCascadeFile); |
56 | - { | 54 | + classifier.load(faceCascadeFile); |
57 | - streaming = false; | 55 | +}); |
58 | - } | 56 | +const FPS = 30; |
59 | - classifier.load("{{url_for('static', filename='js/haarcascade_frontalface_default.xml')}}") | 57 | +function processVideo() { |
60 | - const FPS = 30; | ||
61 | - function processVideo() { | ||
62 | try { | 58 | try { |
63 | if (!streaming) { | 59 | if (!streaming) { |
64 | // clean and stop. | 60 | // clean and stop. |
... | @@ -74,8 +70,10 @@ cv['onRuntimeInitialized']=()=>{ | ... | @@ -74,8 +70,10 @@ cv['onRuntimeInitialized']=()=>{ |
74 | cap.read(src); | 70 | cap.read(src); |
75 | src.copyTo(dst); | 71 | src.copyTo(dst); |
76 | cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); | 72 | cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); |
73 | + alert('d'); | ||
77 | // detect faces. | 74 | // detect faces. |
78 | classifier.detectMultiScale(gray, faces, 1.1, 3, 0); | 75 | classifier.detectMultiScale(gray, faces, 1.1, 3, 0); |
76 | + alert('e'); | ||
79 | // draw faces. | 77 | // draw faces. |
80 | for (let i = 0; i < faces.size(); ++i) { | 78 | for (let i = 0; i < faces.size(); ++i) { |
81 | let face = faces.get(i); | 79 | let face = faces.get(i); |
... | @@ -83,6 +81,7 @@ cv['onRuntimeInitialized']=()=>{ | ... | @@ -83,6 +81,7 @@ cv['onRuntimeInitialized']=()=>{ |
83 | let point2 = new cv.Point(face.x + face.width, face.y + face.height); | 81 | let point2 = new cv.Point(face.x + face.width, face.y + face.height); |
84 | cv.rectangle(dst, point1, point2, [255, 0, 0, 255]); | 82 | cv.rectangle(dst, point1, point2, [255, 0, 0, 255]); |
85 | } | 83 | } |
84 | + alert('f'); | ||
86 | cv.imshow('canvasOutput', dst); | 85 | cv.imshow('canvasOutput', dst); |
87 | // schedule the next one. | 86 | // schedule the next one. |
88 | let delay = 1000/FPS - (Date.now() - begin); | 87 | let delay = 1000/FPS - (Date.now() - begin); |
... | @@ -90,10 +89,19 @@ cv['onRuntimeInitialized']=()=>{ | ... | @@ -90,10 +89,19 @@ cv['onRuntimeInitialized']=()=>{ |
90 | } catch (err) { | 89 | } catch (err) { |
91 | console.log(err); | 90 | console.log(err); |
92 | } | 91 | } |
93 | - } | 92 | +} |
94 | - // schedule the first one. | 93 | +setTimeout(processVideo, 0); |
95 | - setTimeout(processVideo, 0); | ||
96 | } | 94 | } |
97 | </script> | 95 | </script> |
96 | +</head> | ||
97 | +<body onload="cv['onRuntimeInitialized']=()=>{ main() }"> | ||
98 | +<div id="container"> | ||
99 | +<video autoplay="true" id="videoInput" width=640 height=480> <!-- style="visibility: hidden"--> | ||
100 | + | ||
101 | +</video> | ||
102 | +<canvas id='canvasOutput' width=640 height=480> | ||
103 | + | ||
104 | +</canvas> | ||
105 | +</div> | ||
98 | </body> | 106 | </body> |
99 | </html> | 107 | </html> | ... | ... |
-
Please register or login to post a comment