Graduate

Change register page

...@@ -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
......