Showing
5 changed files
with
174 additions
and
10 deletions
client/client.py
0 → 100644
1 | +################################################## | ||
2 | +#1. webcam에서 얼굴을 인식합니다. | ||
3 | +#2. 얼굴일 확률이 97% 이상이고 영역이 15000 이상인 이미지를 서버에 전송 | ||
4 | +################################################## | ||
5 | +import tkinter as tk | ||
6 | +import tkinter.font | ||
7 | +import tkinter.messagebox | ||
8 | +import threading | ||
9 | +import torch | ||
10 | +import numpy as np | ||
11 | +import cv2 | ||
12 | +import asyncio | ||
13 | +import websockets | ||
14 | +import json | ||
15 | +import os | ||
16 | +import timeit | ||
17 | +import base64 | ||
18 | +import time | ||
19 | + | ||
20 | +from PIL import Image, ImageTk | ||
21 | +from io import BytesIO | ||
22 | +import requests | ||
23 | + | ||
24 | +from models.mtcnn import MTCNN | ||
25 | + | ||
26 | +device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') | ||
27 | +print('Running on device: {}'.format(device)) | ||
28 | + | ||
29 | +mtcnn = MTCNN(keep_all=True, post_process=True, device=device) | ||
30 | + | ||
31 | +uri = 'ws://169.56.95.131:8765' | ||
32 | + | ||
33 | +class Register(tk.Frame): | ||
34 | + def __init__(self, parent, *args, **kwargs): | ||
35 | + tk.Frame.__init__(self, parent, *args, **kwargs) | ||
36 | + | ||
37 | + # URI | ||
38 | + self.uri = 'ws://169.56.95.131:8765' | ||
39 | + | ||
40 | + # Pytorch Model | ||
41 | + self.device = device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') | ||
42 | + self.mtcnn = MTCNN(keep_all=True, device=device) | ||
43 | + | ||
44 | + # OpenCV | ||
45 | + self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) | ||
46 | + self.cam_width = 640 | ||
47 | + self.cam_height = 480 | ||
48 | + self.cap.set(3, self.cam_width) | ||
49 | + self.cap.set(4, self.cam_height) | ||
50 | + | ||
51 | + # tkinter GUI | ||
52 | + self.width = 740 | ||
53 | + self.height = 640 | ||
54 | + self.parent = parent | ||
55 | + self.parent.geometry("%dx%d+100+100" % (self.width, self.height)) | ||
56 | + self.pack() | ||
57 | + self.create_widgets() | ||
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 | + def create_widgets(self): | ||
65 | + image = np.zeros([self.cam_height, self.cam_width, 3], dtype=np.uint8) | ||
66 | + image = Image.fromarray(image) | ||
67 | + image = ImageTk.PhotoImage(image) | ||
68 | + | ||
69 | + font = tk.font.Font(family="맑은 고딕", size=15) | ||
70 | + | ||
71 | + self.alert = tk.Label(self, text="출석시스템", font=font) | ||
72 | + self.alert.grid(row=0, column=0, columnspan=20) | ||
73 | + self.label = tk.Label(self, image=image) | ||
74 | + self.label.grid(row=1, column=0, columnspan=20) | ||
75 | + | ||
76 | + self.log = tk.Text(self) | ||
77 | + self.log.grid(row=2, column=0, columnspan=20) | ||
78 | + | ||
79 | + | ||
80 | + self.quit = tk.Button(self, text="나가기", fg="red", command=self.stop) | ||
81 | + self.quit.grid(row=5, column=10) | ||
82 | + | ||
83 | + | ||
84 | + def detect_face(self, frame): | ||
85 | + results = self.mtcnn.detect(frame) | ||
86 | + faces = self.mtcnn(frame, return_prob = False) | ||
87 | + image_list = [] | ||
88 | + face_list = [] | ||
89 | + if results[1][0] == None: | ||
90 | + return [], [] | ||
91 | + for box, face, prob in zip(results[0], faces, results[1]): | ||
92 | + if prob < 0.97: | ||
93 | + continue | ||
94 | + # for debug | ||
95 | + # print('face detected. prob:', prob) | ||
96 | + x1, y1, x2, y2 = box | ||
97 | + if (x2-x1) * (y2-y1) < 15000: | ||
98 | + # 얼굴 해상도가 너무 낮으면 무시 | ||
99 | + self.alert.config(text= "카메라에 더 가까이 접근해주세요.", fg="red") | ||
100 | + self.alert.update() | ||
101 | + continue | ||
102 | + image = frame | ||
103 | + image_list.append(image) | ||
104 | + # MTCNN 데이터 저장 | ||
105 | + face_list.append(face.numpy()) | ||
106 | + return face_list, image_list | ||
107 | + | ||
108 | + def mainthread(self): | ||
109 | + t = threading.currentThread() | ||
110 | + asyncio.set_event_loop(self.event_loop) | ||
111 | + while getattr(t, "do_run", True): | ||
112 | + ret, frame = self.cap.read() | ||
113 | + | ||
114 | + # model에 이용하기 위해 convert | ||
115 | + converted = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | ||
116 | + face_list, image_list = self.detect_face(converted) | ||
117 | + | ||
118 | + # show image | ||
119 | + image = Image.fromarray(converted) | ||
120 | + image = ImageTk.PhotoImage(image) | ||
121 | + self.label.configure(image=image) | ||
122 | + self.label.image = image # kind of double buffering | ||
123 | + | ||
124 | + # 얼굴이 인식되면 요청 | ||
125 | + if face_list: | ||
126 | + self.event_loop.run_until_complete(self.send_face(face_list, image_list)) | ||
127 | + | ||
128 | + | ||
129 | + async def wait(self, n): | ||
130 | + await asyncio.sleep(n) | ||
131 | + | ||
132 | + async def send_face(self, face_list, image_list): | ||
133 | + try: | ||
134 | + async with websockets.connect(uri) as websocket: | ||
135 | + for face, image in zip(face_list, image_list): | ||
136 | + #type: np.float32 | ||
137 | + send = json.dumps({'action': 'verify', 'MTCNN': face.tolist()}) | ||
138 | + await websocket.send(send) | ||
139 | + recv = await websocket.recv() | ||
140 | + data = json.loads(recv) | ||
141 | + if data['status'] == 'success': | ||
142 | + # 성공 | ||
143 | + self.log.insert(tkinter.CURRENT, data['student_id'] + 'is attend') | ||
144 | + self.log.insert(tkinter.CURRENT, '\n') | ||
145 | + else: | ||
146 | + self.log.insert(tkinter.CURRENT, 'verification failed:' + data['status']) | ||
147 | + if data['status'] == 'failed': | ||
148 | + send = json.dumps({'action': 'save_image', 'image': image.tolist()}) | ||
149 | + except Exception as e: | ||
150 | + self.log.insert(tkinter.CURRENT, e) | ||
151 | + self.log.insert(tkinter.CURRENT, '\n') | ||
152 | + | ||
153 | + def stop(self): | ||
154 | + self.thread.do_run = False | ||
155 | + # self.thread.join() # there is a freeze problem | ||
156 | + self.event_loop.close() | ||
157 | + self.cap.release() | ||
158 | + self.parent.destroy() | ||
159 | + | ||
160 | + | ||
161 | +if __name__ == '__main__': | ||
162 | + root = tk.Tk() | ||
163 | + Register(root) | ||
164 | + root.mainloop() | ||
165 | + |
... | @@ -27,15 +27,6 @@ class Register(tk.Frame): | ... | @@ -27,15 +27,6 @@ class Register(tk.Frame): |
27 | def __init__(self, parent, *args, **kwargs): | 27 | def __init__(self, parent, *args, **kwargs): |
28 | tk.Frame.__init__(self, parent, *args, **kwargs) | 28 | tk.Frame.__init__(self, parent, *args, **kwargs) |
29 | 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 | 30 | # URI |
40 | self.uri = 'ws://169.56.95.131:8765' | 31 | self.uri = 'ws://169.56.95.131:8765' |
41 | 32 | ||
... | @@ -56,6 +47,14 @@ class Register(tk.Frame): | ... | @@ -56,6 +47,14 @@ class Register(tk.Frame): |
56 | self.face_list = [] | 47 | self.face_list = [] |
57 | self.image_list = [] | 48 | self.image_list = [] |
58 | 49 | ||
50 | + # tkinter GUI | ||
51 | + self.width = 740 | ||
52 | + self.height = 640 | ||
53 | + self.parent = parent | ||
54 | + self.parent.geometry("%dx%d+100+100" % (self.width, self.height)) | ||
55 | + self.pack() | ||
56 | + self.create_widgets() | ||
57 | + | ||
59 | # Event loop and Thread | 58 | # Event loop and Thread |
60 | # self.event_loop = asyncio.new_event_loop() | 59 | # self.event_loop = asyncio.new_event_loop() |
61 | self.thread = threading.Thread(target=self.mainthread) | 60 | self.thread = threading.Thread(target=self.mainthread) |
... | @@ -63,7 +62,7 @@ class Register(tk.Frame): | ... | @@ -63,7 +62,7 @@ class Register(tk.Frame): |
63 | 62 | ||
64 | 63 | ||
65 | def create_widgets(self): | 64 | def create_widgets(self): |
66 | - image = np.zeros([480,640,3], dtype=np.uint8) | 65 | + image = np.zeros([self.cam_height,self.cam_width,3], dtype=np.uint8) |
67 | image = Image.fromarray(image) | 66 | image = Image.fromarray(image) |
68 | image = ImageTk.PhotoImage(image) | 67 | image = ImageTk.PhotoImage(image) |
69 | 68 | ... | ... |
-
Please register or login to post a comment