Graduate

Make register GUI version

1 CREATE TABLE lecture( 1 CREATE TABLE lecture(
2 lecture_id VARCHAR(20) NOT NULL, 2 lecture_id VARCHAR(20) NOT NULL,
3 lecture_name VARCHAR(50), 3 lecture_name VARCHAR(50),
4 -lecture_room VARCHAR(50) NOT NULL,
5 PRIMARY KEY(lecture_id) 4 PRIMARY KEY(lecture_id)
6 ); 5 );
7 6
...@@ -32,7 +31,8 @@ FOREIGN KEY (lecture_id) REFERENCES lecture(lecture_id) ...@@ -32,7 +31,8 @@ FOREIGN KEY (lecture_id) REFERENCES lecture(lecture_id)
32 31
33 CREATE TABLE lecture_schedule( 32 CREATE TABLE lecture_schedule(
34 lecture_id VARCHAR(20) NOT NULL, 33 lecture_id VARCHAR(20) NOT NULL,
35 -lecture_day VARCHAR(20) NOT NULL, 34 +lecture_day TINYINT NOT NULL,
35 +lecture_room VARCHAR(50) NOT NULL,
36 lecture_start_time TIME NOT NULL, 36 lecture_start_time TIME NOT NULL,
37 lecture_end_time TIME NOT NULL, 37 lecture_end_time TIME NOT NULL,
38 FOREIGN KEY (lecture_id) REFERENCES lecture(lecture_id) 38 FOREIGN KEY (lecture_id) REFERENCES lecture(lecture_id)
......
...@@ -2,6 +2,10 @@ ...@@ -2,6 +2,10 @@
2 #1. webcam에서 얼굴을 인식합니다 2 #1. webcam에서 얼굴을 인식합니다
3 #2. 인식한 얼굴을 등록합니다 3 #2. 인식한 얼굴을 등록합니다
4 ################################################## 4 ##################################################
5 +import tkinter as tk
6 +import tkinter.font
7 +import tkinter.messagebox
8 +import threading
5 import torch 9 import torch
6 import numpy as np 10 import numpy as np
7 import cv2 11 import cv2
...@@ -11,76 +15,206 @@ import json ...@@ -11,76 +15,206 @@ import json
11 import os 15 import os
12 import timeit 16 import timeit
13 import base64 17 import base64
18 +import time
14 19
15 -from PIL import Image 20 +from PIL import Image, ImageTk
16 from io import BytesIO 21 from io import BytesIO
17 import requests 22 import requests
18 23
19 from models.mtcnn import MTCNN 24 from models.mtcnn import MTCNN
20 25
21 -device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
22 -print('Running on device: {}'.format(device))
23 -
24 -mtcnn = MTCNN(keep_all=True, device=device)
25 -
26 -uri = 'ws://169.56.95.131:8765'
27 -
28 -async def send_face(face_list, image_list):
29 - global uri
30 - async with websockets.connect(uri) as websocket:
31 - for face, image in zip(face_list, image_list):
32 - #type: np.float32
33 - send = json.dumps({'action': 'register', 'student_id':'2014101898', 'student_name':'김다솜', 'MTCNN': face.tolist()})
34 - await websocket.send(send)
35 - recv = await websocket.recv()
36 - data = json.loads(recv)
37 - if data['status'] == 'success':
38 - # 성공
39 - print(data['student_id'], 'is registered')
40 -
41 -def detect_face(frame):
42 - # If required, create a face detection pipeline using MTCNN:
43 - global mtcnn
44 - results = mtcnn.detect(frame)
45 - image_list = []
46 - if results[1][0] == None:
47 - return []
48 - for box, prob in zip(results[0], results[1]):
49 - if prob < 0.95:
50 - continue
51 - print('face detected. prob:', prob)
52 - x1, y1, x2, y2 = box
53 - image = frame[int(y1-10):int(y2+10), int(x1-10):int(x2+10)]
54 - image_list.append(image)
55 - return image_list
56 -
57 -def detect_face(frame):
58 - results = mtcnn.detect(frame)
59 - faces = mtcnn(frame, return_prob = False)
60 - image_list = []
61 - face_list = []
62 - if results[1][0] == None:
63 - return [], []
64 - for box, face, prob in zip(results[0], faces, results[1]):
65 - if prob < 0.97:
66 - continue
67 - print('face detected. prob:', prob)
68 - x1, y1, x2, y2 = box
69 - if (x2-x1) * (y2-y1) < 15000:
70 - # 얼굴 해상도가 너무 낮으면 무시
71 - continue
72 - # 얼굴 주변 ±3 영역 저장
73 - image = frame[int(y1-3):int(y2+3), int(x1-3):int(x2+3)]
74 - image_list.append(image)
75 - # MTCNN 데이터 저장
76 - face_list.append(face.numpy())
77 - return image_list, face_list
78 -
79 -cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
80 -cap.set(3, 720)
81 -cap.set(4, 480)
82 -ret, frame = cap.read()
83 -frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
84 -image_list, face_list = detect_face(frame)
85 -if face_list:
86 - asyncio.get_event_loop().run_until_complete(send_face(face_list, image_list))
...\ No newline at end of file ...\ No newline at end of file
26 +class Register(tk.Frame):
27 + def __init__(self, parent, *args, **kwargs):
28 + tk.Frame.__init__(self, parent, *args, **kwargs)
29 +
30 + # tkinter GUI
31 + self.width = 740
32 + self.height = 640
33 +
34 + self.parent = parent
35 + self.parent.geometry("%dx%d+100+100" % (self.width, self.height))
36 + self.pack()
37 + self.create_widgets()
38 +
39 + # URI
40 + self.uri = 'ws://169.56.95.131:8765'
41 +
42 + # Pytorch Model
43 + self.device = device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
44 + self.mtcnn = MTCNN(keep_all=True, device=device)
45 +
46 + # OpenCV
47 + self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
48 + self.cam_width = 640
49 + self.cam_height = 480
50 + self.cap.set(3, self.cam_width)
51 + self.cap.set(4, self.cam_height)
52 +
53 + # Application Function
54 + self.detecting_square = (200, 200)
55 + self.detected = False
56 + self.face_list = []
57 + self.image_list = []
58 +
59 + # Event loop and Thread
60 + # self.event_loop = asyncio.new_event_loop()
61 + self.thread = threading.Thread(target=self.mainthread)
62 + self.thread.start()
63 +
64 +
65 + def create_widgets(self):
66 + image = np.zeros([480,640,3], dtype=np.uint8)
67 + image = Image.fromarray(image)
68 + image = ImageTk.PhotoImage(image)
69 +
70 + font = tk.font.Font(family="맑은 고딕", size=15)
71 +
72 + self.alert = tk.Label(self, text="카메라를 정면으로 향하고 화면의 사각형에 얼굴을 맞춰주세요", font=font)
73 + self.alert.grid(row=0, column=0, columnspan=20)
74 + self.label = tk.Label(self, image=image)
75 + self.label.grid(row=1, column=0, columnspan=20)
76 +
77 + self.studentID = tk.StringVar()
78 + self.studentIdLabel = tk.Label(self, text="학번")
79 + self.studentIdLabel.grid(row=2, column=10)
80 + self.studentIdEntry = tk.Entry(self, width=20, textvariable=self.studentID)
81 + self.studentIdEntry.grid(row=2, column=11)
82 +
83 + self.studentName = tk.StringVar()
84 + self.studentNameLabel = tk.Label(self, text="이름")
85 + self.studentNameLabel.grid(row=3, column=10)
86 + self.studentNameEntry = tk.Entry(self, width=20, textvariable=self.studentName)
87 + self.studentNameEntry.grid(row=3, column=11)
88 +
89 + self.registerButton = tk.Button(self, text="등록", fg="blue", command=self.register_face)
90 + self.registerButton.grid(row=4, column=10)
91 +
92 + self.registerButton = tk.Button(self, text="다시촬영", command=self.restart)
93 + self.registerButton.grid(row=4, column=11)
94 +
95 + self.quit = tk.Button(self, text="나가기", fg="red", command=self.stop)
96 + self.quit.grid(row=5, column=10)
97 +
98 + def register_face(self):
99 + if not self.detected:
100 + tk.messagebox.showinfo("경고", "얼굴이 인식되지 않았습니다.")
101 + return
102 + asyncio.get_event_loop().run_until_complete(self.send_face())
103 +
104 +
105 + def restart(self):
106 + if not self.thread.isAlive():
107 + self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
108 + self.cap.set(3, self.cam_width)
109 + self.cap.set(4, self.cam_height)
110 +
111 + self.detected = False
112 + self.face_list = []
113 + self.image_list = []
114 +
115 + self.thread = threading.Thread(target=self.mainthread)
116 + self.thread.start()
117 +
118 + def detect_face(self, frame):
119 + results = self.mtcnn.detect(frame)
120 + faces = self.mtcnn(frame, return_prob = False)
121 + image_list = []
122 + face_list = []
123 + if results[1][0] == None:
124 + return [], []
125 + for box, face, prob in zip(results[0], faces, results[1]):
126 + if prob < 0.97:
127 + continue
128 + # for debug
129 + # print('face detected. prob:', prob)
130 + x1, y1, x2, y2 = box
131 + if (x2-x1) * (y2-y1) < 15000:
132 + # 얼굴 해상도가 너무 낮으면 무시
133 + self.alert.config(text= "인식된 얼굴이 너무 작습니다. 카메라에 더 가까이 접근해주세요.", fg="red")
134 + self.alert.update()
135 + continue
136 + image = frame
137 + image_list.append(image)
138 + # MTCNN 데이터 저장
139 + face_list.append(face.numpy())
140 + return face_list, image_list
141 +
142 + def mainthread(self):
143 + t = threading.currentThread()
144 + #asyncio.set_event_loop(self.event_loop)
145 + x1 = int(self.cam_width / 2 - self.detecting_square[0] / 2)
146 + x2 = int(self.cam_width / 2 + self.detecting_square[0] / 2)
147 + y1 = int(self.cam_height / 2 - self.detecting_square[1] / 2)
148 + y2 = int(self.cam_height / 2 + self.detecting_square[1] / 2)
149 + detected_time = None
150 + while getattr(t, "do_run", True):
151 + ret, frame = self.cap.read()
152 +
153 + # model에 이용하기 위해 convert
154 + converted = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
155 +
156 + # 사각형 영역만 검사 (속도 차이 큼)
157 + face_list, image_list = self.detect_face(converted[y1:y2, x1:x2])
158 +
159 + # 얼굴이 인식된 경우 파란색 사각형을 띄움
160 + if face_list:
161 + frame = cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 0, 0), 3)
162 + else:
163 + frame = cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 3)
164 +
165 + # show image
166 + converted = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
167 + image = Image.fromarray(converted)
168 + image = ImageTk.PhotoImage(image)
169 + self.label.configure(image=image)
170 + self.label.image = image # kind of double buffering
171 +
172 + # 얼굴이 인식되면 멤버함수에 넣음
173 + if face_list:
174 + self.face_list = face_list
175 + self.image_list = image_list
176 + # 2초 후에 사진이 찍힘
177 + if detected_time is None:
178 + detected_time = time.time()
179 + else:
180 + self.alert.config(text= "얼굴이 인식되었습니다. %f초 후 사진을 촬영합니다"%(2-(time.time()-detected_time)), fg="red")
181 + if time.time() - detected_time >= 2:
182 + self.thread.do_run = False
183 + self.detected = True
184 + self.alert.config(text= "얼굴을 등록해주세요. 올바르게 촬영되지 않았을 경우 다시촬영을 눌러주세요.", fg="blue")
185 + else:
186 + detected_time = None
187 + self.face_list = []
188 + self.image_list = []
189 +
190 +
191 + async def wait(self, n):
192 + await asyncio.sleep(n)
193 +
194 + async def send_face(self):
195 + try:
196 + async with websockets.connect(self.uri) as websocket:
197 + for face, image in zip(self.face_list, self.image_list):
198 + #type: np.float32
199 + send = json.dumps({'action': 'register', 'student_id':self.studentID, 'student_name':self.studentName, 'MTCNN': face.tolist()})
200 + await websocket.send(send)
201 + recv = await websocket.recv()
202 + data = json.loads(recv)
203 + if data['status'] == 'success':
204 + tk.messagebox.showinfo("등록완료", self.studentID.get() + ' ' + self.studentName.get())
205 + except Exception as e:
206 + tk.messagebox.showinfo("등록실패", e)
207 +
208 + def stop(self):
209 + self.thread.do_run = False
210 + # self.thread.join() # there is a freeze problem
211 + # self.event_loop.close()
212 + self.cap.release()
213 + self.parent.destroy()
214 +
215 +
216 +if __name__ == '__main__':
217 + root = tk.Tk()
218 + Register(root)
219 + root.mainloop()
220 +
......