Showing
2 changed files
with
300 additions
and
235 deletions
... | @@ -5,14 +5,14 @@ | ... | @@ -5,14 +5,14 @@ |
5 | <title>Web Attendance System</title> | 5 | <title>Web Attendance System</title> |
6 | <style> | 6 | <style> |
7 | #container { | 7 | #container { |
8 | - margin: 0px auto; | 8 | + margin: 0px auto; |
9 | - border: 10px #333 solid; | 9 | + border: 10px #333 solid; |
10 | } | 10 | } |
11 | #videoInput { | 11 | #videoInput { |
12 | - background-color: #666; | 12 | + background-color: #666; |
13 | } | 13 | } |
14 | #canvasOutput { | 14 | #canvasOutput { |
15 | - background-color: #666; | 15 | + background-color: #666; |
16 | } | 16 | } |
17 | </style> | 17 | </style> |
18 | <script type='text/javascript' src="{{url_for('static', filename='js/opencv.js')}}"></script> | 18 | <script type='text/javascript' src="{{url_for('static', filename='js/opencv.js')}}"></script> |
... | @@ -27,18 +27,18 @@ function init() | ... | @@ -27,18 +27,18 @@ function init() |
27 | let canvasOutput = document.getElementById("canvasOutput"); | 27 | let canvasOutput = document.getElementById("canvasOutput"); |
28 | if (navigator.mediaDevices.getUserMedia){ | 28 | if (navigator.mediaDevices.getUserMedia){ |
29 | navigator.mediaDevices.getUserMedia({ video: true }) | 29 | navigator.mediaDevices.getUserMedia({ video: true }) |
30 | - .then(function (stream) { | 30 | + .then(function (stream) { |
31 | video.srcObject = stream; | 31 | video.srcObject = stream; |
32 | - video.addEventListener('canplay', () => { | 32 | + video.addEventListener('canplay', () => { |
33 | - video.width = video.videoWidth; | 33 | + video.width = video.videoWidth; |
34 | - video.height = video.videoHeight; | 34 | + video.height = video.videoHeight; |
35 | - container.style.width = video.videoWidth + 'px'; | 35 | + container.style.width = video.videoWidth + 'px'; |
36 | - container.style.height = video.videoHeight + 'px'; | 36 | + container.style.height = video.videoHeight + 'px'; |
37 | - canvasOutput.width = video.videoWidth; | 37 | + canvasOutput.width = video.videoWidth; |
38 | - canvasOutput.height = video.videoHeight; | 38 | + canvasOutput.height = video.videoHeight; |
39 | - load_cascade(); | 39 | + load_cascade(); |
40 | - }); | 40 | + }); |
41 | - }).catch(function (err0r) { | 41 | + }).catch(function (err0r) { |
42 | console.log("Something went wrong!"); | 42 | console.log("Something went wrong!"); |
43 | streaming = false; | 43 | streaming = false; |
44 | }); | 44 | }); |
... | @@ -49,7 +49,7 @@ function load_cascade() | ... | @@ -49,7 +49,7 @@ function load_cascade() |
49 | { | 49 | { |
50 | let faceCascadeFile = 'haarcascade_frontalface_default.xml' | 50 | let faceCascadeFile = 'haarcascade_frontalface_default.xml' |
51 | let faceCascadeURL = 'static/js/haarcascade_frontalface_default.xml' | 51 | let faceCascadeURL = 'static/js/haarcascade_frontalface_default.xml' |
52 | - let utils = new Utils('errorMessage'); | 52 | + let utils = new Utils('errorMessage'); |
53 | utils.createFileFromUrl(faceCascadeFile, faceCascadeURL, () => { | 53 | utils.createFileFromUrl(faceCascadeFile, faceCascadeURL, () => { |
54 | main() | 54 | main() |
55 | }); | 55 | }); |
... | @@ -58,129 +58,128 @@ function load_cascade() | ... | @@ -58,129 +58,128 @@ function load_cascade() |
58 | 58 | ||
59 | function main() | 59 | function main() |
60 | { | 60 | { |
61 | -let video = document.getElementById("videoInput"); | 61 | + let video = document.getElementById("videoInput"); |
62 | -let canvasOutput = document.getElementById("canvasOutput"); | 62 | + let canvasOutput = document.getElementById("canvasOutput"); |
63 | -let canvasContext = canvasOutput.getContext('2d'); | 63 | + let canvasContext = canvasOutput.getContext('2d'); |
64 | -let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); | 64 | + let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); |
65 | -let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4); | 65 | + let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4); |
66 | -// let gray = new cv.Mat(); | 66 | + // let gray = new cv.Mat(); |
67 | -let cap = new cv.VideoCapture(video); | 67 | + let cap = new cv.VideoCapture(video); |
68 | -let faces = new cv.RectVector(); | 68 | + let faces = new cv.RectVector(); |
69 | -let classifier = new cv.CascadeClassifier(); | 69 | + let classifier = new cv.CascadeClassifier(); |
70 | -class Tracker{ | 70 | + class Tracker{ |
71 | - constructor(){ | 71 | + constructor(){ |
72 | - this.arr = new Array(); | 72 | + this.arr = new Array(); |
73 | - } | 73 | + } |
74 | - register = function(x, y, width, height) { | 74 | + register = function(x, y, width, height) { |
75 | - var x_center = (x + width) / 2; | 75 | + var x_center = (x + width) / 2; |
76 | - var y_center = (y + height) / 2; | 76 | + var y_center = (y + height) / 2; |
77 | - var now = Date.now() | 77 | + var now = Date.now() |
78 | - this.arr = this.arr.filter(ent => now - ent.time < 300); | 78 | + this.arr = this.arr.filter(ent => now - ent.time < 300); |
79 | - for (const prop in this.arr){ | 79 | + for (const prop in this.arr){ |
80 | - var prop_x_center = (this.arr[prop].x + this.arr[prop].width) / 2; | 80 | + var prop_x_center = (this.arr[prop].x + this.arr[prop].width) / 2; |
81 | - var prop_y_center = (this.arr[prop].y + this.arr[prop].height) / 2; | 81 | + var prop_y_center = (this.arr[prop].y + this.arr[prop].height) / 2; |
82 | - if (Math.abs(x_center - prop_x_center) < 10 && Math.abs(y_center - prop_y_center) < 10){ | 82 | + if (Math.abs(x_center - prop_x_center) < 10 && Math.abs(y_center - prop_y_center) < 10){ |
83 | - this.arr[prop].x = x; | 83 | + this.arr[prop].x = x; |
84 | - this.arr[prop].y = y; | 84 | + this.arr[prop].y = y; |
85 | - this.arr[prop].width = width; | 85 | + this.arr[prop].width = width; |
86 | - this.arr[prop].height = height; | 86 | + this.arr[prop].height = height; |
87 | - this.arr[prop].time = now; | 87 | + this.arr[prop].time = now; |
88 | - return false; | 88 | + return false; |
89 | - } | 89 | + } |
90 | - } | 90 | + } |
91 | - var ent = {x: x, y: y, width: width, height: height, time: now} | 91 | + var ent = {x: x, y: y, width: width, height: height, time: now} |
92 | - this.arr.push(ent) | 92 | + this.arr.push(ent) |
93 | - return true; | 93 | + return true; |
94 | - } | 94 | + } |
95 | -}; | 95 | + }; |
96 | -var tracker = new Tracker(); | 96 | + var tracker = new Tracker(); |
97 | -var streaming = true; | 97 | + var streaming = true; |
98 | 98 | ||
99 | -classifier.load('haarcascade_frontalface_default.xml'); | 99 | + classifier.load('haarcascade_frontalface_default.xml'); |
100 | 100 | ||
101 | -const FPS = 30; | 101 | + const FPS = 30; |
102 | -function processVideo() { | 102 | + function processVideo() { |
103 | - try { | 103 | + try { |
104 | - if (!streaming) { | 104 | + if (!streaming) { |
105 | - // clean and stop. | 105 | + // clean and stop. |
106 | - src.delete(); | 106 | + src.delete(); |
107 | - dst.delete(); | 107 | + dst.delete(); |
108 | - gray.delete(); | 108 | + gray.delete(); |
109 | - faces.delete(); | 109 | + faces.delete(); |
110 | - classifier.delete(); | 110 | + classifier.delete(); |
111 | - return; | 111 | + return; |
112 | + } | ||
113 | + let begin = Date.now(); | ||
114 | + // start processing. | ||
115 | + cap.read(src); | ||
116 | + cv.flip(src, src, 1); | ||
117 | + src.copyTo(dst); | ||
118 | + // cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); | ||
119 | + // detect faces. | ||
120 | + let msize = new cv.Size(video.width / 4, video.height / 4); | ||
121 | + classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize); | ||
122 | + // draw faces. | ||
123 | + console.log('draw faces'); | ||
124 | + for (let i = 0; i < faces.size(); ++i) { | ||
125 | + let face = faces.get(i); | ||
126 | + let point1 = new cv.Point(face.x, face.y); | ||
127 | + let point2 = new cv.Point(face.x + face.width, face.y + face.height); | ||
128 | + cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8); | ||
129 | + let cropped = new cv.Mat(); | ||
130 | + let rect = new cv.Rect(Math.max(face.x-22, 0), Math.max(face.y-44, 0), Math.min(face.width+44, src.cols), Math.min(face.height+66, src.rows)); | ||
131 | + cropped = src.roi(rect); | ||
132 | + let tempCanvas = document.createElement("canvas"); | ||
133 | + cv.imshow(tempCanvas,cropped); | ||
134 | + console.log('b64encode'); | ||
135 | + if (tracker.register(face.x, face.y, face.width, face.height)){ | ||
136 | + let b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0); | ||
137 | + b64encoded = b64encoded.replace('data:image/jpeg;base64,', ''); | ||
138 | + $.ajax({ | ||
139 | + type: "POST", | ||
140 | + url: "/verify", | ||
141 | + dataType: "json", | ||
142 | + data: {'image':b64encoded}, | ||
143 | + success: function(data){ | ||
144 | + if (data.status == "attend"){ | ||
145 | + var newDiv = document.createElement("div"); | ||
146 | + var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "출석"); | ||
147 | + newDiv.appendChild(newContent); | ||
148 | + document.body.appendChild(newDiv); | ||
149 | + } | ||
150 | + else if (data.status == "already"){ | ||
151 | + var newDiv = document.createElement("div"); | ||
152 | + var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "이미 출석처리 되었습니다."); | ||
153 | + newDiv.appendChild(newContent); | ||
154 | + document.body.appendChild(newDiv); | ||
155 | + } | ||
156 | + else{ | ||
157 | + var newDiv = document.createElement("div"); | ||
158 | + var newContent = document.createTextNode("실패"); | ||
159 | + newDiv.appendChild(newContent); | ||
160 | + document.body.appendChild(newDiv); | ||
161 | + } | ||
162 | + } | ||
163 | + }); | ||
164 | + } | ||
165 | + } | ||
166 | + // to do resize preview | ||
167 | + cv.imshow('canvasOutput', dst); | ||
168 | + // schedule the next one. | ||
169 | + let delay = 1000/FPS - (Date.now() - begin); | ||
170 | + setTimeout(processVideo, delay); | ||
171 | + } catch (err) { | ||
172 | + console.log(err); | ||
112 | } | 173 | } |
113 | - let begin = Date.now(); | ||
114 | - // start processing. | ||
115 | - cap.read(src); | ||
116 | - cv.flip(src, src, 1); | ||
117 | - src.copyTo(dst); | ||
118 | - // cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); | ||
119 | - // detect faces. | ||
120 | - let msize = new cv.Size(video.width / 4, video.height / 4); | ||
121 | - classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize); | ||
122 | - // draw faces. | ||
123 | - console.log('draw faces'); | ||
124 | - for (let i = 0; i < faces.size(); ++i) { | ||
125 | - let face = faces.get(i); | ||
126 | - let point1 = new cv.Point(face.x, face.y); | ||
127 | - let point2 = new cv.Point(face.x + face.width, face.y + face.height); | ||
128 | - cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8); | ||
129 | - let cropped = new cv.Mat(); | ||
130 | - let rect = new cv.Rect(Math.max(face.x-22, 0), Math.max(face.y-44, 0), Math.min(face.width+44, src.cols), Math.min(face.height+66, src.rows)); | ||
131 | - cropped = src.roi(rect); | ||
132 | - let tempCanvas = document.createElement("canvas"); | ||
133 | - cv.imshow(tempCanvas,cropped); | ||
134 | - console.log('b64encode'); | ||
135 | - if (tracker.register(face.x, face.y, face.width, face.height, Date.now())){ | ||
136 | - let b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0); | ||
137 | - b64encoded = b64encoded.replace('data:image/jpeg;base64,', '') | ||
138 | - console.log('ajax post'); | ||
139 | - $.ajax({ | ||
140 | - type: "POST", | ||
141 | - url: "/verify", | ||
142 | - dataType: "json", | ||
143 | - data: {'image':b64encoded}, | ||
144 | - success: function(data){ | ||
145 | - if (data.status == "attend"){ | ||
146 | - var newDiv = document.createElement("div"); | ||
147 | - var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "출석"); | ||
148 | - newDiv.appendChild(newContent); | ||
149 | - document.body.appendChild(newDiv); | ||
150 | - } | ||
151 | - else if (data.status == "already"){ | ||
152 | - var newDiv = document.createElement("div"); | ||
153 | - var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "이미 출석처리 되었습니다."); | ||
154 | - newDiv.appendChild(newContent); | ||
155 | - document.body.appendChild(newDiv); | ||
156 | - } | ||
157 | - else{ | ||
158 | - var newDiv = document.createElement("div"); | ||
159 | - var newContent = document.createTextNode("실패"); | ||
160 | - newDiv.appendChild(newContent); | ||
161 | - document.body.appendChild(newDiv); | ||
162 | - } | ||
163 | - } | ||
164 | - }); | ||
165 | - } | ||
166 | - } | ||
167 | - // to do resize preview | ||
168 | - cv.imshow('canvasOutput', dst); | ||
169 | - // schedule the next one. | ||
170 | - let delay = 1000/FPS - (Date.now() - begin); | ||
171 | - setTimeout(processVideo, delay); | ||
172 | - } catch (err) { | ||
173 | - console.log(err); | ||
174 | } | 174 | } |
175 | -} | 175 | + setTimeout(processVideo, 0); |
176 | -setTimeout(processVideo, 0); | ||
177 | } | 176 | } |
178 | </script> | 177 | </script> |
179 | </head> | 178 | </head> |
180 | <body onload="cv['onRuntimeInitialized']=()=>{ init(); };"> | 179 | <body onload="cv['onRuntimeInitialized']=()=>{ init(); };"> |
181 | -<div id="container"> | 180 | + <div id="container"> |
182 | -<video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video> | 181 | + <video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video> |
183 | -<canvas id="canvasOutput"></canvas> | 182 | + <canvas id="canvasOutput"></canvas> |
184 | -</div> | 183 | + </div> |
185 | </body> | 184 | </body> |
186 | </html> | 185 | </html> | ... | ... |
... | @@ -11,133 +11,199 @@ | ... | @@ -11,133 +11,199 @@ |
11 | <script type='text/javascript' src="{{url_for('static', filename='js/utils.js')}}"></script> | 11 | <script type='text/javascript' src="{{url_for('static', filename='js/utils.js')}}"></script> |
12 | <script type='text/javascript' src="https://code.jquery.com/jquery-1.12.4.min.js"></script> | 12 | <script type='text/javascript' src="https://code.jquery.com/jquery-1.12.4.min.js"></script> |
13 | <script type='text/javascript'> | 13 | <script type='text/javascript'> |
14 | -var tempImage = new Image(); | 14 | +var b64encoded = ''; |
15 | -var tempCanvas = document.createElement("canvas"); | 15 | +var streaming = true; |
16 | +function init() | ||
17 | +{ | ||
18 | + let video = document.getElementById('videoInput'); | ||
19 | + let container = document.getElementById('container'); | ||
20 | + let canvasOutput = document.getElementById("canvasOutput"); | ||
21 | + if (navigator.mediaDevices.getUserMedia){ | ||
22 | + navigator.mediaDevices.getUserMedia({ video: true }) | ||
23 | + .then(function (stream) { | ||
24 | + video.srcObject = stream; | ||
25 | + video.addEventListener('canplay', () => { | ||
26 | + video.width = video.videoWidth; | ||
27 | + video.height = video.videoHeight; | ||
28 | + container.style.width = video.videoWidth + 'px'; | ||
29 | + container.style.height = video.videoHeight + 'px'; | ||
30 | + canvasOutput.width = video.videoWidth; | ||
31 | + canvasOutput.height = video.videoHeight; | ||
32 | + load_cascade(); | ||
33 | + }); | ||
34 | + }).catch(function (err0r) { | ||
35 | + console.log("Something went wrong!"); | ||
36 | + streaming = false; | ||
37 | + }); | ||
38 | + } | ||
39 | +} | ||
16 | 40 | ||
17 | function load_cascade() | 41 | function load_cascade() |
18 | { | 42 | { |
19 | let faceCascadeFile = 'haarcascade_frontalface_default.xml' | 43 | let faceCascadeFile = 'haarcascade_frontalface_default.xml' |
20 | let faceCascadeURL = 'static/js/haarcascade_frontalface_default.xml' | 44 | let faceCascadeURL = 'static/js/haarcascade_frontalface_default.xml' |
21 | - let utils = new Utils('errorMessage'); | 45 | + let utils = new Utils('errorMessage'); |
22 | utils.createFileFromUrl(faceCascadeFile, faceCascadeURL, () => { | 46 | utils.createFileFromUrl(faceCascadeFile, faceCascadeURL, () => { |
23 | - activate(); | 47 | + main(); |
24 | }); | 48 | }); |
25 | } | 49 | } |
26 | -function activate() | 50 | + |
51 | +function main() | ||
52 | +{ | ||
53 | + let video = document.getElementById("videoInput"); | ||
54 | + let canvasOutput = document.getElementById("canvasOutput"); | ||
55 | + let canvasContext = canvasOutput.getContext('2d'); | ||
56 | + let src = new cv.Mat(video.height, video.width, cv.CV_8UC4); | ||
57 | + let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4); | ||
58 | + let cap = new cv.VideoCapture(video); | ||
59 | + let faces = new cv.RectVector(); | ||
60 | + let classifier = new cv.CascadeClassifier(); | ||
61 | + | ||
62 | + class Tracker{ | ||
63 | + constructor(){ | ||
64 | + this.arr = new Array(); | ||
65 | + } | ||
66 | + register = function(x, y, width, height) { | ||
67 | + var x_center = (x + width) / 2; | ||
68 | + var y_center = (y + height) / 2; | ||
69 | + var now = Date.now() | ||
70 | + this.arr = this.arr.filter(ent => now - ent.time < 300); | ||
71 | + for (const prop in this.arr){ | ||
72 | + var prop_x_center = (this.arr[prop].x + this.arr[prop].width) / 2; | ||
73 | + var prop_y_center = (this.arr[prop].y + this.arr[prop].height) / 2; | ||
74 | + if (Math.abs(x_center - prop_x_center) < 10 && Math.abs(y_center - prop_y_center) < 10){ | ||
75 | + this.arr[prop].x = x; | ||
76 | + this.arr[prop].y = y; | ||
77 | + this.arr[prop].width = width; | ||
78 | + this.arr[prop].height = height; | ||
79 | + this.arr[prop].time = now; | ||
80 | + return this.arr[prop].init_time; | ||
81 | + } | ||
82 | + } | ||
83 | + var ent = {x: x, y: y, width: width, height: height, time: now, init_time: now} | ||
84 | + this.arr.push(ent) | ||
85 | + return now; | ||
86 | + } | ||
87 | + }; | ||
88 | + | ||
89 | + var tracker = new Tracker(); | ||
90 | + classifier.load('haarcascade_frontalface_default.xml'); | ||
91 | + const FPS = 30; | ||
92 | + function processVideo() { | ||
93 | + try { | ||
94 | + if (!streaming) { | ||
95 | + // clean and stop. | ||
96 | + src.delete(); | ||
97 | + dst.delete(); | ||
98 | + gray.delete(); | ||
99 | + faces.delete(); | ||
100 | + classifier.delete(); | ||
101 | + return; | ||
102 | + } | ||
103 | + let begin = Date.now(); | ||
104 | + // start processing. | ||
105 | + cap.read(src); | ||
106 | + cv.flip(src, src, 1); | ||
107 | + src.copyTo(dst); | ||
108 | + // cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); | ||
109 | + // detect faces. | ||
110 | + let msize = new cv.Size(video.width / 4, video.height / 4); | ||
111 | + classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize); | ||
112 | + // draw faces. | ||
113 | + console.log('draw faces'); | ||
114 | + for (let i = 0; i < faces.size(); ++i) { | ||
115 | + let face = faces.get(i); | ||
116 | + let point1 = new cv.Point(face.x, face.y); | ||
117 | + let point2 = new cv.Point(face.x + face.width, face.y + face.height); | ||
118 | + cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8); | ||
119 | + let cropped = new cv.Mat(); | ||
120 | + let rect = new cv.Rect(Math.max(face.x-22, 0), Math.max(face.y-44, 0), Math.min(face.width+44, src.cols), Math.min(face.height+66, src.rows)); | ||
121 | + cropped = src.roi(rect); | ||
122 | + let tempCanvas = document.createElement("canvas"); | ||
123 | + cv.imshow(tempCanvas,cropped); | ||
124 | + if (Date.now() - tracker.register(face.x, face.y, face.width, face.height) > 1000){ | ||
125 | + // 1초동안 인식되면 사진 촬영 종료하고 등록 버튼 활성화 | ||
126 | + b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0); | ||
127 | + toggle_streaming(); | ||
128 | + activate_sender(); | ||
129 | + } | ||
130 | + } | ||
131 | + // to do resize preview | ||
132 | + cv.imshow('canvasOutput', dst); | ||
133 | + // schedule the next one. | ||
134 | + let delay = 1000/FPS - (Date.now() - begin); | ||
135 | + setTimeout(processVideo, delay); | ||
136 | + } catch (err) { | ||
137 | + console.log(err); | ||
138 | + } | ||
139 | + } | ||
140 | + setTimeout(processVideo, 0); | ||
141 | +} | ||
142 | + | ||
143 | +function activate_sender() | ||
27 | { | 144 | { |
28 | - let fileloader = document.getElementById("fileloader"); | 145 | + let sender = document.getElementById("sender"); |
29 | fileloader.disabled = false; | 146 | fileloader.disabled = false; |
30 | } | 147 | } |
31 | 148 | ||
32 | -function detect_face() | 149 | +function toggle_streaming() |
33 | { | 150 | { |
34 | - let canvas = document.createElement('canvas'); | 151 | + streamButton = document.getElementById("streamButton"); |
35 | - canvas.width = tempImage.width; | 152 | + streaming = !streaming; |
36 | - canvas.height = tempImage.height; | 153 | + if (streaming) |
37 | - let ctx = canvas.getContext('2d') | 154 | + streamButton.value = "촬영중지"; |
38 | - ctx.drawImage(tempImage, 0, 0); | 155 | + else |
39 | - let src = cv.imread(canvas); | 156 | + streamButton.value = "촬영시작"; |
40 | - let dst = new cv.Mat(src.cols, src.rows, cv.CV_8UC4); | 157 | + main(); |
41 | - // let gray = new cv.Mat(); | ||
42 | - let faces = new cv.RectVector(); | ||
43 | - let classifier = new cv.CascadeClassifier(); | ||
44 | - classifier.load('haarcascade_frontalface_default.xml'); | ||
45 | - src.copyTo(dst); | ||
46 | - // cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); | ||
47 | - let msize = new cv.Size(tempImage.width / 4, tempImage.height / 4); | ||
48 | - // detect faces. | ||
49 | - classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize); | ||
50 | - if (faces.size() == 0) | ||
51 | - { | ||
52 | - alert('얼굴이 인식되지 않았습니다. 얼굴 이미지가 작지 않은지 확인해주세요.'); | ||
53 | - } | ||
54 | - else if (faces.size() > 1) | ||
55 | - { | ||
56 | - alert('하나의 얼굴만 등록해주세요.') | ||
57 | - } | ||
58 | - // draw faces. | ||
59 | - for (let i = 0; i < faces.size(); ++i) { | ||
60 | - let face = faces.get(i); | ||
61 | - let point1 = new cv.Point(face.x, face.y); | ||
62 | - let point2 = new cv.Point(face.x + face.width, face.y + face.height); | ||
63 | - cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8); | ||
64 | - let rect = new cv.Rect(Math.max(face.x-22, 0), Math.max(face.y-44, 0), Math.min(face.width+44, src.cols), Math.min(face.height+66, src.rows)); | ||
65 | - let cropped = src.roi(rect); | ||
66 | - cv.imshow(tempCanvas,cropped); | ||
67 | - } | ||
68 | - if (faces.size() == 1) | ||
69 | - { | ||
70 | - let sender = document.getElementById("sender"); | ||
71 | - sender.disabled = false; | ||
72 | - } | ||
73 | - if (dst.cols > $(window).width() || dst.rows > $(window).height()) | ||
74 | - { | ||
75 | - let ratio = Math.min($(window).width() / parseFloat(dst.cols), $(window).height() / parseFloat(dst.rows)); | ||
76 | - let dsize = new cv.Size(dst.cols * ratio, dst.rows * ratio); | ||
77 | - cv.resize(dst, dst, dsize, 0, 0, cv.INTER_AREA); | ||
78 | - } | ||
79 | - let preview = document.getElementById('preview'); | ||
80 | - cv.imshow(preview, dst); | ||
81 | } | 158 | } |
82 | 159 | ||
83 | function submit() | 160 | function submit() |
84 | { | 161 | { |
85 | - let b64encoded = tempCanvas.toDataURL('image/jpeg', 1.0); | 162 | + let student_id = document.getElementById('student_id').value; |
86 | - let student_id = document.getElementById('student_id').value; | 163 | + let student_name = document.getElementById('student_name').value; |
87 | - let student_name = document.getElementById('student_name').value; | 164 | + b64encoded = b64encoded.replace('data:image/jpeg;base64,', '') |
88 | - b64encoded = b64encoded.replace('data:image/jpeg;base64,', '') | 165 | + $.ajax({ |
89 | - $.ajax({ | 166 | + type: "POST", |
90 | - type: "POST", | 167 | + url: "/register", |
91 | - url: "/register", | 168 | + dataType: "json", |
92 | - dataType: "json", | 169 | + data: {'image':b64encoded, 'student_id':student_id, 'student_name':student_name}, |
93 | - data: {'image':b64encoded, 'student_id':student_id, 'student_name':student_name}, | 170 | + success: function(data){ |
94 | - success: function(data){ | 171 | + if (data.status == "success"){ |
95 | - if (data.status == "success"){ | 172 | + alert("등록 성공"); |
96 | - alert("등록 성공"); | 173 | + } |
97 | - } | 174 | + else{ |
98 | - else{ | 175 | + alert("등록 실패"); |
99 | - alert("등록 실패"); | 176 | + } |
100 | - } | 177 | + } |
101 | - } | 178 | + }) |
102 | - }) | ||
103 | } | 179 | } |
104 | 180 | ||
105 | -var loadFile = function(event) { | ||
106 | - var reader = new FileReader(); | ||
107 | - reader.readAsDataURL(event.target.files[0]); | ||
108 | - reader.onload = function() { | ||
109 | - tempImage.src = reader.result; | ||
110 | - tempImage.onload = function() | ||
111 | - { | ||
112 | - detect_face(); | ||
113 | - } | ||
114 | - }; | ||
115 | - }; | ||
116 | </script> | 181 | </script> |
117 | </head> | 182 | </head> |
118 | -<body onload="cv['onRuntimeInitialized']=()=>{load_cascade();};" class="w3-light-grey"> | 183 | +<body onload="cv['onRuntimeInitialized']=()=>{init();};" class="w3-light-grey"> |
119 | <!-- w3-content defines a container for fixed size centered content, | 184 | <!-- w3-content defines a container for fixed size centered content, |
120 | and is wrapped around the whole page content, except for the footer in this example --> | 185 | and is wrapped around the whole page content, except for the footer in this example --> |
121 | - <div class="w3-content" style="max-width:1400px"> | 186 | + <div class="w3-content" style="max-width:1400px"> |
122 | - <!-- Header --> | 187 | + <!-- Header --> |
123 | - <header class="w3-container w3-center w3-padding-32"> | 188 | + <header class="w3-container w3-center w3-padding-32"> |
124 | - <h1><b>얼굴 등록</b></h1> | 189 | + <h1><b>얼굴 등록</b></h1> |
125 | - <p>Made by <span class="w3-tag">정해갑</span></p> | 190 | + <p>Made by <span class="w3-tag">정해갑</span></p> |
126 | - </header> | 191 | + </header> |
127 | 192 | ||
128 | - <div class="w3-row", style='text-align:center'> | 193 | + <div class="w3-row", style='text-align:center'> |
129 | - <h2><b>얼굴 파일을 등록해주세요 (jpeg only)</b></h2> | 194 | + <h2><b>얼굴을 등록해주세요 (jpeg only)</b></h2> |
130 | - <div> | 195 | + <div id="container"> |
131 | - 학번: <input type="text" id="student_id"><br> | 196 | + <video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video> |
132 | - 이름: <input type="text" id="student_name"><br><br> | 197 | + <canvas id="canvasOutput"></canvas> |
133 | - <input type="file" id="fileloader" name="file" onchange="loadFile(event)" autocomplete="off" accept="image/jpeg" required disabled> | 198 | + </div> |
134 | - <div> | 199 | + <div> |
135 | - <canvas id="preview"></canvas> | 200 | + 학번: <input type="text" id="student_id"><br> |
136 | - </div> | 201 | + 이름: <input type="text" id="student_name"><br><br> |
137 | - <input id="sender" type="button" onclick="submit()" value="등록" disabled> | 202 | + <input id="streamButton" type="button" onclick="toggle_streaming()" value="활영중지" disabled> |
138 | - </div> | 203 | + <input id="sender" type="button" onclick="submit()" value="등록" disabled> |
139 | - </div> | 204 | + </div> |
140 | - </div> | 205 | + </div> |
206 | + </div> | ||
141 | </body> | 207 | </body> |
142 | </html> | 208 | </html> |
143 | 209 | ... | ... |
-
Please register or login to post a comment