최성환

enrollment & Authentication 추가

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_()) # 프로그램 대기상태 유지, 무한루프
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_()) # 프로그램 대기상태 유지, 무한루프