Graduate

Change register page

......@@ -5,14 +5,14 @@
<title>Web Attendance System</title>
<style>
#container {
margin: 0px auto;
border: 10px #333 solid;
margin: 0px auto;
border: 10px #333 solid;
}
#videoInput {
background-color: #666;
background-color: #666;
}
#canvasOutput {
background-color: #666;
background-color: #666;
}
</style>
<script type='text/javascript' src="{{url_for('static', filename='js/opencv.js')}}"></script>
......@@ -27,18 +27,18 @@ function init()
let canvasOutput = document.getElementById("canvasOutput");
if (navigator.mediaDevices.getUserMedia){
navigator.mediaDevices.getUserMedia({ video: true })
.then(function (stream) {
.then(function (stream) {
video.srcObject = stream;
video.addEventListener('canplay', () => {
video.width = video.videoWidth;
video.height = video.videoHeight;
container.style.width = video.videoWidth + 'px';
container.style.height = video.videoHeight + 'px';
canvasOutput.width = video.videoWidth;
canvasOutput.height = video.videoHeight;
load_cascade();
});
}).catch(function (err0r) {
video.addEventListener('canplay', () => {
video.width = video.videoWidth;
video.height = video.videoHeight;
container.style.width = video.videoWidth + 'px';
container.style.height = video.videoHeight + 'px';
canvasOutput.width = video.videoWidth;
canvasOutput.height = video.videoHeight;
load_cascade();
});
}).catch(function (err0r) {
console.log("Something went wrong!");
streaming = false;
});
......@@ -49,7 +49,7 @@ function load_cascade()
{
let faceCascadeFile = 'haarcascade_frontalface_default.xml'
let faceCascadeURL = 'static/js/haarcascade_frontalface_default.xml'
let utils = new Utils('errorMessage');
let utils = new Utils('errorMessage');
utils.createFileFromUrl(faceCascadeFile, faceCascadeURL, () => {
main()
});
......@@ -58,129 +58,128 @@ function load_cascade()
function main()
{
let video = document.getElementById("videoInput");
let canvasOutput = document.getElementById("canvasOutput");
let canvasContext = canvasOutput.getContext('2d');
let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4);
// let gray = new cv.Mat();
let cap = new cv.VideoCapture(video);
let faces = new cv.RectVector();
let classifier = new cv.CascadeClassifier();
class Tracker{
constructor(){
this.arr = new Array();
}
register = function(x, y, width, height) {
var x_center = (x + width) / 2;
var y_center = (y + height) / 2;
var now = Date.now()
this.arr = this.arr.filter(ent => now - ent.time < 300);
for (const prop in this.arr){
var prop_x_center = (this.arr[prop].x + this.arr[prop].width) / 2;
var prop_y_center = (this.arr[prop].y + this.arr[prop].height) / 2;
if (Math.abs(x_center - prop_x_center) < 10 && Math.abs(y_center - prop_y_center) < 10){
this.arr[prop].x = x;
this.arr[prop].y = y;
this.arr[prop].width = width;
this.arr[prop].height = height;
this.arr[prop].time = now;
return false;
}
}
var ent = {x: x, y: y, width: width, height: height, time: now}
this.arr.push(ent)
return true;
}
};
var tracker = new Tracker();
var streaming = true;
let video = document.getElementById("videoInput");
let canvasOutput = document.getElementById("canvasOutput");
let canvasContext = canvasOutput.getContext('2d');
let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4);
// let gray = new cv.Mat();
let cap = new cv.VideoCapture(video);
let faces = new cv.RectVector();
let classifier = new cv.CascadeClassifier();
class Tracker{
constructor(){
this.arr = new Array();
}
register = function(x, y, width, height) {
var x_center = (x + width) / 2;
var y_center = (y + height) / 2;
var now = Date.now()
this.arr = this.arr.filter(ent => now - ent.time < 300);
for (const prop in this.arr){
var prop_x_center = (this.arr[prop].x + this.arr[prop].width) / 2;
var prop_y_center = (this.arr[prop].y + this.arr[prop].height) / 2;
if (Math.abs(x_center - prop_x_center) < 10 && Math.abs(y_center - prop_y_center) < 10){
this.arr[prop].x = x;
this.arr[prop].y = y;
this.arr[prop].width = width;
this.arr[prop].height = height;
this.arr[prop].time = now;
return false;
}
}
var ent = {x: x, y: y, width: width, height: height, time: now}
this.arr.push(ent)
return true;
}
};
var tracker = new Tracker();
var streaming = true;
classifier.load('haarcascade_frontalface_default.xml');
classifier.load('haarcascade_frontalface_default.xml');
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
src.delete();
dst.delete();
gray.delete();
faces.delete();
classifier.delete();
return;
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
src.delete();
dst.delete();
gray.delete();
faces.delete();
classifier.delete();
return;
}
let begin = Date.now();
// start processing.
cap.read(src);
cv.flip(src, src, 1);
src.copyTo(dst);
// cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0);
// detect faces.
let msize = new cv.Size(video.width / 4, video.height / 4);
classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize);
// draw faces.
console.log('draw faces');
for (let i = 0; i < faces.size(); ++i) {
let face = faces.get(i);
let point1 = new cv.Point(face.x, face.y);
let point2 = new cv.Point(face.x + face.width, face.y + face.height);
cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8);
let cropped = new cv.Mat();
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));
cropped = src.roi(rect);
let tempCanvas = document.createElement("canvas");
cv.imshow(tempCanvas,cropped);
console.log('b64encode');
if (tracker.register(face.x, face.y, face.width, face.height)){
let b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0);
b64encoded = b64encoded.replace('data:image/jpeg;base64,', '');
$.ajax({
type: "POST",
url: "/verify",
dataType: "json",
data: {'image':b64encoded},
success: function(data){
if (data.status == "attend"){
var newDiv = document.createElement("div");
var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "출석");
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
}
else if (data.status == "already"){
var newDiv = document.createElement("div");
var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "이미 출석처리 되었습니다.");
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
}
else{
var newDiv = document.createElement("div");
var newContent = document.createTextNode("실패");
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
}
}
});
}
}
// to do resize preview
cv.imshow('canvasOutput', dst);
// schedule the next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
console.log(err);
}
let begin = Date.now();
// start processing.
cap.read(src);
cv.flip(src, src, 1);
src.copyTo(dst);
// cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0);
// detect faces.
let msize = new cv.Size(video.width / 4, video.height / 4);
classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize);
// draw faces.
console.log('draw faces');
for (let i = 0; i < faces.size(); ++i) {
let face = faces.get(i);
let point1 = new cv.Point(face.x, face.y);
let point2 = new cv.Point(face.x + face.width, face.y + face.height);
cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8);
let cropped = new cv.Mat();
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));
cropped = src.roi(rect);
let tempCanvas = document.createElement("canvas");
cv.imshow(tempCanvas,cropped);
console.log('b64encode');
if (tracker.register(face.x, face.y, face.width, face.height, Date.now())){
let b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0);
b64encoded = b64encoded.replace('data:image/jpeg;base64,', '')
console.log('ajax post');
$.ajax({
type: "POST",
url: "/verify",
dataType: "json",
data: {'image':b64encoded},
success: function(data){
if (data.status == "attend"){
var newDiv = document.createElement("div");
var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "출석");
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
}
else if (data.status == "already"){
var newDiv = document.createElement("div");
var newContent = document.createTextNode('[' + data.student_id + '/' + data.student_name + ']' + "이미 출석처리 되었습니다.");
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
}
else{
var newDiv = document.createElement("div");
var newContent = document.createTextNode("실패");
newDiv.appendChild(newContent);
document.body.appendChild(newDiv);
}
}
});
}
}
// to do resize preview
cv.imshow('canvasOutput', dst);
// schedule the next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
console.log(err);
}
}
setTimeout(processVideo, 0);
setTimeout(processVideo, 0);
}
</script>
</head>
<body onload="cv['onRuntimeInitialized']=()=>{ init(); };">
<div id="container">
<video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video>
<canvas id="canvasOutput"></canvas>
</div>
<div id="container">
<video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video>
<canvas id="canvasOutput"></canvas>
</div>
</body>
</html>
......
......@@ -11,133 +11,199 @@
<script type='text/javascript' src="{{url_for('static', filename='js/utils.js')}}"></script>
<script type='text/javascript' src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<script type='text/javascript'>
var tempImage = new Image();
var tempCanvas = document.createElement("canvas");
var b64encoded = '';
var streaming = true;
function init()
{
let video = document.getElementById('videoInput');
let container = document.getElementById('container');
let canvasOutput = document.getElementById("canvasOutput");
if (navigator.mediaDevices.getUserMedia){
navigator.mediaDevices.getUserMedia({ video: true })
.then(function (stream) {
video.srcObject = stream;
video.addEventListener('canplay', () => {
video.width = video.videoWidth;
video.height = video.videoHeight;
container.style.width = video.videoWidth + 'px';
container.style.height = video.videoHeight + 'px';
canvasOutput.width = video.videoWidth;
canvasOutput.height = video.videoHeight;
load_cascade();
});
}).catch(function (err0r) {
console.log("Something went wrong!");
streaming = false;
});
}
}
function load_cascade()
{
let faceCascadeFile = 'haarcascade_frontalface_default.xml'
let faceCascadeURL = 'static/js/haarcascade_frontalface_default.xml'
let utils = new Utils('errorMessage');
let utils = new Utils('errorMessage');
utils.createFileFromUrl(faceCascadeFile, faceCascadeURL, () => {
activate();
main();
});
}
function activate()
function main()
{
let video = document.getElementById("videoInput");
let canvasOutput = document.getElementById("canvasOutput");
let canvasContext = canvasOutput.getContext('2d');
let src = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let dst = new cv.Mat(video.height, video.width, cv.CV_8UC4);
let cap = new cv.VideoCapture(video);
let faces = new cv.RectVector();
let classifier = new cv.CascadeClassifier();
class Tracker{
constructor(){
this.arr = new Array();
}
register = function(x, y, width, height) {
var x_center = (x + width) / 2;
var y_center = (y + height) / 2;
var now = Date.now()
this.arr = this.arr.filter(ent => now - ent.time < 300);
for (const prop in this.arr){
var prop_x_center = (this.arr[prop].x + this.arr[prop].width) / 2;
var prop_y_center = (this.arr[prop].y + this.arr[prop].height) / 2;
if (Math.abs(x_center - prop_x_center) < 10 && Math.abs(y_center - prop_y_center) < 10){
this.arr[prop].x = x;
this.arr[prop].y = y;
this.arr[prop].width = width;
this.arr[prop].height = height;
this.arr[prop].time = now;
return this.arr[prop].init_time;
}
}
var ent = {x: x, y: y, width: width, height: height, time: now, init_time: now}
this.arr.push(ent)
return now;
}
};
var tracker = new Tracker();
classifier.load('haarcascade_frontalface_default.xml');
const FPS = 30;
function processVideo() {
try {
if (!streaming) {
// clean and stop.
src.delete();
dst.delete();
gray.delete();
faces.delete();
classifier.delete();
return;
}
let begin = Date.now();
// start processing.
cap.read(src);
cv.flip(src, src, 1);
src.copyTo(dst);
// cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0);
// detect faces.
let msize = new cv.Size(video.width / 4, video.height / 4);
classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize);
// draw faces.
console.log('draw faces');
for (let i = 0; i < faces.size(); ++i) {
let face = faces.get(i);
let point1 = new cv.Point(face.x, face.y);
let point2 = new cv.Point(face.x + face.width, face.y + face.height);
cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8);
let cropped = new cv.Mat();
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));
cropped = src.roi(rect);
let tempCanvas = document.createElement("canvas");
cv.imshow(tempCanvas,cropped);
if (Date.now() - tracker.register(face.x, face.y, face.width, face.height) > 1000){
// 1초동안 인식되면 사진 촬영 종료하고 등록 버튼 활성화
b64encoded = tempCanvas.toDataURL("image/jpeg", 1.0);
toggle_streaming();
activate_sender();
}
}
// to do resize preview
cv.imshow('canvasOutput', dst);
// schedule the next one.
let delay = 1000/FPS - (Date.now() - begin);
setTimeout(processVideo, delay);
} catch (err) {
console.log(err);
}
}
setTimeout(processVideo, 0);
}
function activate_sender()
{
let fileloader = document.getElementById("fileloader");
let sender = document.getElementById("sender");
fileloader.disabled = false;
}
function detect_face()
function toggle_streaming()
{
let canvas = document.createElement('canvas');
canvas.width = tempImage.width;
canvas.height = tempImage.height;
let ctx = canvas.getContext('2d')
ctx.drawImage(tempImage, 0, 0);
let src = cv.imread(canvas);
let dst = new cv.Mat(src.cols, src.rows, cv.CV_8UC4);
// let gray = new cv.Mat();
let faces = new cv.RectVector();
let classifier = new cv.CascadeClassifier();
classifier.load('haarcascade_frontalface_default.xml');
src.copyTo(dst);
// cv.cvtColor(dst, gray, cv.COLOR_RGBA2GRAY, 0);
let msize = new cv.Size(tempImage.width / 4, tempImage.height / 4);
// detect faces.
classifier.detectMultiScale(dst, faces, 1.1, 3, 0, msize);
if (faces.size() == 0)
{
alert('얼굴이 인식되지 않았습니다. 얼굴 이미지가 작지 않은지 확인해주세요.');
}
else if (faces.size() > 1)
{
alert('하나의 얼굴만 등록해주세요.')
}
// draw faces.
for (let i = 0; i < faces.size(); ++i) {
let face = faces.get(i);
let point1 = new cv.Point(face.x, face.y);
let point2 = new cv.Point(face.x + face.width, face.y + face.height);
cv.rectangle(dst, point1, point2, [255, 0, 0, 255], 8);
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));
let cropped = src.roi(rect);
cv.imshow(tempCanvas,cropped);
}
if (faces.size() == 1)
{
let sender = document.getElementById("sender");
sender.disabled = false;
}
if (dst.cols > $(window).width() || dst.rows > $(window).height())
{
let ratio = Math.min($(window).width() / parseFloat(dst.cols), $(window).height() / parseFloat(dst.rows));
let dsize = new cv.Size(dst.cols * ratio, dst.rows * ratio);
cv.resize(dst, dst, dsize, 0, 0, cv.INTER_AREA);
}
let preview = document.getElementById('preview');
cv.imshow(preview, dst);
streamButton = document.getElementById("streamButton");
streaming = !streaming;
if (streaming)
streamButton.value = "촬영중지";
else
streamButton.value = "촬영시작";
main();
}
function submit()
{
let b64encoded = tempCanvas.toDataURL('image/jpeg', 1.0);
let student_id = document.getElementById('student_id').value;
let student_name = document.getElementById('student_name').value;
b64encoded = b64encoded.replace('data:image/jpeg;base64,', '')
$.ajax({
type: "POST",
url: "/register",
dataType: "json",
data: {'image':b64encoded, 'student_id':student_id, 'student_name':student_name},
success: function(data){
if (data.status == "success"){
alert("등록 성공");
}
else{
alert("등록 실패");
}
}
})
let student_id = document.getElementById('student_id').value;
let student_name = document.getElementById('student_name').value;
b64encoded = b64encoded.replace('data:image/jpeg;base64,', '')
$.ajax({
type: "POST",
url: "/register",
dataType: "json",
data: {'image':b64encoded, 'student_id':student_id, 'student_name':student_name},
success: function(data){
if (data.status == "success"){
alert("등록 성공");
}
else{
alert("등록 실패");
}
}
})
}
var loadFile = function(event) {
var reader = new FileReader();
reader.readAsDataURL(event.target.files[0]);
reader.onload = function() {
tempImage.src = reader.result;
tempImage.onload = function()
{
detect_face();
}
};
};
</script>
</head>
<body onload="cv['onRuntimeInitialized']=()=>{load_cascade();};" class="w3-light-grey">
<body onload="cv['onRuntimeInitialized']=()=>{init();};" class="w3-light-grey">
<!-- w3-content defines a container for fixed size centered content,
and is wrapped around the whole page content, except for the footer in this example -->
<div class="w3-content" style="max-width:1400px">
<!-- Header -->
<header class="w3-container w3-center w3-padding-32">
<h1><b>얼굴 등록</b></h1>
<p>Made by <span class="w3-tag">정해갑</span></p>
</header>
<div class="w3-content" style="max-width:1400px">
<!-- Header -->
<header class="w3-container w3-center w3-padding-32">
<h1><b>얼굴 등록</b></h1>
<p>Made by <span class="w3-tag">정해갑</span></p>
</header>
<div class="w3-row", style='text-align:center'>
<h2><b>얼굴 파일을 등록해주세요 (jpeg only)</b></h2>
<div>
학번: <input type="text" id="student_id"><br>
이름: <input type="text" id="student_name"><br><br>
<input type="file" id="fileloader" name="file" onchange="loadFile(event)" autocomplete="off" accept="image/jpeg" required disabled>
<div>
<canvas id="preview"></canvas>
</div>
<input id="sender" type="button" onclick="submit()" value="등록" disabled>
</div>
</div>
</div>
<div class="w3-row", style='text-align:center'>
<h2><b>얼굴을 등록해주세요 (jpeg only)</b></h2>
<div id="container">
<video autoplay="true" id="videoInput" style="display: none; object-fit: cover;"></video>
<canvas id="canvasOutput"></canvas>
</div>
<div>
학번: <input type="text" id="student_id"><br>
이름: <input type="text" id="student_name"><br><br>
<input id="streamButton" type="button" onclick="toggle_streaming()" value="활영중지" disabled>
<input id="sender" type="button" onclick="submit()" value="등록" disabled>
</div>
</div>
</div>
</body>
</html>
......