├── .idea
├── PLJSJC.iml
├── encodings.xml
├── misc.xml
├── modules.xml
└── workspace.xml
├── README.md
├── __pycache__
└── main_ui.cpython-36.pyc
├── dlib-19.8.1-cp36-cp36m-win_amd64.whl
├── main.py
├── main.ui
├── main_ui.py
├── requirements.txt
├── test.py
├── 关于系统.txt
└── 需求.png
/.idea/PLJSJC.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/.idea/encodings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/workspace.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | predictor
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | 1663484649939
115 |
116 |
117 | 1663484649939
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Python_ConvolutionalNeuralNetwork_FaceRecognition_fatiguedriving
2 | 基于Python卷积神经网络人脸识别驾驶员疲劳检测与预警系统设计
3 |
4 | 开发技术环境: Pycharm + Python3.6 + PyQt5 + OpenCV + 卷积神经网络模型
5 |
6 | 本文采用卷积神经算法对驾驶室内的驾驶员进行实时的面部图像抓拍,通过图像处理的技术分析人眼的闭合程度,从而判断驾驶员的疲劳程度。本文介绍了对目标图像进行人脸检测,然后在分割出的人脸图像中,对人脸图像进行水平投影,并根据水平投影得到的人眼上下眼睑,定位出人眼的位置,而且根据人眼的上下眼睑可以通过事先给出的一定判别标准,判断眼部是否处于疲劳状态,从而达到疲劳检测的目的。当检测出驾驶员处于疲劳时,系统会自动报警,使驾驶员恢复到正常状态,从而尽量规避了行车的安全隐患,并且系统做出预留功能,可以将驾驶员的疲劳状态图片发送给指定的服务器以备查询。因此组成本系统中系统模块如下:
7 | (1)视频采集模块
8 | (2)图像预处理模块
9 | (3)人脸定位模块
10 | (4)人眼定位模块
11 | (5)疲劳程度判别模块
12 | (6)报警模块
13 |
--------------------------------------------------------------------------------
/__pycache__/main_ui.cpython-36.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjianlin1985/Python_ConvolutionalNeuralNetwork_FaceRecognition_fatiguedriving/27901fc2ae9bfbde75fd1f0ba37ecddbb86809d5/__pycache__/main_ui.cpython-36.pyc
--------------------------------------------------------------------------------
/dlib-19.8.1-cp36-cp36m-win_amd64.whl:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjianlin1985/Python_ConvolutionalNeuralNetwork_FaceRecognition_fatiguedriving/27901fc2ae9bfbde75fd1f0ba37ecddbb86809d5/dlib-19.8.1-cp36-cp36m-win_amd64.whl
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import os
3 | import sys
4 | import threading
5 | import math
6 | import time
7 |
8 | from PySide6.QtGui import QImage
9 |
10 | import main_ui
11 |
12 | from PySide6 import QtCore, QtGui, QtWidgets
13 | import dlib
14 | import numpy as np
15 | import cv2
16 | from scipy.spatial import distance as dist
17 |
18 | from imutils.video import FileVideoStream
19 | from imutils.video import VideoStream
20 | from imutils import face_utils
21 |
22 | import pygame
23 |
24 | # pyside6-uic -o main_ui.py main.ui
25 |
26 | class MainUI(QtWidgets.QWidget, main_ui.Ui_Form):
27 | # 信号,在UI线程中,不能在其他线程直接操作UI
28 | thread_signal = QtCore.Signal(dict)
29 |
30 | def __init__(self):
31 | super().__init__()
32 | self.setupUi(self)
33 |
34 | # 连接信号
35 | self.pushButton.clicked.connect(self.button_clicked)
36 | # self.thread_signal.connect(self.thread_singnal_slot)
37 |
38 | # 六个功能是否要用
39 | self.fun = [True for i in range(6)]
40 | self.checkBox_11.setChecked(self.fun[0])
41 | self.checkBox_12.setChecked(self.fun[1])
42 | self.checkBox_21.setChecked(self.fun[2])
43 | self.checkBox_22.setChecked(self.fun[3])
44 | self.checkBox_31.setChecked(self.fun[4])
45 | self.checkBox_32.setChecked(self.fun[5])
46 |
47 | self.checkBox_11.stateChanged.connect(self.select_changed)
48 | self.checkBox_12.stateChanged.connect(self.select_changed)
49 | self.checkBox_21.stateChanged.connect(self.select_changed)
50 | self.checkBox_22.stateChanged.connect(self.select_changed)
51 | self.checkBox_31.stateChanged.connect(self.select_changed)
52 | self.checkBox_32.stateChanged.connect(self.select_changed)
53 |
54 | # 阈值
55 | self.values = [3,2,3,5,2]
56 | self.spinBox_1.setValue(self.values[0])
57 | self.spinBox_2.setValue(self.values[1])
58 | self.spinBox_3.setValue(self.values[2])
59 | self.spinBox_4.setValue(self.values[3])
60 | self.spinBox_5.setValue(self.values[4])
61 | self.spinBox_1.valueChanged.connect(self.value_changed)
62 | self.spinBox_2.valueChanged.connect(self.value_changed)
63 | self.spinBox_3.valueChanged.connect(self.value_changed)
64 | self.spinBox_4.valueChanged.connect(self.value_changed)
65 | self.spinBox_5.valueChanged.connect(self.value_changed)
66 | #self.spinBox_6.valueChanged.connect(self.value_changed)
67 |
68 | self.thread_signal.connect(self.thread_singnal_slot)
69 |
70 | self.label_img.setScaledContents(True)
71 |
72 | self.plainTextEdit_tip.appendPlainText('等待开始\n')
73 |
74 |
75 | """参数"""
76 | # 默认为摄像头0
77 | self.VIDEO_STREAM = 0
78 | self.CAMERA_STYLE = False # False未打开摄像头,True摄像头已打开
79 | # 闪烁阈值(秒)
80 | self.AR_CONSEC_FRAMES_check = 3
81 | self.OUT_AR_CONSEC_FRAMES_check = 5
82 | # 眼睛长宽比
83 | self.EYE_AR_THRESH = 0.2
84 | self.EYE_AR_CONSEC_FRAMES = self.AR_CONSEC_FRAMES_check
85 | # 打哈欠长宽比
86 | self.MAR_THRESH = 0.5
87 | self.MOUTH_AR_CONSEC_FRAMES = self.AR_CONSEC_FRAMES_check
88 | # 瞌睡点头
89 | self.HAR_THRESH = 0.3
90 | self.NOD_AR_CONSEC_FRAMES = self.AR_CONSEC_FRAMES_check
91 |
92 | """计数"""
93 | # 初始化帧计数器和眨眼总数
94 | self.COUNTER = 0
95 | self.TOTAL = 0
96 | # 初始化帧计数器和打哈欠总数
97 | self.mCOUNTER = 0
98 | self.mTOTAL = 0
99 | # 初始化帧计数器和点头总数
100 | self.hCOUNTER = 0
101 | self.hTOTAL = 0
102 | # 离职时间长度
103 | self.oCOUNTER = 0
104 |
105 | """姿态"""
106 | # 世界坐标系(UVW):填写3D参考点,该模型参考http://aifi.isr.uc.pt/Downloads/OpenGL/glAnthropometric3DModel.cpp
107 | self.object_pts = np.float32([[6.825897, 6.760612, 4.402142], #33左眉左上角
108 | [1.330353, 7.122144, 6.903745], #29左眉右角
109 | [-1.330353, 7.122144, 6.903745], #34右眉左角
110 | [-6.825897, 6.760612, 4.402142], #38右眉右上角
111 | [5.311432, 5.485328, 3.987654], #13左眼左上角
112 | [1.789930, 5.393625, 4.413414], #17左眼右上角
113 | [-1.789930, 5.393625, 4.413414], #25右眼左上角
114 | [-5.311432, 5.485328, 3.987654], #21右眼右上角
115 | [2.005628, 1.409845, 6.165652], #55鼻子左上角
116 | [-2.005628, 1.409845, 6.165652], #49鼻子右上角
117 | [2.774015, -2.080775, 5.048531], #43嘴左上角
118 | [-2.774015, -2.080775, 5.048531],#39嘴右上角
119 | [0.000000, -3.116408, 6.097667], #45嘴中央下角
120 | [0.000000, -7.415691, 4.070434]])#6下巴角
121 |
122 | # 相机坐标系(XYZ):添加相机内参
123 | self.K = [6.5308391993466671e+002, 0.0, 3.1950000000000000e+002,
124 | 0.0, 6.5308391993466671e+002, 2.3950000000000000e+002,
125 | 0.0, 0.0, 1.0]# 等价于矩阵[fx, 0, cx; 0, fy, cy; 0, 0, 1]
126 | # 图像中心坐标系(uv):相机畸变参数[k1, k2, p1, p2, k3]
127 | self.D = [7.0834633684407095e-002, 6.9140193737175351e-002, 0.0, 0.0, -1.3073460323689292e+000]
128 |
129 | # 像素坐标系(xy):填写凸轮的本征和畸变系数
130 | self.cam_matrix = np.array(self.K).reshape(3, 3).astype(np.float32)
131 | self.dist_coeffs = np.array(self.D).reshape(5, 1).astype(np.float32)
132 |
133 | # 重新投影3D点的世界坐标轴以验证结果姿势
134 | self.reprojectsrc = np.float32([[10.0, 10.0, 10.0],
135 | [10.0, 10.0, -10.0],
136 | [10.0, -10.0, -10.0],
137 | [10.0, -10.0, 10.0],
138 | [-10.0, 10.0, 10.0],
139 | [-10.0, 10.0, -10.0],
140 | [-10.0, -10.0, -10.0],
141 | [-10.0, -10.0, 10.0]])
142 | # 绘制正方体12轴
143 | self.line_pairs = [[0, 1], [1, 2], [2, 3], [3, 0],
144 | [4, 5], [5, 6], [6, 7], [7, 4],
145 | [0, 4], [1, 5], [2, 6], [3, 7]]
146 |
147 |
148 | # 线程
149 | self.thread = None
150 | self.sound_thread = None
151 |
152 |
153 | def get_head_pose(self,shape):# 头部姿态估计
154 | # (像素坐标集合)填写2D参考点,注释遵循https://ibug.doc.ic.ac.uk/resources/300-W/
155 | # 17左眉左上角/21左眉右角/22右眉左上角/26右眉右上角/36左眼左上角/39左眼右上角/42右眼左上角/
156 | # 45右眼右上角/31鼻子左上角/35鼻子右上角/48左上角/54嘴右上角/57嘴中央下角/8下巴角
157 | image_pts = np.float32([shape[17], shape[21], shape[22], shape[26], shape[36],
158 | shape[39], shape[42], shape[45], shape[31], shape[35],
159 | shape[48], shape[54], shape[57], shape[8]])
160 | # solvePnP计算姿势——求解旋转和平移矩阵:
161 | # rotation_vec表示旋转矩阵,translation_vec表示平移矩阵,cam_matrix与K矩阵对应,dist_coeffs与D矩阵对应。
162 | _, rotation_vec, translation_vec = cv2.solvePnP(self.object_pts, image_pts, self.cam_matrix, self.dist_coeffs)
163 | # projectPoints重新投影误差:原2d点和重投影2d点的距离(输入3d点、相机内参、相机畸变、r、t,输出重投影2d点)
164 | reprojectdst, _ = cv2.projectPoints(self.reprojectsrc, rotation_vec, translation_vec, self.cam_matrix,self.dist_coeffs)
165 | reprojectdst = tuple(map(tuple, reprojectdst.reshape(8, 2)))# 以8行2列显示
166 |
167 | # 计算欧拉角calc euler angle
168 | # 参考https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#decomposeprojectionmatrix
169 | rotation_mat, _ = cv2.Rodrigues(rotation_vec)#罗德里格斯公式(将旋转矩阵转换为旋转向量)
170 | pose_mat = cv2.hconcat((rotation_mat, translation_vec))# 水平拼接,vconcat垂直拼接
171 | # decomposeProjectionMatrix将投影矩阵分解为旋转矩阵和相机矩阵
172 | _, _, _, _, _, _, euler_angle = cv2.decomposeProjectionMatrix(pose_mat)
173 |
174 | pitch, yaw, roll = [math.radians(_) for _ in euler_angle]
175 |
176 | pitch = math.degrees(math.asin(math.sin(pitch)))
177 | roll = -math.degrees(math.asin(math.sin(roll)))
178 | yaw = math.degrees(math.asin(math.sin(yaw)))
179 | #print('pitch:{}, yaw:{}, roll:{}'.format(pitch, yaw, roll))
180 |
181 | return reprojectdst, euler_angle# 投影误差,欧拉角
182 | def eye_aspect_ratio(self,eye):
183 | # 垂直眼标志(X,Y)坐标
184 | A = dist.euclidean(eye[1], eye[5])# 计算两个集合之间的欧式距离
185 | B = dist.euclidean(eye[2], eye[4])
186 | # 计算水平之间的欧几里得距离
187 | # 水平眼标志(X,Y)坐标
188 | C = dist.euclidean(eye[0], eye[3])
189 | # 眼睛长宽比的计算
190 | ear = (A + B) / (2.0 * C)
191 | # 返回眼睛的长宽比
192 | return ear
193 |
194 | def mouth_aspect_ratio(self,mouth):# 嘴部
195 | A = np.linalg.norm(mouth[2] - mouth[9]) # 51, 59
196 | B = np.linalg.norm(mouth[4] - mouth[7]) # 53, 57
197 | C = np.linalg.norm(mouth[0] - mouth[6]) # 49, 55
198 | mar = (A + B) / (2.0 * C)
199 | return mar
200 |
201 | def _learning_face(self):
202 | """dlib的初始化调用"""
203 | # 使用人脸检测器get_frontal_face_detector
204 | self.detector = dlib.get_frontal_face_detector()
205 | # dlib的68点模型,使用作者训练好的特征预测器
206 | self.predictor = dlib.shape_predictor("./model/shape_predictor_68_face_landmarks.dat")
207 | data = {
208 | 'type':'msg',
209 | 'value':u"加载模型成功!!!\n"
210 | }
211 | self.thread_signal.emit(data)
212 |
213 | # 分别获取左右眼面部标志的索引
214 | (lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
215 | (rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]
216 | (mStart, mEnd) = face_utils.FACIAL_LANDMARKS_IDXS["mouth"]
217 |
218 | # 建cv2摄像头对象,这里使用电脑自带摄像头,如果接了外部摄像头,则自动切换到外部摄像头
219 | self.cap = cv2.VideoCapture(self.VIDEO_STREAM)
220 |
221 | data = {
222 | 'type': 'msg',
223 | }
224 | if self.cap.isOpened() == True: # 返回true/false 检查初始化是否成功
225 | self.CAMERA_STYLE = True
226 | data['value'] = u"打开摄像头成功!!!"
227 | else:
228 | data['value'] = u"摄像头打开失败!!!"
229 | self.thread_signal.emit(data)
230 | # 所有结果
231 | res = []
232 | t_time = datetime.datetime.now()
233 | e_time = datetime.datetime.now()
234 | h_time = datetime.datetime.now()
235 | # 成功打开视频,循环读取视频流
236 | while (self.cap.isOpened()):
237 | start_time = datetime.datetime.now()
238 | res = ['-' for i in range(9)]
239 | # cap.read()
240 | # 返回两个值:
241 | # 一个布尔值true/false,用来判断读取视频是否成功/是否到视频末尾
242 | # 图像对象,图像的三维矩阵
243 | flag, im_rd = self.cap.read()
244 | # 取灰度
245 | img_gray = cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY)
246 |
247 | # 使用人脸检测器检测每一帧图像中的人脸。并返回人脸数faces
248 | faces = self.detector(img_gray, 0)
249 | # 如果检测到人脸
250 | if (len(faces) != 0):
251 | res[0] = '识别到人脸'
252 | # enumerate方法同时返回数据对象的索引和数据,k为索引,d为faces中的对象
253 | for k, d in enumerate(faces):
254 | # 用红色矩形框出人脸
255 | cv2.rectangle(im_rd, (d.left(), d.top()), (d.right(), d.bottom()), (0, 0, 255), 1)
256 | # 使用预测器得到68点数据的坐标
257 | shape = self.predictor(im_rd, d)
258 | # 圆圈显示每个特征点
259 | for i in range(68):
260 | cv2.circle(im_rd, (shape.part(i).x, shape.part(i).y), 2, (0, 255, 0), -1, 8)
261 | # 将脸部特征信息转换为数组array的格式
262 | shape = face_utils.shape_to_np(shape)
263 |
264 | """
265 | 打哈欠
266 | """
267 | if self.fun[1]:
268 | # 嘴巴坐标
269 | mouth = shape[mStart:mEnd]
270 | # 打哈欠
271 | mar = self.mouth_aspect_ratio(mouth)
272 | # 使用cv2.convexHull获得凸包位置,使用drawContours画出轮廓位置进行画图操作
273 | mouthHull = cv2.convexHull(mouth)
274 | cv2.drawContours(im_rd, [mouthHull], -1, (0, 255, 0), 1)
275 | # 同理,判断是否打哈欠
276 | if mar > self.MAR_THRESH: # 张嘴阈值0.5
277 | self.mCOUNTER += 1
278 | res[4] = '张嘴'
279 | else:
280 | # 如果连续3次都小于阈值,则表示打了一次哈欠
281 | if self.mCOUNTER >= self.MOUTH_AR_CONSEC_FRAMES: # 阈值:3
282 | self.mTOTAL += 1
283 | # 显示
284 | # cv2.putText(im_rd, "Yawning!", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
285 | self.thread_signal.emit({'type':'msg','value':time.strftime('%Y-%m-%d %H:%M ', time.localtime()) + u"打哈欠"})
286 | # 重置嘴帧计数器
287 | self.mCOUNTER = 0
288 | res[4] = '闭嘴'
289 | # cv2.putText(im_rd, "COUNTER: {}".format(self.mCOUNTER), (150, 60), cv2.FONT_HERSHEY_SIMPLEX,
290 | # 0.7, (0, 0, 255), 2)
291 | # cv2.putText(im_rd, "MAR: {:.2f}".format(mar), (300, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
292 | # (0, 0, 255), 2)
293 | # cv2.putText(im_rd, "Yawning: {}".format(self.mTOTAL), (450, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
294 | # (255, 255, 0), 2)
295 | else:
296 | pass
297 | """
298 | 眨眼
299 | """
300 | if self.fun[0]:
301 | # 提取左眼和右眼坐标
302 | leftEye = shape[lStart:lEnd]
303 | rightEye = shape[rStart:rEnd]
304 | # 构造函数计算左右眼的EAR值,使用平均值作为最终的EAR
305 | leftEAR = self.eye_aspect_ratio(leftEye)
306 | rightEAR = self.eye_aspect_ratio(rightEye)
307 | ear = (leftEAR + rightEAR) / 2.0
308 | leftEyeHull = cv2.convexHull(leftEye)
309 | rightEyeHull = cv2.convexHull(rightEye)
310 | # 使用cv2.convexHull获得凸包位置,使用drawContours画出轮廓位置进行画图操作
311 | cv2.drawContours(im_rd, [leftEyeHull], -1, (0, 255, 0), 1)
312 | cv2.drawContours(im_rd, [rightEyeHull], -1, (0, 255, 0), 1)
313 | # 循环,满足条件的,眨眼次数+1
314 | if ear < self.EYE_AR_THRESH: # 眼睛长宽比:0.2
315 | self.COUNTER += 1
316 | res[5] = '闭眼'
317 | else:
318 | # 如果连续3次都小于阈值,则表示进行了一次眨眼活动
319 | if self.COUNTER >= self.EYE_AR_CONSEC_FRAMES: # 阈值:3
320 | self.TOTAL += 1
321 | self.thread_signal.emit({'type':'msg','value':time.strftime('%Y-%m-%d %H:%M ', time.localtime()) + u"眨眼"})
322 | # 重置眼帧计数器
323 | self.COUNTER = 0
324 | res[5] = '睁眼'
325 | # 第十四步:进行画图操作,同时使用cv2.putText将眨眼次数进行显示
326 | # cv2.putText(im_rd, "Faces: {}".format(len(faces)), (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
327 | # (0, 0, 255), 2)
328 | # cv2.putText(im_rd, "COUNTER: {}".format(self.COUNTER), (150, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
329 | # (0, 0, 255), 2)
330 | # cv2.putText(im_rd, "EAR: {:.2f}".format(ear), (300, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
331 | # (0, 0, 255), 2)
332 | # cv2.putText(im_rd, "Blinks: {}".format(self.TOTAL), (450, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
333 | # (255, 255, 0), 2)
334 | else:
335 | pass
336 | """
337 | 瞌睡点头
338 | """
339 | if self.fun[2]:
340 | # 获取头部姿态
341 | reprojectdst, euler_angle = self.get_head_pose(shape)
342 | har = euler_angle[0, 0] # 取pitch旋转角度
343 | if har > self.HAR_THRESH: # 点头阈值0.3
344 | self.hCOUNTER += 1
345 | res[3] = '斜'
346 | else:
347 | # 如果连续3次都小于阈值,则表示瞌睡点头一次
348 | if self.hCOUNTER >= self.NOD_AR_CONSEC_FRAMES: # 阈值:3
349 | self.hTOTAL += 1
350 | self.thread_signal.emit({'type': 'msg', 'value': time.strftime('%Y-%m-%d %H:%M ',
351 | time.localtime()) + u"瞌睡点头"})
352 | # 重置点头帧计数器
353 | self.hCOUNTER = 0
354 | res[3] = '正'
355 | # 绘制正方体12轴(视频流尺寸过大时,reprojectdst会超出int范围,建议压缩检测视频尺寸)
356 | # for start, end in self.line_pairs:
357 | # x1, y1 = reprojectdst[start]
358 | # x2, y2 = reprojectdst[end]
359 | #cv2.line(im_rd, (int(x1), int(y1)), (int(x2), int(y2)), (0, 0, 255))
360 | # 显示角度结果
361 | # cv2.putText(im_rd, "X: " + "{:7.2f}".format(euler_angle[0, 0]), (10, 90),
362 | # cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 255, 0), thickness=2) # GREEN
363 | # cv2.putText(im_rd, "Y: " + "{:7.2f}".format(euler_angle[1, 0]), (150, 90),
364 | # cv2.FONT_HERSHEY_SIMPLEX, 0.75, (255, 0, 0), thickness=2) # BLUE
365 | # cv2.putText(im_rd, "Z: " + "{:7.2f}".format(euler_angle[2, 0]), (300, 90),
366 | # cv2.FONT_HERSHEY_SIMPLEX, 0.75, (0, 0, 255), thickness=2) # RED
367 | # cv2.putText(im_rd, "Nod: {}".format(self.hTOTAL), (450, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
368 | # (255, 255, 0), 2)
369 | else:
370 | pass
371 |
372 | # print('嘴巴实时长宽比:{:.2f} '.format(mar)+"\t是否张嘴:"+str([False,True][mar > self.MAR_THRESH]))
373 | # print('眼睛实时长宽比:{:.2f} '.format(ear)+"\t是否眨眼:"+str([False,True][self.COUNTER>=1]))
374 | # 是否瞌睡
375 | # 点头次数
376 | res[6] = str(self.TOTAL)
377 | # 哈欠次数
378 | res[7] = str(self.mTOTAL)
379 | # 点头次数
380 | res[8] = str(self.hTOTAL)
381 | res[1] = '正常'
382 | if self.TOTAL >= self.values[0]:
383 | res[1] = '轻微疲劳'
384 | pass
385 | if self.hTOTAL >= self.values[2]:
386 | if self.TOTAL >= self.values[0]:
387 | res[1] = '瞌睡'
388 | else:
389 | res[1] = '轻微疲劳'
390 | pass
391 | if self.mTOTAL >= self.values[4]:
392 | if self.TOTAL >= self.values[0]:
393 | res[1] = '瞌睡'
394 | else:
395 | res[1] = '轻微疲劳'
396 | pass
397 | if (datetime.datetime.now() - t_time).seconds >= 10:
398 | self.TOTAL = 0
399 | self.mTOTAL = 0
400 | self.hTOTAL = 0
401 | t_time = datetime.datetime.now()
402 | if res[3] == '斜' and res[5]=='闭眼':
403 | if (datetime.datetime.now() - h_time).seconds>=self.values[3]:
404 | res[1] = '瞌睡'
405 | else:
406 | h_time = datetime.datetime.now()
407 | if res[5] == '闭眼':
408 | if (datetime.datetime.now() - e_time).seconds>=self.values[1]:
409 | res[1] = '瞌睡'
410 | else:
411 | e_time = datetime.datetime.now()
412 |
413 |
414 | else:
415 | res[0] = '未识别到'
416 | # 没有检测到人脸
417 | self.oCOUNTER += 1
418 | cv2.putText(im_rd, "No Face", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3, cv2.LINE_AA)
419 | if self.oCOUNTER >= self.OUT_AR_CONSEC_FRAMES_check:
420 | self.thread_signal.emit({'type': 'msg', 'value': time.strftime('%Y-%m-%d %H:%M ',
421 | time.localtime()) + u"没有识别到人脸"})
422 | self.oCOUNTER = 0
423 |
424 | self.TOTAL = 0
425 | self.mTOTAL = 0
426 | self.hTOTAL = 0
427 |
428 | # 确定疲劳提示:眨眼50次,打哈欠15次,瞌睡点头30次
429 | # if self.TOTAL >= 50 or self.mTOTAL >= 15 or self.hTOTAL >= 30:
430 | # cv2.putText(im_rd, "SLEEP!!!", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 3)
431 | # self.m_textCtrl3.AppendText(u"疲劳")
432 |
433 | # opencv中imread的图片内部是BGR排序,wxPython的StaticBitmap需要的图片是RGB排序,不转换会出现颜色变换
434 | height, width = im_rd.shape[:2]
435 | RGBImg = cv2.cvtColor(im_rd, cv2.COLOR_BGR2RGB)
436 |
437 | data = {'type':'img','value':RGBImg}
438 | self.thread_signal.emit(data)
439 |
440 | end_time = datetime.datetime.now()
441 |
442 | # 帧数
443 | res[2] = str(int(1 / (end_time- start_time).microseconds * 1000000))
444 |
445 | data = {'type': 'res', 'value': res}
446 | self.thread_signal.emit(data)
447 |
448 | # 释放摄像头
449 | self.cap.release()
450 |
451 | def value_changed(self):
452 | self.values[0] = self.spinBox_1.value()
453 | self.values[1] = self.spinBox_2.value()
454 | self.values[2] = self.spinBox_3.value()
455 | self.values[3] = self.spinBox_4.value()
456 | self.values[4] = self.spinBox_5.value()
457 | pass
458 |
459 | def select_changed(self):
460 | self.fun[0] = self.checkBox_11.isChecked()
461 | self.fun[1] = self.checkBox_12.isChecked()
462 | self.fun[2] = self.checkBox_21.isChecked()
463 | self.fun[3] = self.checkBox_22.isChecked()
464 | self.fun[4] = self.checkBox_31.isChecked()
465 | self.fun[5] = self.checkBox_32.isChecked()
466 | pass
467 |
468 | def button_clicked(self):
469 | if self.thread is not None and self.thread.is_alive():
470 | self.plainTextEdit_tip('已经开始')
471 | else:
472 | self.thread = threading.Thread(target=self._learning_face,daemon=True)
473 | self.thread.start()
474 | pass
475 |
476 | def thread_sound(self):
477 | pygame.mixer.init()
478 | pygame.mixer.music.load('1.mp3')
479 | pygame.mixer.music.play()
480 | time.sleep(15)
481 | pygame.mixer.music.stop()
482 |
483 | def paly_sound(self):
484 | if self.sound_thread is not None and self.sound_thread.is_alive():
485 | # self.plainTextEdit_tip('播放声音中')
486 | pass
487 | else:
488 | self.plainTextEdit_tip.appendPlainText('疲劳驾驶 播放声音')
489 | self.sound_thread = threading.Thread(target=self.thread_sound,daemon=True)
490 | self.sound_thread.start()
491 | pass
492 |
493 | def thread_singnal_slot(self, d):
494 | if d['type']=='img':
495 | RGBImg = d['value']
496 | # 将图片转化成Qt可读格式 QImage
497 | qimage = QImage(RGBImg, RGBImg.shape[1], RGBImg.shape[0], QImage.Format_RGB888)
498 | piximage = QtGui.QPixmap(qimage)
499 | # 显示图片
500 | self.label_img.setPixmap(piximage)
501 | #pic_show_label.setScaledContents(True)
502 | elif d['type'] == 'msg':
503 | self.plainTextEdit_tip.appendPlainText(d['value'])
504 | elif d['type'] == 'res':
505 | self.label_11.setText(d['value'][0])
506 | self.label_12.setText(d['value'][1])
507 | self.label_13.setText(d['value'][2])
508 | self.label_21.setText(d['value'][3])
509 | self.label_22.setText(d['value'][4])
510 | self.label_23.setText(d['value'][5])
511 | self.label_31.setText(d['value'][6])
512 | self.label_32.setText(d['value'][7])
513 | self.label_33.setText(d['value'][8])
514 | if d['value'][1] == '轻微疲劳':
515 | self.label_12.setStyleSheet("color:yellow;")
516 | elif d['value'][1] == '瞌睡':
517 | self.label_12.setStyleSheet("color:red;")
518 | self.paly_sound()
519 | else:
520 | self.label_12.setStyleSheet("color:black;")
521 |
522 | pass
523 |
524 | def close(self) -> bool:
525 | self.cap.release()
526 | super(MainUI, self).close()
527 |
528 |
529 |
530 | if __name__ == '__main__':
531 | app = QtWidgets.QApplication(sys.argv)
532 | window = MainUI()
533 | window.show()
534 | sys.exit(app.exec())
535 |
--------------------------------------------------------------------------------
/main.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Form
4 |
5 |
6 |
7 | 0
8 | 0
9 | 664
10 | 599
11 |
12 |
13 |
14 | 系统
15 |
16 |
17 |
18 |
19 | 0
20 | 330
21 | 661
22 | 261
23 |
24 |
25 |
26 | 状态显示
27 |
28 |
29 |
30 |
31 | 10
32 | 20
33 | 641
34 | 111
35 |
36 |
37 |
38 | 实时状态
39 |
40 |
41 |
42 |
43 | 20
44 | 30
45 | 60
46 | 16
47 |
48 |
49 |
50 | 人脸状态
51 |
52 |
53 |
54 |
55 |
56 | 110
57 | 30
58 | 60
59 | 16
60 |
61 |
62 |
63 | 未识别到
64 |
65 |
66 |
67 |
68 |
69 | 210
70 | 30
71 | 60
72 | 16
73 |
74 |
75 |
76 | 是否瞌睡
77 |
78 |
79 |
80 |
81 |
82 | 310
83 | 30
84 | 60
85 | 16
86 |
87 |
88 |
89 | 正常
90 |
91 |
92 |
93 |
94 |
95 | 420
96 | 30
97 | 60
98 | 16
99 |
100 |
101 |
102 | 帧数
103 |
104 |
105 |
106 |
107 |
108 | 520
109 | 30
110 | 60
111 | 16
112 |
113 |
114 |
115 | 0
116 |
117 |
118 |
119 |
120 |
121 | 520
122 | 60
123 | 60
124 | 16
125 |
126 |
127 |
128 | 0
129 |
130 |
131 |
132 |
133 |
134 | 420
135 | 60
136 | 60
137 | 16
138 |
139 |
140 |
141 | 眼部状态
142 |
143 |
144 |
145 |
146 |
147 | 110
148 | 60
149 | 60
150 | 16
151 |
152 |
153 |
154 | 0
155 |
156 |
157 |
158 |
159 |
160 | 210
161 | 60
162 | 60
163 | 16
164 |
165 |
166 |
167 | 嘴巴状态
168 |
169 |
170 |
171 |
172 |
173 | 310
174 | 60
175 | 60
176 | 16
177 |
178 |
179 |
180 | 0
181 |
182 |
183 |
184 |
185 |
186 | 20
187 | 60
188 | 60
189 | 16
190 |
191 |
192 |
193 | 头部状态
194 |
195 |
196 |
197 |
198 |
199 | 20
200 | 90
201 | 60
202 | 16
203 |
204 |
205 |
206 | 点头次数
207 |
208 |
209 |
210 |
211 |
212 | 520
213 | 90
214 | 60
215 | 16
216 |
217 |
218 |
219 | 0
220 |
221 |
222 |
223 |
224 |
225 | 310
226 | 90
227 | 60
228 | 16
229 |
230 |
231 |
232 | 0
233 |
234 |
235 |
236 |
237 |
238 | 420
239 | 90
240 | 60
241 | 16
242 |
243 |
244 |
245 | 眨眼次数
246 |
247 |
248 |
249 |
250 |
251 | 210
252 | 90
253 | 60
254 | 16
255 |
256 |
257 |
258 | 哈欠次数
259 |
260 |
261 |
262 |
263 |
264 | 110
265 | 90
266 | 60
267 | 16
268 |
269 |
270 |
271 | 0
272 |
273 |
274 |
275 |
276 |
277 |
278 | 10
279 | 130
280 | 641
281 | 121
282 |
283 |
284 |
285 | 提示
286 |
287 |
288 | -
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 | 470
298 | 0
299 | 191
300 | 331
301 |
302 |
303 |
304 | 设置
305 |
306 |
307 | -
308 |
309 |
310 | -
311 |
312 |
313 | -
314 |
315 |
316 | 头侧阈值
317 |
318 |
319 |
320 | -
321 |
322 |
323 | 哈欠阈值10s
324 |
325 |
326 |
327 | -
328 |
329 |
330 | -
331 |
332 |
333 | -
334 |
335 |
336 | 头部功能
337 |
338 |
339 |
340 | -
341 |
342 |
343 | 弹窗警告
344 |
345 |
346 |
347 | -
348 |
349 |
350 | 信息提示
351 |
352 |
353 |
354 | -
355 |
356 |
357 | 语音播报
358 |
359 |
360 |
361 | -
362 |
363 |
364 | 哈欠识别
365 |
366 |
367 |
368 | -
369 |
370 |
371 | 眨眼阈值10s
372 |
373 |
374 |
375 | -
376 |
377 |
378 | 眼部功能
379 |
380 |
381 |
382 | -
383 |
384 |
385 | 开始识别
386 |
387 |
388 |
389 | -
390 |
391 |
392 | -
393 |
394 |
395 | 闭眼阈值10s
396 |
397 |
398 |
399 | -
400 |
401 |
402 | 点头阈值10s
403 |
404 |
405 |
406 |
407 |
408 |
409 |
410 |
411 | 10
412 | 0
413 | 451
414 | 331
415 |
416 |
417 |
418 | 图像信息
419 |
420 |
421 | -
422 |
423 |
424 |
425 |
426 |
427 |
428 |
429 |
430 |
431 |
432 |
433 |
434 |
--------------------------------------------------------------------------------
/main_ui.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | ################################################################################
4 | ## Form generated from reading UI file 'main.ui'
5 | ##
6 | ## Created by: Qt User Interface Compiler version 6.3.0
7 | ##
8 | ## WARNING! All changes made in this file will be lost when recompiling UI file!
9 | ################################################################################
10 |
11 | from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
12 | QMetaObject, QObject, QPoint, QRect,
13 | QSize, QTime, QUrl, Qt)
14 | from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
15 | QFont, QFontDatabase, QGradient, QIcon,
16 | QImage, QKeySequence, QLinearGradient, QPainter,
17 | QPalette, QPixmap, QRadialGradient, QTransform)
18 | from PySide6.QtWidgets import (QApplication, QCheckBox, QGridLayout, QGroupBox,
19 | QLabel, QPlainTextEdit, QPushButton, QSizePolicy,
20 | QSpinBox, QWidget)
21 |
22 | class Ui_Form(object):
23 | def setupUi(self, Form):
24 | if not Form.objectName():
25 | Form.setObjectName(u"Form")
26 | Form.resize(664, 599)
27 | self.groupBox_3 = QGroupBox(Form)
28 | self.groupBox_3.setObjectName(u"groupBox_3")
29 | self.groupBox_3.setGeometry(QRect(0, 330, 661, 261))
30 | self.groupBox_5 = QGroupBox(self.groupBox_3)
31 | self.groupBox_5.setObjectName(u"groupBox_5")
32 | self.groupBox_5.setGeometry(QRect(10, 20, 641, 111))
33 | self.label_444 = QLabel(self.groupBox_5)
34 | self.label_444.setObjectName(u"label_444")
35 | self.label_444.setGeometry(QRect(20, 30, 60, 16))
36 | self.label_11 = QLabel(self.groupBox_5)
37 | self.label_11.setObjectName(u"label_11")
38 | self.label_11.setGeometry(QRect(110, 30, 60, 16))
39 | self.label_447 = QLabel(self.groupBox_5)
40 | self.label_447.setObjectName(u"label_447")
41 | self.label_447.setGeometry(QRect(210, 30, 60, 16))
42 | self.label_12 = QLabel(self.groupBox_5)
43 | self.label_12.setObjectName(u"label_12")
44 | self.label_12.setGeometry(QRect(310, 30, 60, 16))
45 | self.label_4410 = QLabel(self.groupBox_5)
46 | self.label_4410.setObjectName(u"label_4410")
47 | self.label_4410.setGeometry(QRect(420, 30, 60, 16))
48 | self.label_13 = QLabel(self.groupBox_5)
49 | self.label_13.setObjectName(u"label_13")
50 | self.label_13.setGeometry(QRect(520, 30, 60, 16))
51 | self.label_23 = QLabel(self.groupBox_5)
52 | self.label_23.setObjectName(u"label_23")
53 | self.label_23.setGeometry(QRect(520, 60, 60, 16))
54 | self.label_441 = QLabel(self.groupBox_5)
55 | self.label_441.setObjectName(u"label_441")
56 | self.label_441.setGeometry(QRect(420, 60, 60, 16))
57 | self.label_21 = QLabel(self.groupBox_5)
58 | self.label_21.setObjectName(u"label_21")
59 | self.label_21.setGeometry(QRect(110, 60, 60, 16))
60 | self.label_448 = QLabel(self.groupBox_5)
61 | self.label_448.setObjectName(u"label_448")
62 | self.label_448.setGeometry(QRect(210, 60, 60, 16))
63 | self.label_22 = QLabel(self.groupBox_5)
64 | self.label_22.setObjectName(u"label_22")
65 | self.label_22.setGeometry(QRect(310, 60, 60, 16))
66 | self.label_445 = QLabel(self.groupBox_5)
67 | self.label_445.setObjectName(u"label_445")
68 | self.label_445.setGeometry(QRect(20, 60, 60, 16))
69 | self.label446 = QLabel(self.groupBox_5)
70 | self.label446.setObjectName(u"label446")
71 | self.label446.setGeometry(QRect(20, 90, 60, 16))
72 | self.label_33 = QLabel(self.groupBox_5)
73 | self.label_33.setObjectName(u"label_33")
74 | self.label_33.setGeometry(QRect(520, 90, 60, 16))
75 | self.label_32 = QLabel(self.groupBox_5)
76 | self.label_32.setObjectName(u"label_32")
77 | self.label_32.setGeometry(QRect(310, 90, 60, 16))
78 | self.label_442 = QLabel(self.groupBox_5)
79 | self.label_442.setObjectName(u"label_442")
80 | self.label_442.setGeometry(QRect(420, 90, 60, 16))
81 | self.label_449 = QLabel(self.groupBox_5)
82 | self.label_449.setObjectName(u"label_449")
83 | self.label_449.setGeometry(QRect(210, 90, 60, 16))
84 | self.label_31 = QLabel(self.groupBox_5)
85 | self.label_31.setObjectName(u"label_31")
86 | self.label_31.setGeometry(QRect(110, 90, 60, 16))
87 | self.groupBox_4 = QGroupBox(self.groupBox_3)
88 | self.groupBox_4.setObjectName(u"groupBox_4")
89 | self.groupBox_4.setGeometry(QRect(10, 130, 641, 121))
90 | self.gridLayout = QGridLayout(self.groupBox_4)
91 | self.gridLayout.setObjectName(u"gridLayout")
92 | self.plainTextEdit_tip = QPlainTextEdit(self.groupBox_4)
93 | self.plainTextEdit_tip.setObjectName(u"plainTextEdit_tip")
94 |
95 | self.gridLayout.addWidget(self.plainTextEdit_tip, 0, 0, 1, 1)
96 |
97 | self.groupBox_2 = QGroupBox(Form)
98 | self.groupBox_2.setObjectName(u"groupBox_2")
99 | self.groupBox_2.setGeometry(QRect(470, 0, 191, 331))
100 | self.gridLayout_2 = QGridLayout(self.groupBox_2)
101 | self.gridLayout_2.setObjectName(u"gridLayout_2")
102 | self.spinBox_3 = QSpinBox(self.groupBox_2)
103 | self.spinBox_3.setObjectName(u"spinBox_3")
104 |
105 | self.gridLayout_2.addWidget(self.spinBox_3, 6, 1, 1, 1)
106 |
107 | self.spinBox_4 = QSpinBox(self.groupBox_2)
108 | self.spinBox_4.setObjectName(u"spinBox_4")
109 |
110 | self.gridLayout_2.addWidget(self.spinBox_4, 7, 1, 1, 1)
111 |
112 | self.label_241 = QLabel(self.groupBox_2)
113 | self.label_241.setObjectName(u"label_241")
114 |
115 | self.gridLayout_2.addWidget(self.label_241, 7, 0, 1, 1)
116 |
117 | self.label_251 = QLabel(self.groupBox_2)
118 | self.label_251.setObjectName(u"label_251")
119 |
120 | self.gridLayout_2.addWidget(self.label_251, 8, 0, 1, 1)
121 |
122 | self.spinBox_5 = QSpinBox(self.groupBox_2)
123 | self.spinBox_5.setObjectName(u"spinBox_5")
124 |
125 | self.gridLayout_2.addWidget(self.spinBox_5, 8, 1, 1, 1)
126 |
127 | self.spinBox_1 = QSpinBox(self.groupBox_2)
128 | self.spinBox_1.setObjectName(u"spinBox_1")
129 |
130 | self.gridLayout_2.addWidget(self.spinBox_1, 4, 1, 1, 1)
131 |
132 | self.checkBox_21 = QCheckBox(self.groupBox_2)
133 | self.checkBox_21.setObjectName(u"checkBox_21")
134 |
135 | self.gridLayout_2.addWidget(self.checkBox_21, 2, 0, 1, 1)
136 |
137 | self.checkBox_32 = QCheckBox(self.groupBox_2)
138 | self.checkBox_32.setObjectName(u"checkBox_32")
139 |
140 | self.gridLayout_2.addWidget(self.checkBox_32, 3, 1, 1, 1)
141 |
142 | self.checkBox_22 = QCheckBox(self.groupBox_2)
143 | self.checkBox_22.setObjectName(u"checkBox_22")
144 |
145 | self.gridLayout_2.addWidget(self.checkBox_22, 2, 1, 1, 1)
146 |
147 | self.checkBox_31 = QCheckBox(self.groupBox_2)
148 | self.checkBox_31.setObjectName(u"checkBox_31")
149 |
150 | self.gridLayout_2.addWidget(self.checkBox_31, 3, 0, 1, 1)
151 |
152 | self.checkBox_12 = QCheckBox(self.groupBox_2)
153 | self.checkBox_12.setObjectName(u"checkBox_12")
154 |
155 | self.gridLayout_2.addWidget(self.checkBox_12, 1, 1, 1, 1)
156 |
157 | self.label_211 = QLabel(self.groupBox_2)
158 | self.label_211.setObjectName(u"label_211")
159 |
160 | self.gridLayout_2.addWidget(self.label_211, 4, 0, 1, 1)
161 |
162 | self.checkBox_11 = QCheckBox(self.groupBox_2)
163 | self.checkBox_11.setObjectName(u"checkBox_11")
164 |
165 | self.gridLayout_2.addWidget(self.checkBox_11, 1, 0, 1, 1)
166 |
167 | self.pushButton = QPushButton(self.groupBox_2)
168 | self.pushButton.setObjectName(u"pushButton")
169 |
170 | self.gridLayout_2.addWidget(self.pushButton, 0, 0, 1, 2)
171 |
172 | self.spinBox_2 = QSpinBox(self.groupBox_2)
173 | self.spinBox_2.setObjectName(u"spinBox_2")
174 |
175 | self.gridLayout_2.addWidget(self.spinBox_2, 5, 1, 1, 1)
176 |
177 | self.label_221 = QLabel(self.groupBox_2)
178 | self.label_221.setObjectName(u"label_221")
179 |
180 | self.gridLayout_2.addWidget(self.label_221, 5, 0, 1, 1)
181 |
182 | self.label_231 = QLabel(self.groupBox_2)
183 | self.label_231.setObjectName(u"label_231")
184 |
185 | self.gridLayout_2.addWidget(self.label_231, 6, 0, 1, 1)
186 |
187 | self.groupBox = QGroupBox(Form)
188 | self.groupBox.setObjectName(u"groupBox")
189 | self.groupBox.setGeometry(QRect(10, 0, 451, 331))
190 | self.gridLayout_3 = QGridLayout(self.groupBox)
191 | self.gridLayout_3.setObjectName(u"gridLayout_3")
192 | self.label_img = QLabel(self.groupBox)
193 | self.label_img.setObjectName(u"label_img")
194 |
195 | self.gridLayout_3.addWidget(self.label_img, 0, 0, 1, 1)
196 |
197 |
198 | self.retranslateUi(Form)
199 |
200 | QMetaObject.connectSlotsByName(Form)
201 | # setupUi
202 |
203 | def retranslateUi(self, Form):
204 | Form.setWindowTitle(QCoreApplication.translate("Form", u"\u7cfb\u7edf", None))
205 | self.groupBox_3.setTitle(QCoreApplication.translate("Form", u"\u72b6\u6001\u663e\u793a", None))
206 | self.groupBox_5.setTitle(QCoreApplication.translate("Form", u"\u5b9e\u65f6\u72b6\u6001", None))
207 | self.label_444.setText(QCoreApplication.translate("Form", u"\u4eba\u8138\u72b6\u6001", None))
208 | self.label_11.setText(QCoreApplication.translate("Form", u"\u672a\u8bc6\u522b\u5230", None))
209 | self.label_447.setText(QCoreApplication.translate("Form", u"\u662f\u5426\u778c\u7761", None))
210 | self.label_12.setText(QCoreApplication.translate("Form", u"\u6b63\u5e38", None))
211 | self.label_4410.setText(QCoreApplication.translate("Form", u"\u5e27\u6570", None))
212 | self.label_13.setText(QCoreApplication.translate("Form", u"0", None))
213 | self.label_23.setText(QCoreApplication.translate("Form", u"0", None))
214 | self.label_441.setText(QCoreApplication.translate("Form", u"\u773c\u90e8\u72b6\u6001", None))
215 | self.label_21.setText(QCoreApplication.translate("Form", u"0", None))
216 | self.label_448.setText(QCoreApplication.translate("Form", u"\u5634\u5df4\u72b6\u6001", None))
217 | self.label_22.setText(QCoreApplication.translate("Form", u"0", None))
218 | self.label_445.setText(QCoreApplication.translate("Form", u"\u5934\u90e8\u72b6\u6001", None))
219 | self.label446.setText(QCoreApplication.translate("Form", u"\u70b9\u5934\u6b21\u6570", None))
220 | self.label_33.setText(QCoreApplication.translate("Form", u"0", None))
221 | self.label_32.setText(QCoreApplication.translate("Form", u"0", None))
222 | self.label_442.setText(QCoreApplication.translate("Form", u"\u7728\u773c\u6b21\u6570", None))
223 | self.label_449.setText(QCoreApplication.translate("Form", u"\u54c8\u6b20\u6b21\u6570", None))
224 | self.label_31.setText(QCoreApplication.translate("Form", u"0", None))
225 | self.groupBox_4.setTitle(QCoreApplication.translate("Form", u"\u63d0\u793a", None))
226 | self.groupBox_2.setTitle(QCoreApplication.translate("Form", u"\u8bbe\u7f6e", None))
227 | self.label_241.setText(QCoreApplication.translate("Form", u"\u5934\u4fa7\u9608\u503c", None))
228 | self.label_251.setText(QCoreApplication.translate("Form", u"\u54c8\u6b20\u9608\u503c10s", None))
229 | self.checkBox_21.setText(QCoreApplication.translate("Form", u"\u5934\u90e8\u529f\u80fd", None))
230 | self.checkBox_32.setText(QCoreApplication.translate("Form", u"\u5f39\u7a97\u8b66\u544a", None))
231 | self.checkBox_22.setText(QCoreApplication.translate("Form", u"\u4fe1\u606f\u63d0\u793a", None))
232 | self.checkBox_31.setText(QCoreApplication.translate("Form", u"\u8bed\u97f3\u64ad\u62a5", None))
233 | self.checkBox_12.setText(QCoreApplication.translate("Form", u"\u54c8\u6b20\u8bc6\u522b", None))
234 | self.label_211.setText(QCoreApplication.translate("Form", u"\u7728\u773c\u9608\u503c10s", None))
235 | self.checkBox_11.setText(QCoreApplication.translate("Form", u"\u773c\u90e8\u529f\u80fd", None))
236 | self.pushButton.setText(QCoreApplication.translate("Form", u"\u5f00\u59cb\u8bc6\u522b", None))
237 | self.label_221.setText(QCoreApplication.translate("Form", u"\u95ed\u773c\u9608\u503c10s", None))
238 | self.label_231.setText(QCoreApplication.translate("Form", u"\u70b9\u5934\u9608\u503c10s", None))
239 | self.groupBox.setTitle(QCoreApplication.translate("Form", u"\u56fe\u50cf\u4fe1\u606f", None))
240 | self.label_img.setText("")
241 | # retranslateUi
242 |
243 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | imutils>=0.5.4
2 | opencv-python>=4.5.5.64
3 | pygame>=2.1.2
4 | PySide6>=6.3.0
5 | python-play>=1.0.5
6 | scipy
7 |
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 |
2 | import time
3 | import pygame
4 | pygame.mixer.init()
5 | print("播放音乐1")
6 | track = pygame.mixer.music.load('1.mp3')
7 | pygame.mixer.music.play()
8 | time.sleep(10)
9 | pygame.mixer.music.stop()
10 | print('结束')
--------------------------------------------------------------------------------
/关于系统.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjianlin1985/Python_ConvolutionalNeuralNetwork_FaceRecognition_fatiguedriving/27901fc2ae9bfbde75fd1f0ba37ecddbb86809d5/关于系统.txt
--------------------------------------------------------------------------------
/需求.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/wangjianlin1985/Python_ConvolutionalNeuralNetwork_FaceRecognition_fatiguedriving/27901fc2ae9bfbde75fd1f0ba37ecddbb86809d5/需求.png
--------------------------------------------------------------------------------