Graduate

Haar cascade with margin

[server]
uri=ws://localhost:3000
[client]
image_size=160
margin=44
\ No newline at end of file
......
##################################################
#1. webcam에서 얼굴을 인식합니다.
#2. 얼굴일 확률이 97% 이상이고 영역이 15000 이상인 이미지를 서버에 전송
#2. 얼굴일 영역이 15000 이상인 이미지를 서버에 전송
##################################################
import tkinter as tk
import tkinter.font
......@@ -39,7 +39,9 @@ class Client(tk.Frame):
self.cap.set(4, self.cam_height)
# Preprocessing
self.image_size = (160, 160)
self.margin = int(config['client']['margin'])
image_size = int(config['client']['image_size'])
self.image_size = (image_size, image_size)
# cam에서 MTCNN 적용하는 영역
self.detecting_square = (500, 300)
......@@ -96,7 +98,8 @@ class Client(tk.Frame):
minSize=self.image_size
)
for (x, y, w, h) in faces:
image = frame[y:y+h, x:x+w]
margin = int(self.margin / 2)
image = frame[y-margin:y+h+margin, x-margin:x+w+margin]
return image, True
return [], False
......@@ -126,10 +129,13 @@ class Client(tk.Frame):
self.label.image = image # kind of double buffering
@asyncio.coroutine
def set_rectangle(self):
def set_rectangle_success(self):
self.rectangle_color = (255, 0, 0)
yield from asyncio.sleep(2)
self.rectangle_color = (0, 0, 255)
def set_rectangle_fail(self):
self.rectangle_color = (0, 0, 255)
async def send_face(self, image):
try:
......@@ -137,24 +143,30 @@ class Client(tk.Frame):
img = base64.b64encode(cv2.imencode('.jpg', image)[1]).decode()
send = json.dumps({'action': 'verify', 'image': img})
await websocket.send(send)
recv = await websocket.recv()
recv = await asyncio.wait_for(websocket.recv(), timeout=1000)
data = json.loads(recv)
if data['action'] == 'success':
self.logging('succeed')
if data['status'] == 'attend':
student_id = data['student_id']
student_name = data['student_name']
self.logging(student_id + ' ' + student_name + ' is attend')
# change rectangle color
asyncio.ensure_future(self.set_rectangle())
elif data['action'] == 'fail':
asyncio.ensure_future(self.set_rectangle_success())
elif data['status'] == 'already':
# self.logging('already attend')
# change rectangle color
asyncio.ensure_future(self.set_rectangle_success())
elif data['status'] == 'fail':
self.logging('failed')
self.set_rectangle_fail()
except Exception as e:
self.logging(e)
def stop(self):
self.thread.do_run = False
self.thread.join()
self.event_loop.close()
#self.thread.join()
#self.event_loop.close()
self.cap.release()
self.parent.destroy()
if __name__ == '__main__':
root = tk.Tk()
......
[server]
uri=ws://localhost:3000
[register]
taking_time=0.2
image_size=160
margin=44
\ No newline at end of file
......
......@@ -26,7 +26,6 @@ class Register(tk.Frame):
# URI
self.uri = config['server']['uri']
# Cascade Model
self.cascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
......@@ -36,9 +35,12 @@ class Register(tk.Frame):
self.cam_height = 480
self.cap.set(3, self.cam_width)
self.cap.set(4, self.cam_height)
self.image_size = (160, 160)
image_size = int(config['register']['image_size'])
self.image_size = (image_size, image_size)
self.margin = int(config['register']['margin'])
# Application Function
self.taking_time = float(config['register']['taking_time'])
self.detecting_square = (400, 400)
self.detected = False
self.face = []
......@@ -120,7 +122,8 @@ class Register(tk.Frame):
minSize=self.image_size
)
for (x, y, w, h) in faces:
image = frame[y:y+h, x:x+w]
margin = int(self.margin / 2)
image = frame[y-margin:y+h+margin, x-margin:x+w+margin]
return image, True
return [], False
......@@ -157,12 +160,12 @@ class Register(tk.Frame):
# 얼굴이 인식되면 멤버함수에 넣음
if detected:
self.face = face
# 2초 후에 사진이 찍힘
# 0.5초 후에 사진이 찍힘
if detected_time is None:
detected_time = time.time()
else:
self.alert.config(text= "얼굴이 인식되었습니다. %f초 후 사진을 촬영합니다"%(2-(time.time()-detected_time)), fg="red")
if time.time() - detected_time >= 2:
self.alert.config(text= "얼굴이 인식되었습니다. %f초 후 사진을 촬영합니다"%(self.taking_time-(time.time()-detected_time)), fg="red")
if time.time() - detected_time >= self.taking_time:
self.thread.do_run = False
self.detected = True
self.alert.config(text= "얼굴을 등록해주세요. 올바르게 촬영되지 않았을 경우 다시촬영을 눌러주세요.", fg="blue")
......@@ -180,9 +183,9 @@ class Register(tk.Frame):
async with websockets.connect(self.uri) as websocket:
img = base64.b64encode(cv2.imencode('.jpg', self.face)[1]).decode()
send = json.dumps({'action': 'register',
'student_id':self.studentID.get(),
'student_name':self.studentName.get(),
'tensor': img})
'student_id': self.studentID.get(),
'student_name': self.studentName.get(),
'image': img})
await websocket.send(send)
recv = await websocket.recv()
data = json.loads(recv)
......
[verification_server]
host=localhost
port=3000
model=model/20200816-080621
model=models/20200816-080621
threshold=0.75
image_size=160
\ No newline at end of file
......
......@@ -11,7 +11,6 @@ import configparser
import logging
from datetime import datetime
lock = asyncio.Lock()
clients = set()
config = configparser.ConfigParser()
......@@ -27,23 +26,21 @@ image_size = int(config['verification_server']['image_size'])
threshold = float(config['verification_server']['threshold'])
print('connect to DB')
db = pymysql.connect(
attendance_db = pymysql.connect(
read_default_file="./DB.cnf"
)
async def register(websocket):
async with lock:
clients.add(websocket)
#remote_ip = websocket.remote_address[0]
#msg='[{ip}] connected'.format(ip=remote_ip)
#print(msg)
clients.add(websocket)
remote_ip = websocket.remote_address[0]
msg='[{ip}] connected'.format(ip=remote_ip)
print(msg)
async def unregister(websocket):
async with lock:
clients.remove(websocket)
#remote_ip = websocket.remote_address[0]
#msg='[{ip}] disconnected'.format(ip=remote_ip)
#print(msg)
clients.remove(websocket)
remote_ip = websocket.remote_address[0]
msg='[{ip}] disconnected'.format(ip=remote_ip)
print(msg)
def resize(image):
resized = cv2.resize(image, (image_size, image_size), interpolation=cv2.INTER_CUBIC)
......@@ -63,22 +60,20 @@ def get_distance(arr1, arr2):
async def thread(websocket, path):
await register(websocket)
cursor = db.cursor(pymysql.cursors.DictCursor)
cursor = attendance_db.cursor(pymysql.cursors.DictCursor)
remote_ip = websocket.remote_address[0]
try:
async for message in websocket:
data = json.loads(message)
remote_ip = websocket.remote_address[0]
msg='[{ip}] connected'.format(ip=remote_ip)
print(msg)
if data['action'] == 'register':
# log
msg='[{ip}] register face'.format(ip=remote_ip)
print(msg)
student_id = data['student_id']
student_name = data['student_name']
# 학생을 찾음
sql = "SELECT student_id FROM student WHERE student_id = %s;"
rows_count = cursor.execute(sql, (student_id))
# DB에 학생이 없으면 등록
if rows_count == 0:
sql = "INSERT INTO student(student_id, student_name) VALUES (%s, %s)"
......@@ -132,7 +127,8 @@ async def thread(websocket, path):
for row_data in result:
db_embedding = np.frombuffer(row_data['embedding'], dtype=np.float32)
db_embedding = db_embedding.reshape((1,512))
distance = await get_distance(embedding, db_embedding)
distance = get_distance(embedding, db_embedding)
print(distance)
if (distance < threshold):
verified_id = row_data['student_id']
break
......@@ -143,19 +139,22 @@ async def thread(websocket, path):
# 인증 성공
# 오늘 이미 출석 됐는지 확인
sql = "SELECT DATE(timestamp) FROM student_attendance WHERE (lecture_id=%s) AND (student_id=%s) AND (DATE(timestamp) = CURDATE());"
rows_count = cursor.execute(sql, ('0', verified_id))
cursor.execute(sql, ('0', verified_id))
# 출석 기록이 없는 경우에만
if rows_count == 0:
if cursor.rowcount == 0:
# 테이블 맨 뒤에 datetime attribute가 있음. 서버 시간 가져오게 default로 설정해둠.
sql = "INSERT INTO student_attendance(lecture_id, student_id, status) VALUES (%s, %s, %s)"
# TODO: attend / late 처리
cursor.execute(sql, ('0', verified_id, 'attend'))
attendance_db.commit()
sql = "SELECT student_name FROM student WHERE student_id = %s"
cursor.execute(sql, (verified_id))
row_data = cursor.fetchone()
verified_name = row_data['student_name']
# log 작성
msg='[{ip}] verification success {id}'.format(ip=remote_ip, id=verified_id)
print(msg)
send = json.dumps({'status': 'success', 'student_id': verified_id})
send = json.dumps({'status': 'attend', 'student_id': verified_id, 'student_name': verified_name})
else:
msg='[{ip}] verification failed: {id} is already verified'.format(ip=remote_ip, id=verified_id)
print(msg)
......