Graduate

Change register page

...@@ -58,16 +58,16 @@ function load_cascade() ...@@ -58,16 +58,16 @@ 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 }
...@@ -92,14 +92,14 @@ class Tracker{ ...@@ -92,14 +92,14 @@ class Tracker{
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.
...@@ -132,10 +132,9 @@ function processVideo() { ...@@ -132,10 +132,9 @@ function processVideo() {
132 let tempCanvas = document.createElement("canvas"); 132 let tempCanvas = document.createElement("canvas");
133 cv.imshow(tempCanvas,cropped); 133 cv.imshow(tempCanvas,cropped);
134 console.log('b64encode'); 134 console.log('b64encode');
135 - if (tracker.register(face.x, face.y, face.width, face.height, Date.now())){ 135 + if (tracker.register(face.x, face.y, face.width, face.height)){
136 let b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0); 136 let b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0);
137 - b64encoded = b64encoded.replace('data:image/jpeg;base64,', '') 137 + b64encoded = b64encoded.replace('data:image/jpeg;base64,', '');
138 - console.log('ajax post');
139 $.ajax({ 138 $.ajax({
140 type: "POST", 139 type: "POST",
141 url: "/verify", 140 url: "/verify",
...@@ -172,15 +171,15 @@ function processVideo() { ...@@ -172,15 +171,15 @@ function processVideo() {
172 } catch (err) { 171 } catch (err) {
173 console.log(err); 172 console.log(err);
174 } 173 }
175 -} 174 + }
176 -setTimeout(processVideo, 0); 175 + 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,8 +11,32 @@ ...@@ -11,8 +11,32 @@
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 {
...@@ -20,69 +44,121 @@ function load_cascade() ...@@ -20,69 +44,121 @@ function load_cascade()
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()
27 -{
28 - let fileloader = document.getElementById("fileloader");
29 - fileloader.disabled = false;
30 -}
31 50
32 -function detect_face() 51 +function main()
33 { 52 {
34 - let canvas = document.createElement('canvas'); 53 + let video = document.getElementById("videoInput");
35 - canvas.width = tempImage.width; 54 + let canvasOutput = document.getElementById("canvasOutput");
36 - canvas.height = tempImage.height; 55 + let canvasContext = canvasOutput.getContext('2d');
37 - let ctx = canvas.getContext('2d') 56 + let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
38 - ctx.drawImage(tempImage, 0, 0); 57 + let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4);
39 - let src = cv.imread(canvas); 58 + let cap = new cv.VideoCapture(video);
40 - let dst = new cv.Mat(src.cols, src.rows, cv.CV_8UC4);
41 - // let gray = new cv.Mat();
42 let faces = new cv.RectVector(); 59 let faces = new cv.RectVector();
43 let classifier = new cv.CascadeClassifier(); 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();
44 classifier.load('haarcascade_frontalface_default.xml'); 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);
45 src.copyTo(dst); 107 src.copyTo(dst);
46 // cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0); 108 // cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0);
47 - let msize = new cv.Size(tempImage.width / 4, tempImage.height / 4);
48 // detect faces. 109 // detect faces.
110 + let msize = new cv.Size(video.width / 4, video.height / 4);
49 classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize); 111 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. 112 // draw faces.
113 + console.log('draw faces');
59 for (let i = 0; i < faces.size(); ++i) { 114 for (let i = 0; i < faces.size(); ++i) {
60 let face = faces.get(i); 115 let face = faces.get(i);
61 let point1 = new cv.Point(face.x, face.y); 116 let point1 = new cv.Point(face.x, face.y);
62 let point2 = new cv.Point(face.x + face.width, face.y + face.height); 117 let point2 = new cv.Point(face.x + face.width, face.y + face.height);
63 cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8); 118 cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8);
119 + let cropped = new cv.Mat();
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)); 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));
65 - let cropped = src.roi(rect); 121 + cropped = src.roi(rect);
122 + let tempCanvas = document.createElement("canvas");
66 cv.imshow(tempCanvas,cropped); 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();
67 } 129 }
68 - if (faces.size() == 1)
69 - {
70 - let sender = document.getElementById("sender");
71 - sender.disabled = false;
72 } 130 }
73 - if (dst.cols > $(window).width() || dst.rows > $(window).height()) 131 + // to do resize preview
74 - { 132 + cv.imshow('canvasOutput', dst);
75 - let ratio = Math.min($(window).width() / parseFloat(dst.cols), $(window).height() / parseFloat(dst.rows)); 133 + // schedule the next one.
76 - let dsize = new cv.Size(dst.cols * ratio, dst.rows * ratio); 134 + let delay = 1000/FPS - (Date.now() - begin);
77 - cv.resize(dst, dst, dsize, 0, 0, cv.INTER_AREA); 135 + setTimeout(processVideo, delay);
136 + } catch (err) {
137 + console.log(err);
138 + }
78 } 139 }
79 - let preview = document.getElementById('preview'); 140 + setTimeout(processVideo, 0);
80 - cv.imshow(preview, dst); 141 +}
142 +
143 +function activate_sender()
144 +{
145 + let sender = document.getElementById("sender");
146 + fileloader.disabled = false;
147 +}
148 +
149 +function toggle_streaming()
150 +{
151 + streamButton = document.getElementById("streamButton");
152 + streaming = !streaming;
153 + if (streaming)
154 + streamButton.value = "촬영중지";
155 + else
156 + streamButton.value = "촬영시작";
157 + main();
81 } 158 }
82 159
83 function submit() 160 function submit()
84 { 161 {
85 - let b64encoded = tempCanvas.toDataURL('image/jpeg', 1.0);
86 let student_id = document.getElementById('student_id').value; 162 let student_id = document.getElementById('student_id').value;
87 let student_name = document.getElementById('student_name').value; 163 let student_name = document.getElementById('student_name').value;
88 b64encoded = b64encoded.replace('data:image/jpeg;base64,', '') 164 b64encoded = b64encoded.replace('data:image/jpeg;base64,', '')
...@@ -102,20 +178,9 @@ function submit() ...@@ -102,20 +178,9 @@ function submit()
102 }) 178 })
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">
...@@ -126,14 +191,15 @@ and is wrapped around the whole page content, except for the footer in this exam ...@@ -126,14 +191,15 @@ and is wrapped around the whole page content, except for the footer in this exam
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>
195 + <div id="container">
196 + <video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video>
197 + <canvas id="canvasOutput"></canvas>
198 + </div>
130 <div> 199 <div>
131 학번: <input type="text" id="student_id"><br> 200 학번: <input type="text" id="student_id"><br>
132 이름: <input type="text" id="student_name"><br><br> 201 이름: <input type="text" id="student_name"><br><br>
133 - <input type="file" id="fileloader" name="file" onchange="loadFile(event)" autocomplete="off" accept="image/jpeg" required disabled> 202 + <input id="streamButton" type="button" onclick="toggle_streaming()" value="활영중지" disabled>
134 - <div>
135 - <canvas id="preview"></canvas>
136 - </div>
137 <input id="sender" type="button" onclick="submit()" value="등록" disabled> 203 <input id="sender" type="button" onclick="submit()" value="등록" disabled>
138 </div> 204 </div>
139 </div> 205 </div>
......