Showing
2 changed files
with
1140 additions
and
0 deletions
source/detect_mask_video_test3.py
0 → 100644
1 | +# USAGE | ||
2 | +# python detect_mask_video.py | ||
3 | + | ||
4 | +# import the necessary packages | ||
5 | +from tensorflow.keras.applications.mobilenet_v2 import preprocess_input | ||
6 | +from tensorflow.keras.preprocessing.image import img_to_array | ||
7 | +from tensorflow.keras.models import load_model | ||
8 | +import numpy as np | ||
9 | +import argparse | ||
10 | +import os | ||
11 | +import cv2 | ||
12 | +import sys | ||
13 | +from PyQt5 import QtCore | ||
14 | +from PyQt5 import QtWidgets | ||
15 | +from PyQt5 import QtGui | ||
16 | +from PyQt5 import QtTest | ||
17 | +import pyaudio | ||
18 | +import wave | ||
19 | +import requests | ||
20 | + | ||
21 | +#Audio | ||
22 | +# Record Audio의 startRecording 메서드에서 input_device_index는 기기마다 다름. | ||
23 | +FORMAT = pyaudio.paInt16 | ||
24 | +CHANNELS = 1 | ||
25 | +RATE = 16000 | ||
26 | +CHUNK = 1024 | ||
27 | +MAX_RECORD_SECONDS = 30 | ||
28 | +WAVE_OUTPUT_FILENAME = "audiofile\\file.wav" | ||
29 | +#URL | ||
30 | +URL = 'http://163.180.146.68:7777/{}' | ||
31 | +#SpeakerRecognition | ||
32 | +THRESHOLD = 0.8 | ||
33 | + | ||
34 | +class ShowVideo(QtCore.QObject): | ||
35 | + flag_detect_mask = True | ||
36 | + run_video = True | ||
37 | + | ||
38 | + camera = cv2.VideoCapture(0) # 연결된 영상장치 index, 기본은 0 | ||
39 | + | ||
40 | + ret, image = camera.read() # 2개의 값 리턴, 첫 번째는 프레임 읽음여부, 두 번째는 프레임 자체 | ||
41 | + height, width = image.shape[:2] | ||
42 | + | ||
43 | + VideoSignal1 = QtCore.pyqtSignal(QtGui.QImage) # VideoSignal1이라는 사용자 정의 시그널 생성 | ||
44 | + | ||
45 | + def __init__(self, parent=None): | ||
46 | + super(ShowVideo, self).__init__(parent) | ||
47 | + | ||
48 | + @QtCore.pyqtSlot() | ||
49 | + def startVideo(self, faceNet, maskNet): | ||
50 | + global image | ||
51 | + | ||
52 | + run_video = True | ||
53 | + self.flag_detect_mask = True | ||
54 | + while run_video: | ||
55 | + ret, image = self.camera.read() | ||
56 | + | ||
57 | + # detect faces in the frame and determine if they are wearing a | ||
58 | + # face mask or not | ||
59 | + (locs, preds) = detect_and_predict_mask(image, faceNet, maskNet) | ||
60 | + | ||
61 | + QtWidgets.QApplication.processEvents() | ||
62 | + if self.flag_detect_mask: | ||
63 | + frame = image | ||
64 | + # loop over the detected face locations and their corresponding | ||
65 | + # locations | ||
66 | + for (box, pred) in zip(locs, preds): | ||
67 | + # unpack the bounding box and predictions | ||
68 | + (startX, startY, endX, endY) = box | ||
69 | + (mask, withoutMask) = pred | ||
70 | + | ||
71 | + # determine the class label and color we'll use to draw | ||
72 | + # the bounding box and text | ||
73 | + label = "Mask" if mask > withoutMask else "No Mask" # 박스 상단 출력 string | ||
74 | + color = (0, 255, 0) if label == "Mask" else (0, 0, 255) | ||
75 | + | ||
76 | + # include the probability in the label | ||
77 | + label = "{}: {:.2f}%".format(label, max(mask, withoutMask) * 100) | ||
78 | + | ||
79 | + # display the label and bounding box rectangle on the output | ||
80 | + # frame | ||
81 | + cv2.putText(frame, label, (startX, startY - 10), # label에 string들어감 | ||
82 | + cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2) | ||
83 | + cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2) | ||
84 | + image = frame | ||
85 | + ### | ||
86 | + color_swapped_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | ||
87 | + | ||
88 | + qt_image1 = QtGui.QImage(color_swapped_image.data, | ||
89 | + self.width, | ||
90 | + self.height, | ||
91 | + color_swapped_image.strides[0], | ||
92 | + QtGui.QImage.Format_RGB888) | ||
93 | + self.VideoSignal1.emit(qt_image1) | ||
94 | + | ||
95 | + loop = QtCore.QEventLoop() | ||
96 | + QtCore.QTimer.singleShot(25, loop.quit) # 25 ms | ||
97 | + loop.exec_() | ||
98 | + | ||
99 | + @QtCore.pyqtSlot() | ||
100 | + def maskdetectionoff(self): | ||
101 | + self.flag_detect_mask = False | ||
102 | + | ||
103 | + | ||
104 | +class ImageViewer(QtWidgets.QWidget): | ||
105 | + def __init__(self, parent=None): | ||
106 | + super(ImageViewer, self).__init__(parent) | ||
107 | + self.image = QtGui.QImage() | ||
108 | + self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent) | ||
109 | + | ||
110 | + def paintEvent(self, event): | ||
111 | + painter = QtGui.QPainter(self) | ||
112 | + painter.drawImage(0, 0, self.image) | ||
113 | + self.image = QtGui.QImage() | ||
114 | + | ||
115 | + def initUI(self): | ||
116 | + self.setWindowTitle('Webcam') | ||
117 | + | ||
118 | + @QtCore.pyqtSlot(QtGui.QImage) | ||
119 | + def setImage(self, image): | ||
120 | + if image.isNull(): | ||
121 | + print("Viewer Dropped frame!") | ||
122 | + | ||
123 | + self.image = image | ||
124 | + if image.size() != self.size(): | ||
125 | + self.setFixedSize(image.size()) | ||
126 | + self.update() | ||
127 | + | ||
128 | + | ||
129 | +def detect_and_predict_mask(frame, faceNet, maskNet): | ||
130 | + # grab the dimensions of the frame and then construct a blob | ||
131 | + # from it | ||
132 | + (h, w) = frame.shape[:2] | ||
133 | + blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), | ||
134 | + (104.0, 177.0, 123.0)) | ||
135 | + | ||
136 | + # pass the blob through the network and obtain the face detections | ||
137 | + faceNet.setInput(blob) | ||
138 | + detections = faceNet.forward() | ||
139 | + | ||
140 | + # initialize our list of faces, their corresponding locations, | ||
141 | + # and the list of predictions from our face mask network | ||
142 | + faces = [] | ||
143 | + locs = [] | ||
144 | + preds = [] | ||
145 | + | ||
146 | + # loop over the detections | ||
147 | + for i in range(0, detections.shape[2]): | ||
148 | + # extract the confidence (i.e., probability) associated with | ||
149 | + # the detection | ||
150 | + confidence = detections[0, 0, i, 2] | ||
151 | + | ||
152 | + # filter out weak detections by ensuring the confidence is | ||
153 | + # greater than the minimum confidence | ||
154 | + if confidence > args["confidence"]: | ||
155 | + # compute the (x, y)-coordinates of the bounding box for | ||
156 | + # the object | ||
157 | + box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) | ||
158 | + (startX, startY, endX, endY) = box.astype("int") | ||
159 | + | ||
160 | + # ensure the bounding boxes fall within the dimensions of | ||
161 | + # the frame | ||
162 | + (startX, startY) = (max(0, startX), max(0, startY)) | ||
163 | + (endX, endY) = (min(w - 1, endX), min(h - 1, endY)) | ||
164 | + | ||
165 | + # extract the face ROI, convert it from BGR to RGB channel | ||
166 | + # ordering, resize it to 224x224, and preprocess it | ||
167 | + face = frame[startY:endY, startX:endX] | ||
168 | + face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB) | ||
169 | + face = cv2.resize(face, (224, 224)) | ||
170 | + face = img_to_array(face) | ||
171 | + face = preprocess_input(face) | ||
172 | + | ||
173 | + # add the face and bounding boxes to their respective | ||
174 | + # lists | ||
175 | + faces.append(face) | ||
176 | + locs.append((startX, startY, endX, endY)) | ||
177 | + | ||
178 | + # only make a predictions if at least one face was detected | ||
179 | + if len(faces) > 0: | ||
180 | + # for faster inference we'll make batch predictions on *all* | ||
181 | + # faces at the same time rather than one-by-one predictions | ||
182 | + # in the above `for` loop | ||
183 | + faces = np.array(faces, dtype="float32") | ||
184 | + preds = maskNet.predict(faces, batch_size=32) | ||
185 | + | ||
186 | + # return a 2-tuple of the face locations and their corresponding | ||
187 | + # locations | ||
188 | + return (locs, preds) | ||
189 | + | ||
190 | + | ||
191 | +class SpeakerRecognition(QtWidgets.QWidget): | ||
192 | + verification_url = URL.format('verification') | ||
193 | + identification_url = URL.format('identification') | ||
194 | + | ||
195 | + def __init__(self, parent=None): | ||
196 | + super(SpeakerRecognition, self).__init__(parent) | ||
197 | + self.initUI() | ||
198 | + | ||
199 | + def initUI(self): | ||
200 | + self.label_1_1 = QtWidgets.QLabel('Result Message: ', self) | ||
201 | + self.label_1_2 = QtWidgets.QLabel('', self) | ||
202 | + self.push_button5 =QtWidgets.QPushButton('Authenticate', self) | ||
203 | + self.push_button5.clicked.connect(self.doAction) | ||
204 | + | ||
205 | + def verification(self, speaker): | ||
206 | + try: | ||
207 | + with open(WAVE_OUTPUT_FILENAME, 'rb') as file_opened: | ||
208 | + files = {'file': file_opened} | ||
209 | + data = {'enroll_speaker': speaker} | ||
210 | + r = requests.post(self.verification_url, files=files, data=data) | ||
211 | + print(r.text) | ||
212 | + return r.text | ||
213 | + except FileNotFoundError: | ||
214 | + return False | ||
215 | + | ||
216 | + def identification(self): | ||
217 | + try: | ||
218 | + with open(WAVE_OUTPUT_FILENAME, 'rb') as file_opened: | ||
219 | + files = {'file': file_opened} | ||
220 | + r = requests.post(self.identification_url, files=files) | ||
221 | + print(r.text) | ||
222 | + return r.text | ||
223 | + except FileNotFoundError: | ||
224 | + return False | ||
225 | + | ||
226 | + def recognition(self): | ||
227 | + speaker = self.identification() | ||
228 | + if speaker == False: | ||
229 | + print('Record voice first!') | ||
230 | + return False | ||
231 | + | ||
232 | + percentage = self.verification(speaker) | ||
233 | + print(speaker, percentage) | ||
234 | + | ||
235 | + if float(percentage) >= THRESHOLD: | ||
236 | + result = '승인! 등록된 화자입니다.' | ||
237 | + #result = speaker | ||
238 | + else: | ||
239 | + result = '등록되지 않은 화자입니다!' | ||
240 | + return result | ||
241 | + | ||
242 | + @QtCore.pyqtSlot() | ||
243 | + def doAction(self): | ||
244 | + recog = self.recognition() | ||
245 | + if recog == False: | ||
246 | + self.label_1_2.setText('Voice not recorded, record voice first!') | ||
247 | + else: | ||
248 | + self.label_1_2.setText(recog) | ||
249 | + | ||
250 | +class RecordAudio(QtCore.QObject): | ||
251 | + isrecording = False | ||
252 | + frames = [] | ||
253 | + | ||
254 | + def __init__(self, parent=None): | ||
255 | + super(RecordAudio, self).__init__(parent) | ||
256 | + | ||
257 | + @QtCore.pyqtSlot() | ||
258 | + def startRecording(self): | ||
259 | + # start Recording | ||
260 | + self.audio = pyaudio.PyAudio() | ||
261 | + self.stream = self.audio.open(format=pyaudio.paInt16, | ||
262 | + channels=CHANNELS, | ||
263 | + rate=RATE, | ||
264 | + input=True, | ||
265 | + input_device_index=1, # 기기마다 마이크 인덱스 다름 | ||
266 | + frames_per_buffer=CHUNK) | ||
267 | + self.isrecording = True | ||
268 | + print("recording...") | ||
269 | + | ||
270 | + # frames = [] | ||
271 | + self.frames.clear() | ||
272 | + | ||
273 | + for i in range(0, int(RATE / CHUNK * MAX_RECORD_SECONDS)): | ||
274 | + QtWidgets.QApplication.processEvents() | ||
275 | + if self.isrecording: | ||
276 | + data = self.stream.read(CHUNK) | ||
277 | + self.frames.append(data) | ||
278 | + else: | ||
279 | + print("Stopped recording") | ||
280 | + break | ||
281 | + print("finished recording") | ||
282 | + | ||
283 | + # stop Recording | ||
284 | + self.stream.stop_stream() | ||
285 | + self.stream.close() | ||
286 | + self.audio.terminate() | ||
287 | + waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb') | ||
288 | + waveFile.setnchannels(CHANNELS) | ||
289 | + waveFile.setsampwidth(self.audio.get_sample_size(FORMAT)) | ||
290 | + waveFile.setframerate(RATE) | ||
291 | + waveFile.writeframes(b''.join(self.frames)) | ||
292 | + waveFile.close() | ||
293 | + self.frames.clear() | ||
294 | + | ||
295 | + def stopRecording(self): | ||
296 | + print("stop called") | ||
297 | + self.isrecording = False | ||
298 | + | ||
299 | + def switch(self): | ||
300 | + if self.isrecording: | ||
301 | + QtTest.QTest.qWait(1 * 1000) | ||
302 | + self.stopRecording() | ||
303 | + else: | ||
304 | + self.startRecording() | ||
305 | + | ||
306 | + | ||
307 | +class RecordViewer(QtWidgets.QWidget): | ||
308 | + def __init__(self, parent=None): | ||
309 | + super(RecordViewer, self).__init__(parent) | ||
310 | + self.initUI() | ||
311 | + | ||
312 | + def initUI(self): | ||
313 | + self.pbar = QtWidgets.QProgressBar(self) | ||
314 | + self.pbar.setFixedWidth(400) | ||
315 | + self.pbar.setMaximum(MAX_RECORD_SECONDS) | ||
316 | + self.pbar.setAlignment(QtCore.Qt.AlignCenter) | ||
317 | + | ||
318 | + self.push_button3 = QtWidgets.QPushButton('Start Audio Record', self) | ||
319 | + self.push_button3.clicked.connect(self.doAction) | ||
320 | + | ||
321 | + self.timer = QtCore.QBasicTimer() | ||
322 | + self.step = 0 | ||
323 | + | ||
324 | + def timerEvent(self, e): | ||
325 | + if self.step >= MAX_RECORD_SECONDS: | ||
326 | + self.timer.stop() | ||
327 | + self.push_button3.setText("Restart") | ||
328 | + return | ||
329 | + self.step = self.step + 1 | ||
330 | + self.pbar.setValue(self.step) | ||
331 | + self.pbar.setFormat("%d sec" % self.step) | ||
332 | + | ||
333 | + @QtCore.pyqtSlot() | ||
334 | + def doAction(self): | ||
335 | + if self.timer.isActive(): | ||
336 | + self.timer.stop() | ||
337 | + self.push_button3.setText("Restart") | ||
338 | + else: | ||
339 | + self.pbar.reset() | ||
340 | + self.step = 0 | ||
341 | + self.timer.start(1000, self) # 1000/1000초마다 timer실행 | ||
342 | + self.push_button3.setText("Stop") | ||
343 | + | ||
344 | + | ||
345 | +if __name__ == '__main__': | ||
346 | + # construct the argument parser and parse the arguments | ||
347 | + ap = argparse.ArgumentParser() | ||
348 | + ap.add_argument("-f", "--face", type=str, default="face_detector", | ||
349 | + help="path to face detector model directory") | ||
350 | + ap.add_argument("-m", "--model", type=str, default="mask_detector.model", | ||
351 | + help="path to trained face mask detector model") | ||
352 | + ap.add_argument("-c", "--confidence", type=float, default=0.5, | ||
353 | + help="minimum probability to filter weak detections") | ||
354 | + args = vars(ap.parse_args()) | ||
355 | + | ||
356 | + # load our serialized face detector model from disk | ||
357 | + print("[INFO] loading face detector model...") | ||
358 | + prototxtPath = os.path.sep.join([args["face"], "deploy.prototxt"]) | ||
359 | + weightsPath = os.path.sep.join([args["face"], | ||
360 | + "res10_300x300_ssd_iter_140000.caffemodel"]) | ||
361 | + faceNet = cv2.dnn.readNet(prototxtPath, weightsPath) | ||
362 | + | ||
363 | + # load the face mask detector model from disk | ||
364 | + print("[INFO] loading face mask detector model...") | ||
365 | + maskNet = load_model(args["model"]) | ||
366 | + | ||
367 | + app = QtWidgets.QApplication(sys.argv) # app 생성 | ||
368 | + | ||
369 | + thread = QtCore.QThread() | ||
370 | + thread.start() | ||
371 | + vid = ShowVideo() | ||
372 | + vid.moveToThread(thread) | ||
373 | + | ||
374 | + # test | ||
375 | + thread2 = QtCore.QThread() | ||
376 | + thread2.start() | ||
377 | + aud = RecordViewer() | ||
378 | + aud.moveToThread(thread2) | ||
379 | + | ||
380 | + # test | ||
381 | + thread3 = QtCore.QThread() | ||
382 | + thread3.start() | ||
383 | + mic = RecordAudio() | ||
384 | + mic.moveToThread(thread3) | ||
385 | + | ||
386 | + # test | ||
387 | + thread4 = QtCore.QThread() | ||
388 | + thread4.start() | ||
389 | + sr = SpeakerRecognition() | ||
390 | + sr.moveToThread(thread4) | ||
391 | + | ||
392 | + image_viewer1 = ImageViewer() | ||
393 | + | ||
394 | + vid.VideoSignal1.connect(image_viewer1.setImage) | ||
395 | + | ||
396 | + push_button1 = QtWidgets.QPushButton('Start Mask Detection') | ||
397 | + push_button2 = QtWidgets.QPushButton('Mask Detection Off') | ||
398 | + push_button4 = QtWidgets.QPushButton('Close') | ||
399 | + | ||
400 | + push_button1.clicked.connect(lambda: vid.startVideo(faceNet, maskNet)) | ||
401 | + push_button2.clicked.connect(vid.maskdetectionoff) | ||
402 | + aud.push_button3.clicked.connect(mic.switch) | ||
403 | + push_button4.clicked.connect(sys.exit) | ||
404 | + | ||
405 | + L_groupBox = QtWidgets.QGroupBox("Mask Detection") | ||
406 | + LR_layout = QtWidgets.QVBoxLayout() | ||
407 | + LR_layout.addWidget(push_button1) | ||
408 | + LR_layout.addWidget(push_button2) | ||
409 | + LR_layout.addStretch(1) | ||
410 | + | ||
411 | + L_horizontal_layout1 = QtWidgets.QHBoxLayout() | ||
412 | + L_horizontal_layout1.addWidget(image_viewer1) | ||
413 | + L_horizontal_layout1.addLayout(LR_layout) | ||
414 | + L_groupBox.setLayout(L_horizontal_layout1) | ||
415 | + | ||
416 | + RU_groupBox = QtWidgets.QGroupBox("Voice Record") | ||
417 | + pbar_layout = QtWidgets.QHBoxLayout() | ||
418 | + pbar_layout.addWidget(aud.pbar) | ||
419 | + pbar_layout.addStretch(1) | ||
420 | + | ||
421 | + RL_label1 = QtWidgets.QLabel() | ||
422 | + RL_label1.setText("Max Record Time: 30 sec") | ||
423 | + RL_label2 = QtWidgets.QLabel() | ||
424 | + RL_label2.setText("Press Start/Restart to begin recording") | ||
425 | + | ||
426 | + RL_layout = QtWidgets.QVBoxLayout() | ||
427 | + RL_layout.addLayout(pbar_layout) | ||
428 | + RL_layout.addWidget(RL_label1) | ||
429 | + RL_layout.addWidget(RL_label2) | ||
430 | + RL_layout.addStretch(1) | ||
431 | + | ||
432 | + push_button3_layout = QtWidgets.QHBoxLayout() | ||
433 | + push_button3_layout.addWidget(aud.push_button3) | ||
434 | + # push_button3_layout.addStretch(1) | ||
435 | + | ||
436 | + # close_layout = QtWidgets.QHBoxLayout() | ||
437 | + # close_layout.addWidget(push_button4) | ||
438 | + | ||
439 | + RR_layout = QtWidgets.QVBoxLayout() | ||
440 | + RR_layout.addLayout(push_button3_layout) | ||
441 | + RR_layout.addStretch(1) | ||
442 | + # RR_layout.addLayout(close_layout) | ||
443 | + | ||
444 | + R_horizontal_layout2 = QtWidgets.QHBoxLayout() | ||
445 | + R_horizontal_layout2.addLayout(RL_layout) | ||
446 | + R_horizontal_layout2.addLayout(RR_layout) | ||
447 | + RU_groupBox.setLayout(R_horizontal_layout2) | ||
448 | + | ||
449 | + | ||
450 | + RD_groupBox = QtWidgets.QGroupBox("Speaker Recognition") | ||
451 | + | ||
452 | + label_1_layout = QtWidgets.QHBoxLayout() | ||
453 | + label_1_layout.addWidget(sr.label_1_1) | ||
454 | + label_1_layout.addWidget(sr.label_1_2) | ||
455 | + label_1_layout.addStretch(1) | ||
456 | + | ||
457 | + RDL_layout = QtWidgets.QVBoxLayout() | ||
458 | + RDL_layout.addLayout(label_1_layout) | ||
459 | + RDL_layout.addStretch(1) | ||
460 | + | ||
461 | + push_button5_layout = QtWidgets.QHBoxLayout() | ||
462 | + push_button5_layout.addWidget(sr.push_button5) | ||
463 | + | ||
464 | + close_layout = QtWidgets.QHBoxLayout() | ||
465 | + close_layout.addWidget(push_button4) | ||
466 | + | ||
467 | + RDR_layout = QtWidgets.QVBoxLayout() | ||
468 | + RDR_layout.addLayout(push_button5_layout) | ||
469 | + RDR_layout.addStretch(1) | ||
470 | + RDR_layout.addLayout(close_layout) | ||
471 | + | ||
472 | + RD_horizontal_layout = QtWidgets.QHBoxLayout() | ||
473 | + RD_horizontal_layout.addLayout(RDL_layout) | ||
474 | + RD_horizontal_layout.addLayout(RDR_layout) | ||
475 | + RD_groupBox.setLayout(RD_horizontal_layout) | ||
476 | + | ||
477 | + R_layout = QtWidgets.QVBoxLayout() | ||
478 | + R_layout.addWidget(RU_groupBox) | ||
479 | + R_layout.addWidget(RD_groupBox) | ||
480 | + | ||
481 | + layout = QtWidgets.QHBoxLayout() | ||
482 | + layout.addWidget(L_groupBox) | ||
483 | + layout.addLayout(R_layout) | ||
484 | + | ||
485 | + layout_widget = QtWidgets.QWidget() | ||
486 | + layout_widget.setLayout(layout) | ||
487 | + | ||
488 | + main_window = QtWidgets.QMainWindow() | ||
489 | + main_window.setGeometry(150, 150, 500, 500) # test | ||
490 | + main_window.setCentralWidget(layout_widget) | ||
491 | + main_window.setWindowTitle('마스크 디텍션 및 화자 식별을 통한 입출입 시스템') # main window 제목 | ||
492 | + main_window.show() | ||
493 | + sys.exit(app.exec_()) # 프로그램 대기상태 유지, 무한루프 |
source/detect_mask_video_test4.py
0 → 100644
1 | +# USAGE | ||
2 | +# python detect_mask_video.py | ||
3 | + | ||
4 | +# import the necessary packages | ||
5 | +from tensorflow.keras.applications.mobilenet_v2 import preprocess_input | ||
6 | +from tensorflow.keras.preprocessing.image import img_to_array | ||
7 | +from tensorflow.keras.models import load_model | ||
8 | +import numpy as np | ||
9 | +import argparse | ||
10 | +import os | ||
11 | +import cv2 | ||
12 | +import sys | ||
13 | +from PyQt5 import QtCore | ||
14 | +from PyQt5 import QtWidgets | ||
15 | +from PyQt5 import QtGui | ||
16 | +from PyQt5 import QtTest | ||
17 | +import pyaudio | ||
18 | +import wave | ||
19 | +import requests | ||
20 | + | ||
21 | +#Audio | ||
22 | +# Record Audio의 startRecording 메서드에서 input_device_index는 기기마다 다름. | ||
23 | +FORMAT = pyaudio.paInt16 | ||
24 | +CHANNELS = 1 | ||
25 | +RATE = 16000 | ||
26 | +CHUNK = 1024 | ||
27 | +MAX_RECORD_SECONDS = 30 | ||
28 | +WAVE_OUTPUT_FILENAME = "saved_voice\\audiofile\\file.wav" | ||
29 | +WAVE_ENROLL_FILENAME = "saved_voice\\enrollfile\\file.wav" | ||
30 | +#URL | ||
31 | +URL = 'http://163.180.146.68:7777/{}' | ||
32 | +#SpeakerRecognition | ||
33 | +THRESHOLD = 0.8 | ||
34 | +SPEAKER_ID = 'NA' | ||
35 | + | ||
36 | +class ShowVideo(QtCore.QObject): | ||
37 | + flag_detect_mask = True | ||
38 | + run_video = True | ||
39 | + | ||
40 | + camera = cv2.VideoCapture(0) # 연결된 영상장치 index, 기본은 0 | ||
41 | + | ||
42 | + ret, image = camera.read() # 2개의 값 리턴, 첫 번째는 프레임 읽음여부, 두 번째는 프레임 자체 | ||
43 | + height, width = image.shape[:2] | ||
44 | + | ||
45 | + VideoSignal1 = QtCore.pyqtSignal(QtGui.QImage) # VideoSignal1이라는 사용자 정의 시그널 생성 | ||
46 | + | ||
47 | + def __init__(self, parent=None): | ||
48 | + super(ShowVideo, self).__init__(parent) | ||
49 | + | ||
50 | + @QtCore.pyqtSlot() | ||
51 | + def startVideo(self, faceNet, maskNet): | ||
52 | + global image | ||
53 | + | ||
54 | + run_video = True | ||
55 | + self.flag_detect_mask = True | ||
56 | + while run_video: | ||
57 | + ret, image = self.camera.read() | ||
58 | + | ||
59 | + # detect faces in the frame and determine if they are wearing a | ||
60 | + # face mask or not | ||
61 | + QtWidgets.QApplication.processEvents() | ||
62 | + if self.flag_detect_mask: | ||
63 | + (locs, preds) = detect_and_predict_mask(image, faceNet, maskNet) | ||
64 | + | ||
65 | + # QtWidgets.QApplication.processEvents() | ||
66 | + # if self.flag_detect_mask: | ||
67 | + frame = image | ||
68 | + # loop over the detected face locations and their corresponding | ||
69 | + # locations | ||
70 | + for (box, pred) in zip(locs, preds): | ||
71 | + # unpack the bounding box and predictions | ||
72 | + (startX, startY, endX, endY) = box | ||
73 | + (mask, withoutMask) = pred | ||
74 | + | ||
75 | + # determine the class label and color we'll use to draw | ||
76 | + # the bounding box and text | ||
77 | + label = "Mask" if mask > withoutMask else "No Mask" # 박스 상단 출력 string | ||
78 | + color = (0, 255, 0) if label == "Mask" else (0, 0, 255) | ||
79 | + | ||
80 | + # include the probability in the label | ||
81 | + label = "{}: {:.2f}%".format(label, max(mask, withoutMask) * 100) | ||
82 | + | ||
83 | + # display the label and bounding box rectangle on the output | ||
84 | + # frame | ||
85 | + cv2.putText(frame, label, (startX, startY - 10), # label에 string들어감 | ||
86 | + cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2) | ||
87 | + cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2) | ||
88 | + image = frame | ||
89 | + ### | ||
90 | + color_swapped_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) | ||
91 | + | ||
92 | + qt_image1 = QtGui.QImage(color_swapped_image.data, | ||
93 | + self.width, | ||
94 | + self.height, | ||
95 | + color_swapped_image.strides[0], | ||
96 | + QtGui.QImage.Format_RGB888) | ||
97 | + self.VideoSignal1.emit(qt_image1) | ||
98 | + | ||
99 | + loop = QtCore.QEventLoop() | ||
100 | + QtCore.QTimer.singleShot(25, loop.quit) # 25 ms | ||
101 | + loop.exec_() | ||
102 | + | ||
103 | + @QtCore.pyqtSlot() | ||
104 | + def maskdetectionoff(self): | ||
105 | + self.flag_detect_mask = False | ||
106 | + | ||
107 | + | ||
108 | +class ImageViewer(QtWidgets.QWidget): | ||
109 | + def __init__(self, parent=None): | ||
110 | + super(ImageViewer, self).__init__(parent) | ||
111 | + self.image = QtGui.QImage() | ||
112 | + self.setAttribute(QtCore.Qt.WA_OpaquePaintEvent) | ||
113 | + | ||
114 | + def paintEvent(self, event): | ||
115 | + painter = QtGui.QPainter(self) | ||
116 | + painter.drawImage(0, 0, self.image) | ||
117 | + self.image = QtGui.QImage() | ||
118 | + | ||
119 | + def initUI(self): | ||
120 | + self.setWindowTitle('Webcam') | ||
121 | + | ||
122 | + @QtCore.pyqtSlot(QtGui.QImage) | ||
123 | + def setImage(self, image): | ||
124 | + if image.isNull(): | ||
125 | + print("Viewer Dropped frame!") | ||
126 | + | ||
127 | + self.image = image | ||
128 | + if image.size() != self.size(): | ||
129 | + self.setFixedSize(image.size()) | ||
130 | + self.update() | ||
131 | + | ||
132 | + | ||
133 | +def detect_and_predict_mask(frame, faceNet, maskNet): | ||
134 | + # grab the dimensions of the frame and then construct a blob | ||
135 | + # from it | ||
136 | + (h, w) = frame.shape[:2] | ||
137 | + blob = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), | ||
138 | + (104.0, 177.0, 123.0)) | ||
139 | + | ||
140 | + # pass the blob through the network and obtain the face detections | ||
141 | + faceNet.setInput(blob) | ||
142 | + detections = faceNet.forward() | ||
143 | + | ||
144 | + # initialize our list of faces, their corresponding locations, | ||
145 | + # and the list of predictions from our face mask network | ||
146 | + faces = [] | ||
147 | + locs = [] | ||
148 | + preds = [] | ||
149 | + | ||
150 | + # loop over the detections | ||
151 | + for i in range(0, detections.shape[2]): | ||
152 | + # extract the confidence (i.e., probability) associated with | ||
153 | + # the detection | ||
154 | + confidence = detections[0, 0, i, 2] | ||
155 | + | ||
156 | + # filter out weak detections by ensuring the confidence is | ||
157 | + # greater than the minimum confidence | ||
158 | + if confidence > args["confidence"]: | ||
159 | + # compute the (x, y)-coordinates of the bounding box for | ||
160 | + # the object | ||
161 | + box = detections[0, 0, i, 3:7] * np.array([w, h, w, h]) | ||
162 | + (startX, startY, endX, endY) = box.astype("int") | ||
163 | + | ||
164 | + # ensure the bounding boxes fall within the dimensions of | ||
165 | + # the frame | ||
166 | + (startX, startY) = (max(0, startX), max(0, startY)) | ||
167 | + (endX, endY) = (min(w - 1, endX), min(h - 1, endY)) | ||
168 | + | ||
169 | + # extract the face ROI, convert it from BGR to RGB channel | ||
170 | + # ordering, resize it to 224x224, and preprocess it | ||
171 | + face = frame[startY:endY, startX:endX] | ||
172 | + face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB) | ||
173 | + face = cv2.resize(face, (224, 224)) | ||
174 | + face = img_to_array(face) | ||
175 | + face = preprocess_input(face) | ||
176 | + | ||
177 | + # add the face and bounding boxes to their respective | ||
178 | + # lists | ||
179 | + faces.append(face) | ||
180 | + locs.append((startX, startY, endX, endY)) | ||
181 | + | ||
182 | + # only make a predictions if at least one face was detected | ||
183 | + if len(faces) > 0: | ||
184 | + # for faster inference we'll make batch predictions on *all* | ||
185 | + # faces at the same time rather than one-by-one predictions | ||
186 | + # in the above `for` loop | ||
187 | + faces = np.array(faces, dtype="float32") | ||
188 | + preds = maskNet.predict(faces, batch_size=32) | ||
189 | + | ||
190 | + # return a 2-tuple of the face locations and their corresponding | ||
191 | + # locations | ||
192 | + return (locs, preds) | ||
193 | + | ||
194 | + | ||
195 | +class SpeakerRecognition(QtWidgets.QWidget): | ||
196 | + verification_url = URL.format('verification') | ||
197 | + identification_url = URL.format('identification') | ||
198 | + enrollment_url = URL.format('enroll') | ||
199 | + speaker_id = '' | ||
200 | + | ||
201 | + def __init__(self, parent=None): | ||
202 | + super(SpeakerRecognition, self).__init__(parent) | ||
203 | + self.initUI() | ||
204 | + | ||
205 | + def initUI(self): | ||
206 | + self.label_1_1 = QtWidgets.QLabel('Result Message: ', self) | ||
207 | + self.label_1_2 = QtWidgets.QLabel('', self) | ||
208 | + self.push_button5 =QtWidgets.QPushButton('Authenticate', self) | ||
209 | + self.push_button5.clicked.connect(self.doAction) | ||
210 | + | ||
211 | + self.dialog_button = QtWidgets.QPushButton('화자 ID 입력:', self) | ||
212 | + self.dialog_button.clicked.connect(self.showDialog) | ||
213 | + self.le = QtWidgets.QLineEdit(self) | ||
214 | + | ||
215 | + self.register_button = QtWidgets.QPushButton('Register new voice', self) | ||
216 | + self.register_button.clicked.connect(self.switch_enrollment) | ||
217 | + | ||
218 | + def verification(self, speaker): | ||
219 | + try: | ||
220 | + with open(WAVE_OUTPUT_FILENAME, 'rb') as file_opened: | ||
221 | + files = {'file': file_opened} | ||
222 | + data = {'enroll_speaker': speaker} | ||
223 | + r = requests.post(self.verification_url, files=files, data=data) | ||
224 | + print(r.text) | ||
225 | + return r.text | ||
226 | + except FileNotFoundError: | ||
227 | + return False | ||
228 | + | ||
229 | + def identification(self): | ||
230 | + try: | ||
231 | + with open(WAVE_OUTPUT_FILENAME, 'rb') as file_opened: | ||
232 | + files = {'file': file_opened} | ||
233 | + r = requests.post(self.identification_url, files=files) | ||
234 | + print(r.text) | ||
235 | + return r.text | ||
236 | + except FileNotFoundError: | ||
237 | + return False | ||
238 | + | ||
239 | + def recognition(self): | ||
240 | + speaker = self.identification() | ||
241 | + if speaker == False: | ||
242 | + print('Record voice first!') | ||
243 | + return False | ||
244 | + | ||
245 | + percentage = self.verification(speaker) | ||
246 | + print(speaker, percentage) | ||
247 | + | ||
248 | + if float(percentage) >= THRESHOLD: | ||
249 | + result = '승인! 등록된 화자입니다.' | ||
250 | + #result = speaker | ||
251 | + else: | ||
252 | + result = '등록되지 않은 화자입니다!' | ||
253 | + return result | ||
254 | + | ||
255 | + @QtCore.pyqtSlot() | ||
256 | + def doAction(self): | ||
257 | + recog = self.recognition() | ||
258 | + if recog == False: | ||
259 | + self.label_1_2.setText('Voice not recorded, record voice first!') | ||
260 | + else: | ||
261 | + self.label_1_2.setText(recog) | ||
262 | + | ||
263 | + def enrollment(self, speaker_id): | ||
264 | + try: | ||
265 | + if speaker_id == '': | ||
266 | + return 0 | ||
267 | + with open(WAVE_ENROLL_FILENAME, 'rb') as file_opened: | ||
268 | + files = {'file': file_opened} | ||
269 | + data = {'enroll_speaker': speaker_id} | ||
270 | + r = requests.post(self.enrollment_url, files=files, data=data) | ||
271 | + print(r.text) | ||
272 | + return r.text | ||
273 | + except FileNotFoundError: | ||
274 | + return 1 | ||
275 | + | ||
276 | + def switch_enrollment(self): | ||
277 | + enroll = self.enrollment(self.speaker_id) | ||
278 | + if enroll == 1: | ||
279 | + self.label_1_2.setText('Voice not recorded, record voice first!') | ||
280 | + elif enroll == 0: | ||
281 | + self.label_1_2.setText('No speaker ID input!') | ||
282 | + else: | ||
283 | + self.label_1_2.setText("""New speaker registered!('%s')""" % self.speaker_id) | ||
284 | + self.speaker_id = '' | ||
285 | + self.le.setText(self.speaker_id) | ||
286 | + | ||
287 | + def showDialog(self): | ||
288 | + text, ok = QtWidgets.QInputDialog.getText(self, '화자 등록', | ||
289 | + '등록할 화자 ID(Unique 값)을 입력하십시오:') | ||
290 | + if ok: | ||
291 | + self.le.setText(str(text)) | ||
292 | + self.speaker_id = str(text) | ||
293 | + | ||
294 | +class RecordAudio(QtCore.QObject): | ||
295 | + isrecording = False | ||
296 | + frames = [] | ||
297 | + | ||
298 | + def __init__(self, parent=None): | ||
299 | + super(RecordAudio, self).__init__(parent) | ||
300 | + | ||
301 | + @QtCore.pyqtSlot() | ||
302 | + def startRecording(self): | ||
303 | + # start Recording | ||
304 | + self.audio = pyaudio.PyAudio() | ||
305 | + self.stream = self.audio.open(format=pyaudio.paInt16, | ||
306 | + channels=CHANNELS, | ||
307 | + rate=RATE, | ||
308 | + input=True, | ||
309 | + input_device_index=1, # 기기마다 마이크 인덱스 다름 | ||
310 | + frames_per_buffer=CHUNK) | ||
311 | + self.isrecording = True | ||
312 | + print("recording...") | ||
313 | + | ||
314 | + # frames = [] | ||
315 | + self.frames.clear() | ||
316 | + | ||
317 | + for i in range(0, int(RATE / CHUNK * MAX_RECORD_SECONDS)): | ||
318 | + QtWidgets.QApplication.processEvents() | ||
319 | + if self.isrecording: | ||
320 | + data = self.stream.read(CHUNK) | ||
321 | + self.frames.append(data) | ||
322 | + else: | ||
323 | + print("Stopped recording") | ||
324 | + break | ||
325 | + print("finished recording") | ||
326 | + | ||
327 | + # stop Recording | ||
328 | + self.stream.stop_stream() | ||
329 | + self.stream.close() | ||
330 | + self.audio.terminate() | ||
331 | + waveFile = wave.open(WAVE_OUTPUT_FILENAME, 'wb') | ||
332 | + waveFile.setnchannels(CHANNELS) | ||
333 | + waveFile.setsampwidth(self.audio.get_sample_size(FORMAT)) | ||
334 | + waveFile.setframerate(RATE) | ||
335 | + waveFile.writeframes(b''.join(self.frames)) | ||
336 | + waveFile.close() | ||
337 | + self.frames.clear() | ||
338 | + | ||
339 | + def stopRecording(self): | ||
340 | + print("stop called") | ||
341 | + self.isrecording = False | ||
342 | + | ||
343 | + def switch(self): | ||
344 | + if self.isrecording: | ||
345 | + QtTest.QTest.qWait(1 * 1000) | ||
346 | + self.stopRecording() | ||
347 | + else: | ||
348 | + self.startRecording() | ||
349 | + | ||
350 | +class RecordAudio_enroll(QtCore.QObject): | ||
351 | + isrecording = False | ||
352 | + frames = [] | ||
353 | + | ||
354 | + def __init__(self, parent=None): | ||
355 | + super(RecordAudio_enroll, self).__init__(parent) | ||
356 | + | ||
357 | + @QtCore.pyqtSlot() | ||
358 | + def startRecording(self): | ||
359 | + # start Recording | ||
360 | + self.audio = pyaudio.PyAudio() | ||
361 | + self.stream = self.audio.open(format=pyaudio.paInt16, | ||
362 | + channels=CHANNELS, | ||
363 | + rate=RATE, | ||
364 | + input=True, | ||
365 | + input_device_index=1, # 기기마다 마이크 인덱스 다름 | ||
366 | + frames_per_buffer=CHUNK) | ||
367 | + self.isrecording = True | ||
368 | + print("recording...") | ||
369 | + | ||
370 | + # frames = [] | ||
371 | + self.frames.clear() | ||
372 | + | ||
373 | + for i in range(0, int(RATE / CHUNK * MAX_RECORD_SECONDS)): | ||
374 | + QtWidgets.QApplication.processEvents() | ||
375 | + if self.isrecording: | ||
376 | + data = self.stream.read(CHUNK) | ||
377 | + self.frames.append(data) | ||
378 | + else: | ||
379 | + print("Stopped recording") | ||
380 | + break | ||
381 | + print("finished recording") | ||
382 | + | ||
383 | + # stop Recording | ||
384 | + self.stream.stop_stream() | ||
385 | + self.stream.close() | ||
386 | + self.audio.terminate() | ||
387 | + waveFile = wave.open(WAVE_ENROLL_FILENAME, 'wb') | ||
388 | + waveFile.setnchannels(CHANNELS) | ||
389 | + waveFile.setsampwidth(self.audio.get_sample_size(FORMAT)) | ||
390 | + waveFile.setframerate(RATE) | ||
391 | + waveFile.writeframes(b''.join(self.frames)) | ||
392 | + waveFile.close() | ||
393 | + self.frames.clear() | ||
394 | + | ||
395 | + def stopRecording(self): | ||
396 | + print("stop called") | ||
397 | + self.isrecording = False | ||
398 | + | ||
399 | + def switch(self): | ||
400 | + if self.isrecording: | ||
401 | + QtTest.QTest.qWait(1 * 1000) | ||
402 | + self.stopRecording() | ||
403 | + else: | ||
404 | + self.startRecording() | ||
405 | + | ||
406 | +class RecordViewer(QtWidgets.QWidget): | ||
407 | + def __init__(self, parent=None): | ||
408 | + super(RecordViewer, self).__init__(parent) | ||
409 | + self.initUI() | ||
410 | + | ||
411 | + def initUI(self): | ||
412 | + self.pbar = QtWidgets.QProgressBar(self) | ||
413 | + self.pbar.setFixedWidth(400) | ||
414 | + self.pbar.setMaximum(MAX_RECORD_SECONDS) | ||
415 | + self.pbar.setAlignment(QtCore.Qt.AlignCenter) | ||
416 | + | ||
417 | + self.push_button3 = QtWidgets.QPushButton('Start Audio Record', self) | ||
418 | + self.push_button3.clicked.connect(self.doAction) | ||
419 | + | ||
420 | + self.timer = QtCore.QBasicTimer() | ||
421 | + self.step = 0 | ||
422 | + | ||
423 | + def timerEvent(self, e): | ||
424 | + if self.step >= MAX_RECORD_SECONDS: | ||
425 | + self.timer.stop() | ||
426 | + self.push_button3.setText("Restart") | ||
427 | + return | ||
428 | + self.step = self.step + 1 | ||
429 | + self.pbar.setValue(self.step) | ||
430 | + self.pbar.setFormat("%d sec" % self.step) | ||
431 | + | ||
432 | + @QtCore.pyqtSlot() | ||
433 | + def doAction(self): | ||
434 | + if self.timer.isActive(): | ||
435 | + self.timer.stop() | ||
436 | + self.push_button3.setText("Restart") | ||
437 | + else: | ||
438 | + self.pbar.reset() | ||
439 | + self.step = 0 | ||
440 | + self.timer.start(1000, self) # 1000/1000초마다 timer실행 | ||
441 | + self.push_button3.setText("Stop") | ||
442 | + | ||
443 | + | ||
444 | +if __name__ == '__main__': | ||
445 | + # construct the argument parser and parse the arguments | ||
446 | + ap = argparse.ArgumentParser() | ||
447 | + ap.add_argument("-f", "--face", type=str, default="face_detector", | ||
448 | + help="path to face detector model directory") | ||
449 | + ap.add_argument("-m", "--model", type=str, default="mask_detector.model", | ||
450 | + help="path to trained face mask detector model") | ||
451 | + ap.add_argument("-c", "--confidence", type=float, default=0.5, | ||
452 | + help="minimum probability to filter weak detections") | ||
453 | + args = vars(ap.parse_args()) | ||
454 | + | ||
455 | + # load our serialized face detector model from disk | ||
456 | + print("[INFO] loading face detector model...") | ||
457 | + prototxtPath = os.path.sep.join([args["face"], "deploy.prototxt"]) | ||
458 | + weightsPath = os.path.sep.join([args["face"], | ||
459 | + "res10_300x300_ssd_iter_140000.caffemodel"]) | ||
460 | + faceNet = cv2.dnn.readNet(prototxtPath, weightsPath) | ||
461 | + | ||
462 | + # load the face mask detector model from disk | ||
463 | + print("[INFO] loading face mask detector model...") | ||
464 | + maskNet = load_model(args["model"]) | ||
465 | + | ||
466 | + app = QtWidgets.QApplication(sys.argv) # app 생성 | ||
467 | + | ||
468 | + thread = QtCore.QThread() | ||
469 | + thread.start() | ||
470 | + vid = ShowVideo() | ||
471 | + vid.moveToThread(thread) | ||
472 | + | ||
473 | + thread2 = QtCore.QThread() | ||
474 | + thread2.start() | ||
475 | + aud = RecordViewer() | ||
476 | + aud.moveToThread(thread2) | ||
477 | + | ||
478 | + thread3 = QtCore.QThread() | ||
479 | + thread3.start() | ||
480 | + mic = RecordAudio_enroll() | ||
481 | + mic.moveToThread(thread3) | ||
482 | + | ||
483 | + thread4 = QtCore.QThread() | ||
484 | + thread4.start() | ||
485 | + sr = SpeakerRecognition() | ||
486 | + sr.moveToThread(thread4) | ||
487 | + | ||
488 | + thread5 = QtCore.QThread() | ||
489 | + thread5.start() | ||
490 | + aud2 = RecordViewer() | ||
491 | + aud2.moveToThread(thread5) | ||
492 | + | ||
493 | + thread6 = QtCore.QThread() | ||
494 | + thread6.start() | ||
495 | + mic2 = RecordAudio() | ||
496 | + mic2.moveToThread(thread6) | ||
497 | + | ||
498 | + thread7 = QtCore.QThread() | ||
499 | + thread7.start() | ||
500 | + sr2 = SpeakerRecognition() | ||
501 | + sr2.moveToThread(thread7) | ||
502 | + | ||
503 | + | ||
504 | + image_viewer1 = ImageViewer() | ||
505 | + | ||
506 | + vid.VideoSignal1.connect(image_viewer1.setImage) | ||
507 | + | ||
508 | + push_button1 = QtWidgets.QPushButton('Start Mask Detection') | ||
509 | + push_button2 = QtWidgets.QPushButton('Mask Detection Off') | ||
510 | + push_button4 = QtWidgets.QPushButton('Close') | ||
511 | + | ||
512 | + push_button1.clicked.connect(lambda: vid.startVideo(faceNet, maskNet)) | ||
513 | + push_button2.clicked.connect(vid.maskdetectionoff) | ||
514 | + aud.push_button3.clicked.connect(mic.switch) | ||
515 | + push_button4.clicked.connect(sys.exit) | ||
516 | + aud2.push_button3.clicked.connect(mic2.switch) | ||
517 | + | ||
518 | + empty_label = QtWidgets.QLabel() | ||
519 | + empty_label.setText('') | ||
520 | + | ||
521 | + L_groupBox = QtWidgets.QGroupBox("Mask Detection") | ||
522 | + LR_layout = QtWidgets.QVBoxLayout() | ||
523 | + LR_layout.addWidget(push_button1) | ||
524 | + LR_layout.addWidget(push_button2) | ||
525 | + LR_layout.addStretch(1) | ||
526 | + | ||
527 | + L_horizontal_layout1 = QtWidgets.QHBoxLayout() | ||
528 | + L_horizontal_layout1.addWidget(image_viewer1) | ||
529 | + L_horizontal_layout1.addLayout(LR_layout) | ||
530 | + L_groupBox.setLayout(L_horizontal_layout1) | ||
531 | + | ||
532 | + RU_groupBox = QtWidgets.QGroupBox("Voice Record") | ||
533 | + pbar_layout = QtWidgets.QHBoxLayout() | ||
534 | + pbar_layout.addWidget(aud.pbar) | ||
535 | + pbar_layout.addStretch(1) | ||
536 | + ## | ||
537 | + dialog_layout = QtWidgets.QHBoxLayout() | ||
538 | + dialog_layout.addWidget(sr2.dialog_button) | ||
539 | + dialog_layout.addWidget(sr2.le) | ||
540 | + dialog_layout.addStretch(1) | ||
541 | + | ||
542 | + register_layout = QtWidgets.QHBoxLayout() | ||
543 | + register_layout.addWidget(sr2.register_button) | ||
544 | + | ||
545 | + result_1_layout = QtWidgets.QHBoxLayout() | ||
546 | + result_1_layout.addWidget(sr2.label_1_1) | ||
547 | + result_1_layout.addWidget(sr2.label_1_2) | ||
548 | + result_1_layout.addStretch(1) | ||
549 | + ## | ||
550 | + RL_label1 = QtWidgets.QLabel() | ||
551 | + RL_label1.setText("Max Record Time: 30 sec") | ||
552 | + RL_label2 = QtWidgets.QLabel() | ||
553 | + RL_label2.setText("Press Start/Restart to begin recording") | ||
554 | + | ||
555 | + RL_layout = QtWidgets.QVBoxLayout() | ||
556 | + RL_layout.addLayout(pbar_layout) | ||
557 | + RL_layout.addWidget(RL_label1) | ||
558 | + RL_layout.addWidget(RL_label2) | ||
559 | + RL_layout.addLayout(dialog_layout) | ||
560 | + RL_layout.addLayout(result_1_layout) | ||
561 | + RL_layout.addStretch(1) | ||
562 | + | ||
563 | + push_button3_layout = QtWidgets.QHBoxLayout() | ||
564 | + push_button3_layout.addWidget(aud.push_button3) | ||
565 | + # push_button3_layout.addStretch(1) | ||
566 | + | ||
567 | + # close_layout = QtWidgets.QHBoxLayout() | ||
568 | + # close_layout.addWidget(push_button4) | ||
569 | + | ||
570 | + RR_layout = QtWidgets.QVBoxLayout() | ||
571 | + RR_layout.addLayout(push_button3_layout) | ||
572 | + RR_layout.addWidget(empty_label) | ||
573 | + RR_layout.addWidget(empty_label) | ||
574 | + RR_layout.addLayout(register_layout) | ||
575 | + RR_layout.addStretch(1) | ||
576 | + # RR_layout.addLayout(close_layout) | ||
577 | + | ||
578 | + R_horizontal_layout2 = QtWidgets.QHBoxLayout() | ||
579 | + R_horizontal_layout2.addLayout(RL_layout) | ||
580 | + R_horizontal_layout2.addLayout(RR_layout) | ||
581 | + RU_groupBox.setLayout(R_horizontal_layout2) | ||
582 | + | ||
583 | + | ||
584 | + RD_groupBox = QtWidgets.QGroupBox("Speaker Recognition") | ||
585 | +### | ||
586 | + pbar_2_layout = QtWidgets.QHBoxLayout() | ||
587 | + pbar_2_layout.addWidget(aud2.pbar) | ||
588 | + pbar_2_layout.addStretch(1) | ||
589 | + | ||
590 | + RDL_label1 = QtWidgets.QLabel() | ||
591 | + RDL_label1.setText("Max Record Time: 30 sec") | ||
592 | + RDL_label2 = QtWidgets.QLabel() | ||
593 | + RDL_label2.setText("Press Start/Restart to begin recording") | ||
594 | + | ||
595 | + push_button3_2_layout = QtWidgets.QHBoxLayout() | ||
596 | + push_button3_2_layout.addWidget(aud2.push_button3) | ||
597 | +### | ||
598 | + result_2_layout = QtWidgets.QHBoxLayout() | ||
599 | + result_2_layout.addWidget(sr.label_1_1) | ||
600 | + result_2_layout.addWidget(sr.label_1_2) | ||
601 | + result_2_layout.addStretch(1) | ||
602 | + | ||
603 | + RDL_layout = QtWidgets.QVBoxLayout() | ||
604 | + RDL_layout.addLayout(pbar_2_layout) | ||
605 | + RDL_layout.addWidget(RDL_label1) | ||
606 | + RDL_layout.addWidget(RDL_label2) | ||
607 | + RDL_layout.addWidget(empty_label) | ||
608 | + RDL_layout.addLayout(result_2_layout) | ||
609 | + RDL_layout.addStretch(1) | ||
610 | + | ||
611 | + push_button5_layout = QtWidgets.QHBoxLayout() | ||
612 | + push_button5_layout.addWidget(sr.push_button5) | ||
613 | + | ||
614 | + close_layout = QtWidgets.QHBoxLayout() | ||
615 | + close_layout.addWidget(push_button4) | ||
616 | + | ||
617 | + RDR_layout = QtWidgets.QVBoxLayout() | ||
618 | + RDR_layout.addLayout(push_button3_2_layout) | ||
619 | + RDR_layout.addWidget(empty_label) | ||
620 | + RDR_layout.addWidget(empty_label) | ||
621 | + RDR_layout.addWidget(empty_label) | ||
622 | + RDR_layout.addLayout(push_button5_layout) | ||
623 | + RDR_layout.addStretch(1) | ||
624 | + RDR_layout.addLayout(close_layout) | ||
625 | + | ||
626 | + RD_horizontal_layout = QtWidgets.QHBoxLayout() | ||
627 | + RD_horizontal_layout.addLayout(RDL_layout) | ||
628 | + RD_horizontal_layout.addLayout(RDR_layout) | ||
629 | + RD_groupBox.setLayout(RD_horizontal_layout) | ||
630 | + | ||
631 | + R_layout = QtWidgets.QVBoxLayout() | ||
632 | + R_layout.addWidget(RU_groupBox) | ||
633 | + R_layout.addWidget(RD_groupBox) | ||
634 | + | ||
635 | + layout = QtWidgets.QHBoxLayout() | ||
636 | + layout.addWidget(L_groupBox) | ||
637 | + layout.addLayout(R_layout) | ||
638 | + | ||
639 | + layout_widget = QtWidgets.QWidget() | ||
640 | + layout_widget.setLayout(layout) | ||
641 | + | ||
642 | + main_window = QtWidgets.QMainWindow() | ||
643 | + main_window.setGeometry(150, 150, 500, 500) # test | ||
644 | + main_window.setCentralWidget(layout_widget) | ||
645 | + main_window.setWindowTitle('마스크 디텍션 및 화자 식별을 통한 입출입 시스템') # main window 제목 | ||
646 | + main_window.show() | ||
647 | + sys.exit(app.exec_()) # 프로그램 대기상태 유지, 무한루프 |
-
Please register or login to post a comment