Toggle navigation
Toggle navigation
This project
Loading...
Sign in
2020-2-capstone-design2
/
2014104149
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
Graduate
2020-11-29 17:02:56 +0900
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
2d48df0028a5760d818b71904b615051811bd332
2d48df00
1 parent
5b31ce44
Update roll book
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
281 additions
and
0 deletions
flask/app.py
flask/templates/attendance.html
flask/app.py
View file @
2d48df0
...
...
@@ -162,6 +162,15 @@ def verify():
attendance_db
.
close
()
return
send
@app.route
(
'/attendance.html'
)
def
tempAttendance
():
attendance_db
=
pymysql
.
connect
(
read_default_file
=
"./DB.cnf"
)
cursor
=
attendance_db
.
cursor
(
pymysql
.
cursors
.
DictCursor
)
sql
=
"SELECT ls.student_id, s.student_name, sa.status FROM lecture_students AS ls LEFT JOIN student_attendance AS sa ON ls.student_id = sa.student_id LEFT JOIN student AS s ON ls.student_id = s.student_id;"
mycursor
.
execute
(
sql
)
data
=
mycursor
.
fetchall
()
return
render_template
(
'attendance.html'
,
output_data
=
data
)
@app.route
(
'/robots.txt'
)
def
robots
():
return
send_from_directory
(
app
.
static_folder
,
request
.
path
[
1
:])
...
...
flask/templates/attendance.html
0 → 100644
View file @
2d48df0
<!doctype html>
<html>
<head>
<meta
charset=
"utf-8"
>
<meta
name=
"viewport"
content=
"width=device-width, initial-scale=1"
>
<title>
Web Attendance System Register
</title>
<link
rel=
"stylesheet"
href=
"https://www.w3schools.com/w3css/4/w3.css"
>
<link
rel=
"stylesheet"
href=
"https://fonts.googleapis.com/css?family=Nanum+Gothic:400,700,800&subset=korean"
>
<style>body
,
h1
,
h2
,
h3
,
h4
,
h5
,
p
{
font-family
:
"Nanum+Gothic"
,
sans-serif
}
</
style
>
<
style
>
#container
{
margin
:
15px
auto
;
}
#videoInput
{
background-color
:
#666
;
}
#canvasOutput
{
background-color
:
#666
;
}
#student_id
{
margin-top
:
10px
;
margin-bottom
:
5px
;
}
#student_name
{
margin-bottom
:
10px
;
}
</style>
<script
type=
'text/javascript'
src=
"{{url_for('static', filename='js/opencv.js')}}"
></script>
<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
b64encoded
=
''
;
var
streaming
=
false
;
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'
,
()
=>
{
var
screenWidth
=
$
(
document
).
width
();
var
screenHeight
=
$
(
document
).
height
();
var
headerHeight
=
$
(
'#header'
).
height
();
var
inputformHeight
=
$
(
'#inputForm'
).
height
();
var
ratio
=
1.0
;
video
.
width
=
video
.
videoWidth
;
video
.
height
=
video
.
videoHeight
;
if
(
video
.
width
>
screenWidth
||
headerHeight
+
video
.
height
+
inputformHeight
>
screenHeight
){
ratio
=
Math
.
min
(
screenWidth
/
(
video
.
width
*
1.0
),
screenHeight
/
((
headerHeight
+
video
.
height
+
inputformHeight
)
*
1.0
));
}
container
.
style
.
width
=
Math
.
round
(
video
.
width
*
ratio
)
+
'px'
;
container
.
style
.
height
=
Math
.
round
(
video
.
height
*
ratio
)
+
'px'
;
canvasOutput
.
width
=
Math
.
round
(
video
.
width
*
ratio
);
canvasOutput
.
height
=
Math
.
round
(
video
.
height
*
ratio
);
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'
);
utils
.
createFileFromUrl
(
faceCascadeFile
,
faceCascadeURL
,
()
=>
{
main
();
});
}
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
msize
=
new
cv
.
Size
(
video
.
width
/
4
,
video
.
height
/
4
);
let
dsize
=
new
cv
.
Size
(
canvasOutput
.
width
,
canvasOutput
.
height
);
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
();
faces
.
delete
();
classifier
.
delete
();
return
;
}
let
begin
=
Date
.
now
();
// start processing.
cap
.
read
(
src
);
cv
.
flip
(
src
,
src
,
1
);
src
.
copyTo
(
dst
);
// detect faces.
classifier
.
detectMultiScale
(
dst
,
faces
,
1.1
,
5
,
0
,
msize
);
// 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
margin_x
=
0
;
let
margin_y
=
0
;
if
(
face
.
width
>
face
.
height
)
{
margin_y
=
(
face
.
width
-
face
.
height
)
/
2
;
}
else
{
margin_x
=
(
face
.
height
-
face
.
width
)
/
2
;
}
Math
.
max
(
face
.
width
,
face
.
height
)
Math
.
min
(
face
.
width
,
face
.
height
)
let
rect
=
new
cv
.
Rect
(
Math
.
max
(
face
.
x
-
margin_x
,
0
),
Math
.
max
(
face
.
y
-
margin_y
,
0
),
Math
.
min
(
face
.
width
+
margin_x
,
src
.
cols
),
Math
.
min
(
face
.
height
+
margin_y
,
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초동안 인식되면 사진 촬영 종료하고 등록 버튼 활성화
cv
.
rectangle
(
dst
,
point1
,
point2
,
[
0
,
255
,
0
,
255
],
8
);
b64encoded
=
tempCanvas
.
toDataURL
(
"image/jpeg"
,
0.6
);
toggle_streaming
();
change_notice
(
"촬영 완료! 정보를 등록해주세요<br>제대로 촬영되지 않은 경우 버튼을 눌러 다시 촬영할 수 있습니다."
);
activate_sender
();
}
}
// to do resize preview
cv
.
resize
(
dst
,
dst
,
dsize
,
0
,
0
,
cv
.
INTER_AREA
);
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
sender
=
document
.
getElementById
(
"sender"
);
sender
.
disabled
=
false
;
}
function
toggle_streaming
()
{
let
streamButton
=
document
.
getElementById
(
"streamButton"
);
streaming
=
!
streaming
;
if
(
streaming
){
streamButton
.
value
=
"촬영중지"
;
change_notice
(
"얼굴이 인식되면 얼굴을 촬영합니다"
);
}
else
{
streamButton
.
value
=
"촬영시작"
;
change_notice
(
"촬영 시작 버튼을 누르면 얼굴을 촬영합니다"
);
}
main
();
}
function
change_notice
(
text
)
{
let
notice
=
document
.
getElementById
(
"notice"
);
notice
.
innerHTML
=
text
;
}
function
submit
()
{
let
student_id
=
document
.
getElementById
(
'student_id'
).
value
;
let
student_name
=
document
.
getElementById
(
'student_name'
).
value
;
if
(
b64encoded
===
''
)
{
alert
(
"얼굴을 먼저 촬영해주세요"
);
return
;
}
if
(
!
(
student_id
.
length
&&
student_name
.
length
))
{
alert
(
"학번과 이름을 입력해주세요"
);
return
;
}
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
if
(
data
.
status
==
"already"
){
alert
(
"등록 실패: 이미 등록된 학번입니다. 학번을 변경해주세요."
);
}
}
})
}
</script>
</head>
<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"
>
<!-- Header -->
<header
id=
"header"
class=
"w3-container w3-center"
>
<h1><b>
얼굴 등록
</b></h1>
<p>
Made by
<span
class=
"w3-tag"
>
정해갑
</span></p>
</header>
<div
class=
"w3-row"
,
style=
'text-align:center'
>
<h2
id=
"notice"
>
촬영 시작 버튼을 누르면 얼굴을 촬영합니다
</h2>
<input
id=
"streamButton"
type=
"button"
onclick=
"toggle_streaming()"
value=
"활영시작"
>
<div
id=
"container"
>
<video
autoplay=
"true"
id=
"videoInput"
style=
"display: none; object-fit:cover;"
></video>
<canvas
id=
"canvasOutput"
>
/canvas>
</div>
<div
id=
"inputForm"
>
<strong>
얼굴 이미지는 서버에 저장되지 않습니다
</strong><br>
<strong>
(복원 불가능한 512차원 벡터로 변환됩니다)
</strong><br>
<strong>
학번과 이름은 임의로 입력해주세요
</strong><br>
<strong>
예)1234/홍길동 등
</strong><br>
학번:
<input
type=
"text"
id=
"student_id"
><br>
이름:
<input
type=
"text"
id=
"student_name"
><br>
<input
id=
"sender"
type=
"button"
onclick=
"submit()"
value=
"등록"
disabled
>
</div>
</div>
</div>
</body>
</html>
Please
register
or
login
to post a comment