当前位置: 首页 > news >正文

计算机竞赛 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录

  • 0 前言
  • 1 课题背景
  • 2 实现目标
  • 3 当前市面上疲劳驾驶检测的方法
  • 4 相关数据集
  • 5 基于头部姿态的驾驶疲劳检测
    • 5.1 如何确定疲劳状态
    • 5.2 算法步骤
    • 5.3 打瞌睡判断
  • 6 基于CNN与SVM的疲劳检测方法
    • 6.1 网络结构
    • 6.2 疲劳图像分类训练
    • 6.3 训练结果
  • 7 最后

0 前言

🔥 优质竞赛项目系列,今天要分享的是

基于深度学习的驾驶疲劳检测

该项目较为新颖,适合作为竞赛课题方向,学长非常推荐!

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

在这里插入图片描述

1 课题背景

关于对疲劳驾驶的研究不在少数, 不少学者从人物面部入手展开。 人类的面部包含着许多不同的特征信息, 例如其中一些比较明显的特征如打哈欠、 闭眼、
揉眼等表情特征可用来作为判断驾驶员是否处于疲劳状态的依据。 随着计算机技术的不断发展, 尤其是在人工智能相关技术勃发的今天,
借助计算机可以快速有效的识别出图片中人脸特征, 对处于当前时刻驾驶员的精神状态做出判断, 并将疲劳预警信息传达给司机, 以保证交通的安全运行,
减少伤亡事故的发生。

2 实现目标

经查阅相关文献,疲劳在人体面部表情中表现出大致三个类型:打哈欠(嘴巴张大且相对较长时间保持这一状态)、眨眼(或眼睛微闭,此时眨眼次数增多,且眨眼速度变慢)、点头(瞌睡点头)。本实验从人脸朝向、位置、瞳孔朝向、眼睛开合度、眨眼频率、瞳孔收缩率等数据入手,并通过这些数据,实时地计算出驾驶员的注意力集中程度,分析驾驶员是否疲劳驾驶和及时作出安全提示。

3 当前市面上疲劳驾驶检测的方法

学长通过对疲劳驾驶在不同方法下研究进展的分析, 可以更清晰的认识的到当下对该问题较为有效的判定方法。 根据研究对象的不同对检测方法进行分类,
具体分类方法如图

在这里插入图片描述

基于驾驶员面部特征的检测方法是根据人在疲劳时面部变化来分析此时的精神状态。 人在瞌睡、 疲劳时面部表情与清醒时有着明显的区别。
通过装置在车辆中的摄像头对驾驶员人脸图片的采集, 利用计算机图像处理和模式识别, 可以有效检测驾驶员的疲
劳特征信息, 比较直观的特征有: 打哈欠, 眨眼, 低头等。

4 相关数据集

学长收集的疲劳检测数据集

驾驶疲劳人脸数据库图片来源分为 3 部分, 每部分均包含疲劳、 轻度疲劳和非疲劳

在这里插入图片描述

5 基于头部姿态的驾驶疲劳检测

5.1 如何确定疲劳状态

  • 思路一:可利用姿态估计结果(如Pitch的读数)来判断是否点头及点头幅度

  • 思路二:或用鼻尖处30号点的前后移动值(或是方差,方差表示一个单位时间数据的偏离程度,程度越大,则表示发生点头动作的概率越大、点头幅度越大)

在这里插入图片描述

5.2 算法步骤

  • 第一步:2D人脸关键点检测;

  • 第二步:3D人脸模型匹配;

  • 第三步:求解3D点和对应2D点的转换关系;

  • 第四步:根据旋转矩阵求解欧拉角。

    import cv2
    import dlib
    import numpy as np
    from imutils import face_utils
    """
    思路:第一步:2D人脸关键点检测;第二步:3D人脸模型匹配;第三步:求解3D点和对应2D点的转换关系;第四步:根据旋转矩阵求解欧拉角。
    """# 加载人脸检测和姿势估计模型(dlib)face_landmark_path = 'D:/myworkspace/JupyterNotebook/fatigue_detecting/model/shape_predictor_68_face_landmarks.dat'"""
    只要知道世界坐标系内点的位置、像素坐标位置和相机参数就可以搞定旋转和平移矩阵(OpenCV自带函数solvePnp())
    """# 世界坐标系(UVW):填写3D参考点,该模型参考http://aifi.isr.uc.pt/Downloads/OpenGL/glAnthropometric3DModel.cppobject_pts = np.float32([[6.825897, 6.760612, 4.402142],  #33左眉左上角[1.330353, 7.122144, 6.903745],  #29左眉右角[-1.330353, 7.122144, 6.903745], #34右眉左角[-6.825897, 6.760612, 4.402142], #38右眉右上角[5.311432, 5.485328, 3.987654],  #13左眼左上角[1.789930, 5.393625, 4.413414],  #17左眼右上角[-1.789930, 5.393625, 4.413414], #25右眼左上角[-5.311432, 5.485328, 3.987654], #21右眼右上角[2.005628, 1.409845, 6.165652],  #55鼻子左上角[-2.005628, 1.409845, 6.165652], #49鼻子右上角[2.774015, -2.080775, 5.048531], #43嘴左上角[-2.774015, -2.080775, 5.048531],#39嘴右上角[0.000000, -3.116408, 6.097667], #45嘴中央下角[0.000000, -7.415691, 4.070434]])#6下巴角# 相机坐标系(XYZ):添加相机内参K = [6.5308391993466671e+002, 0.0, 3.1950000000000000e+002,0.0, 6.5308391993466671e+002, 2.3950000000000000e+002,0.0, 0.0, 1.0]# 等价于矩阵[fx, 0, cx; 0, fy, cy; 0, 0, 1]# 图像中心坐标系(uv):相机畸变参数[k1, k2, p1, p2, k3]D = [7.0834633684407095e-002, 6.9140193737175351e-002, 0.0, 0.0, -1.3073460323689292e+000]# 像素坐标系(xy):填写凸轮的本征和畸变系数cam_matrix = np.array(K).reshape(3, 3).astype(np.float32)
    dist_coeffs = np.array(D).reshape(5, 1).astype(np.float32)# 重新投影3D点的世界坐标轴以验证结果姿势reprojectsrc = np.float32([[10.0, 10.0, 10.0],[10.0, 10.0, -10.0],[10.0, -10.0, -10.0],[10.0, -10.0, 10.0],[-10.0, 10.0, 10.0],[-10.0, 10.0, -10.0],[-10.0, -10.0, -10.0],[-10.0, -10.0, 10.0]])# 绘制正方体12轴line_pairs = [[0, 1], [1, 2], [2, 3], [3, 0],[4, 5], [5, 6], [6, 7], [7, 4],[0, 4], [1, 5], [2, 6], [3, 7]]def get_head_pose(shape):# 填写2D参考点,注释遵循https://ibug.doc.ic.ac.uk/resources/300-W/"""17左眉左上角/21左眉右角/22右眉左上角/26右眉右上角/36左眼左上角/39左眼右上角/42右眼左上角/45右眼右上角/31鼻子左上角/35鼻子右上角/48左上角/54嘴右上角/57嘴中央下角/8下巴角"""# 像素坐标集合image_pts = np.float32([shape[17], shape[21], shape[22], shape[26], shape[36],shape[39], shape[42], shape[45], shape[31], shape[35],shape[48], shape[54], shape[57], shape[8]])"""用solvepnp或sovlepnpRansac,输入3d点、2d点、相机内参、相机畸变,输出r、t之后用projectPoints,输入3d点、相机内参、相机畸变、r、t,输出重投影2d点计算原2d点和重投影2d点的距离作为重投影误差"""# solvePnP计算姿势——求解旋转和平移矩阵:# rotation_vec表示旋转矩阵,translation_vec表示平移矩阵,cam_matrix与K矩阵对应,dist_coeffs与D矩阵对应。_, rotation_vec, translation_vec = cv2.solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs)# projectPoints重新投影误差reprojectdst, _ = cv2.projectPoints(reprojectsrc, rotation_vec, translation_vec, cam_matrix,dist_coeffs)reprojectdst = tuple(map(tuple, reprojectdst.reshape(8, 2)))# 以8行2列显示# 计算欧拉角calc euler angle# 参考https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#decomposeprojectionmatrixrotation_mat, _ = cv2.Rodrigues(rotation_vec)#罗德里格斯公式(将旋转矩阵转换为旋转向量)pose_mat = cv2.hconcat((rotation_mat, translation_vec))# 水平拼接,vconcat垂直拼接# eulerAngles –可选的三元素矢量,包含三个以度为单位的欧拉旋转角度_, _, _, _, _, _, euler_angle = cv2.decomposeProjectionMatrix(pose_mat)# 将投影矩阵分解为旋转矩阵和相机矩阵return reprojectdst, euler_angledef main():# returncap = cv2.VideoCapture(0)if not cap.isOpened():print("Unable to connect to camera.")return# 检测人脸detector = dlib.get_frontal_face_detector()# 检测第一个人脸的关键点predictor = dlib.shape_predictor(face_landmark_path)while cap.isOpened():ret, frame = cap.read()if ret:face_rects = detector(frame, 0)if len(face_rects) > 0:# 循环脸部位置信息,使用predictor(gray, rect)获得脸部特征位置的信息shape = predictor(frame, face_rects[0])# 将脸部特征信息转换为数组array的格式shape = face_utils.shape_to_np(shape)# 获取头部姿态reprojectdst, euler_angle = get_head_pose(shape)pitch = format(euler_angle[0, 0])yaw = format(euler_angle[1, 0])roll = format(euler_angle[2, 0])print('pitch:{}, yaw:{}, roll:{}'.format(pitch, yaw, roll))# 标出68个特征点for (x, y) in shape:cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)# 绘制正方体12轴for start, end in line_pairs:cv2.line(frame, reprojectdst[start], reprojectdst[end], (0, 0, 255))# 显示角度结果cv2.putText(frame, "X: " + "{:7.2f}".format(euler_angle[0, 0]), (20, 20), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)cv2.putText(frame, "Y: " + "{:7.2f}".format(euler_angle[1, 0]), (20, 50), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)cv2.putText(frame, "Z: " + "{:7.2f}".format(euler_angle[2, 0]), (20, 80), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)    # 按q退出提示cv2.putText(frame, "Press 'q': Quit", (20, 450),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (84, 255, 159), 2)# 窗口显示 show with opencvcv2.imshow("Head_Posture", frame)if cv2.waitKey(1) & 0xFF == ord('q'):break# 释放摄像头 release cameracap.release()# do a bit of cleanupcv2.destroyAllWindows()if __name__ == '__main__':main()

在这里插入图片描述

5.3 打瞌睡判断

头部姿态判断打瞌睡得到实时头部姿态的旋转角度过后,为头部旋转角度的3个参数Yaw,Pitch和Roll的示意图,驾驶员在打瞌睡时,显然头部会做类似于点头和倾斜的动作.而根据一般人的打瞌睡时表现出来的头部姿态,显然很少会在Yaw上有动作,而主要集中在Pitch和Roll的行为.设定参数阈值为0.3,在一个时间段内10
s内,当I PitchI≥20°或者|Rolll≥20°的时间比例超过0.3时,就认为驾驶员处于打瞌睡的状态,发出预警。

在这里插入图片描述

from scipy.spatial import distance as distfrom imutils.video import FileVideoStreamfrom imutils.video import VideoStreamfrom imutils import face_utilsimport numpy as np # 数据处理的库 numpyimport argparseimport imutilsimport timeimport dlibimport cv2import mathimport timefrom threading import Thread,# 世界坐标系(UVW):填写3D参考点,该模型参考http://aifi.isr.uc.pt/Downloads/OpenGL/glAnthropometric3DModel.cppobject_pts = np.float32([[6.825897, 6.760612, 4.402142],  #33左眉左上角[1.330353, 7.122144, 6.903745],  #29左眉右角[-1.330353, 7.122144, 6.903745], #34右眉左角[-6.825897, 6.760612, 4.402142], #38右眉右上角[5.311432, 5.485328, 3.987654],  #13左眼左上角[1.789930, 5.393625, 4.413414],  #17左眼右上角[-1.789930, 5.393625, 4.413414], #25右眼左上角[-5.311432, 5.485328, 3.987654], #21右眼右上角[2.005628, 1.409845, 6.165652],  #55鼻子左上角[-2.005628, 1.409845, 6.165652], #49鼻子右上角[2.774015, -2.080775, 5.048531], #43嘴左上角[-2.774015, -2.080775, 5.048531],#39嘴右上角[0.000000, -3.116408, 6.097667], #45嘴中央下角[0.000000, -7.415691, 4.070434]])#6下巴角# 相机坐标系(XYZ):添加相机内参K = [6.5308391993466671e+002, 0.0, 3.1950000000000000e+002,0.0, 6.5308391993466671e+002, 2.3950000000000000e+002,0.0, 0.0, 1.0]# 等价于矩阵[fx, 0, cx; 0, fy, cy; 0, 0, 1]# 图像中心坐标系(uv):相机畸变参数[k1, k2, p1, p2, k3]D = [7.0834633684407095e-002, 6.9140193737175351e-002, 0.0, 0.0, -1.3073460323689292e+000]# 像素坐标系(xy):填写凸轮的本征和畸变系数cam_matrix = np.array(K).reshape(3, 3).astype(np.float32)dist_coeffs = np.array(D).reshape(5, 1).astype(np.float32)# 重新投影3D点的世界坐标轴以验证结果姿势reprojectsrc = np.float32([[10.0, 10.0, 10.0],[10.0, 10.0, -10.0],[10.0, -10.0, -10.0],[10.0, -10.0, 10.0],[-10.0, 10.0, 10.0],[-10.0, 10.0, -10.0],[-10.0, -10.0, -10.0],[-10.0, -10.0, 10.0]])# 绘制正方体12轴line_pairs = [[0, 1], [1, 2], [2, 3], [3, 0],[4, 5], [5, 6], [6, 7], [7, 4],[0, 4], [1, 5], [2, 6], [3, 7]]def get_head_pose(shape):# 头部姿态估计# (像素坐标集合)填写2D参考点,注释遵循https://ibug.doc.ic.ac.uk/resources/300-W/# 17左眉左上角/21左眉右角/22右眉左上角/26右眉右上角/36左眼左上角/39左眼右上角/42右眼左上角/# 45右眼右上角/31鼻子左上角/35鼻子右上角/48左上角/54嘴右上角/57嘴中央下角/8下巴角image_pts = np.float32([shape[17], shape[21], shape[22], shape[26], shape[36],shape[39], shape[42], shape[45], shape[31], shape[35],shape[48], shape[54], shape[57], shape[8]])# solvePnP计算姿势——求解旋转和平移矩阵:# rotation_vec表示旋转矩阵,translation_vec表示平移矩阵,cam_matrix与K矩阵对应,dist_coeffs与D矩阵对应。_, rotation_vec, translation_vec = cv2.solvePnP(object_pts, image_pts, cam_matrix, dist_coeffs)# projectPoints重新投影误差:原2d点和重投影2d点的距离(输入3d点、相机内参、相机畸变、r、t,输出重投影2d点)reprojectdst, _ = cv2.projectPoints(reprojectsrc, rotation_vec, translation_vec, cam_matrix,dist_coeffs)reprojectdst = tuple(map(tuple, reprojectdst.reshape(8, 2)))# 以8行2列显示# 计算欧拉角calc euler angle# 参考https://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#decomposeprojectionmatrixrotation_mat, _ = cv2.Rodrigues(rotation_vec)#罗德里格斯公式(将旋转矩阵转换为旋转向量)pose_mat = cv2.hconcat((rotation_mat, translation_vec))# 水平拼接,vconcat垂直拼接# decomposeProjectionMatrix将投影矩阵分解为旋转矩阵和相机矩阵_, _, _, _, _, _, euler_angle = cv2.decomposeProjectionMatrix(pose_mat)pitch, yaw, roll = [math.radians(_) for _ in euler_angle]pitch = math.degrees(math.asin(math.sin(pitch)))roll = -math.degrees(math.asin(math.sin(roll)))yaw = math.degrees(math.asin(math.sin(yaw)))print('pitch:{}, yaw:{}, roll:{}'.format(pitch, yaw, roll))return reprojectdst, euler_angle# 投影误差,欧拉角def eye_aspect_ratio(eye):# 垂直眼标志(X,Y)坐标A = dist.euclidean(eye[1], eye[5])# 计算两个集合之间的欧式距离B = dist.euclidean(eye[2], eye[4])# 计算水平之间的欧几里得距离# 水平眼标志(X,Y)坐标C = dist.euclidean(eye[0], eye[3])# 眼睛长宽比的计算ear = (A + B) / (2.0 * C)# 返回眼睛的长宽比return eardef mouth_aspect_ratio(mouth):# 嘴部A = np.linalg.norm(mouth[2] - mouth[9])  # 51, 59B = np.linalg.norm(mouth[4] - mouth[7])  # 53, 57C = np.linalg.norm(mouth[0] - mouth[6])  # 49, 55mar = (A + B) / (2.0 * C)return mar# 定义常数# 眼睛长宽比# 闪烁阈值EYE_AR_THRESH = 0.2EYE_AR_CONSEC_FRAMES = 3# 打哈欠长宽比# 闪烁阈值MAR_THRESH = 0.5MOUTH_AR_CONSEC_FRAMES = 3# 瞌睡点头HAR_THRESH = 0.3NOD_AR_CONSEC_FRAMES = 3# 初始化帧计数器和眨眼总数COUNTER = 0TOTAL = 0# 初始化帧计数器和打哈欠总数mCOUNTER = 0mTOTAL = 0# 初始化帧计数器和点头总数hCOUNTER = 0hTOTAL = 0# 初始化DLIB的人脸检测器(HOG),然后创建面部标志物预测print("[INFO] loading facial landmark predictor...")# 第一步:使用dlib.get_frontal_face_detector() 获得脸部位置检测器detector = dlib.get_frontal_face_detector()# 第二步:使用dlib.shape_predictor获得脸部特征位置检测器predictor = dlib.shape_predictor('D:/myworkspace/JupyterNotebook/fatigue_detecting/model/shape_predictor_68_face_landmarks.dat')# 第三步:分别获取左右眼面部标志的索引(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"](rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"](mStart, mEnd) = face_utils.FACIAL_LANDMARKS_IDXS["mouth"]# 第四步:打开cv2 本地摄像头cap = cv2.VideoCapture(0)# 从视频流循环帧while True:# 第五步:进行循环,读取图片,并对图片做维度扩大,并进灰度化ret, frame = cap.read()frame = imutils.resize(frame, width=720)gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)# 第六步:使用detector(gray, 0) 进行脸部位置检测rects = detector(gray, 0)# 第七步:循环脸部位置信息,使用predictor(gray, rect)获得脸部特征位置的信息for rect in rects:shape = predictor(gray, rect)# 第八步:将脸部特征信息转换为数组array的格式shape = face_utils.shape_to_np(shape)# 第九步:提取左眼和右眼坐标leftEye = shape[lStart:lEnd]rightEye = shape[rStart:rEnd]# 嘴巴坐标mouth = shape[mStart:mEnd]        # 第十步:构造函数计算左右眼的EAR值,使用平均值作为最终的EARleftEAR = eye_aspect_ratio(leftEye)rightEAR = eye_aspect_ratio(rightEye)ear = (leftEAR + rightEAR) / 2.0# 打哈欠mar = mouth_aspect_ratio(mouth)# 第十一步:使用cv2.convexHull获得凸包位置,使用drawContours画出轮廓位置进行画图操作leftEyeHull = cv2.convexHull(leftEye)rightEyeHull = cv2.convexHull(rightEye)cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1)mouthHull = cv2.convexHull(mouth)cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)# 第十二步:进行画图操作,用矩形框标注人脸left = rect.left()top = rect.top()right = rect.right()bottom = rect.bottom()cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 1)    '''分别计算左眼和右眼的评分求平均作为最终的评分,如果小于阈值,则加1,如果连续3次都小于阈值,则表示进行了一次眨眼活动'''# 第十三步:循环,满足条件的,眨眼次数+1if ear < EYE_AR_THRESH:# 眼睛长宽比:0.2COUNTER += 1else:# 如果连续3次都小于阈值,则表示进行了一次眨眼活动if COUNTER >= EYE_AR_CONSEC_FRAMES:# 阈值:3TOTAL += 1# 重置眼帧计数器COUNTER = 0# 第十四步:进行画图操作,同时使用cv2.putText将眨眼次数进行显示cv2.putText(frame, "Faces: {}".format(len(rects)), (10, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)     cv2.putText(frame, "COUNTER: {}".format(COUNTER), (150, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.putText(frame, "EAR: {:.2f}".format(ear), (300, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.putText(frame, "Blinks: {}".format(TOTAL), (450, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,0), 2)'''计算张嘴评分,如果小于阈值,则加1,如果连续3次都小于阈值,则表示打了一次哈欠,同一次哈欠大约在3帧'''# 同理,判断是否打哈欠    if mar > MAR_THRESH:# 张嘴阈值0.5mCOUNTER += 1cv2.putText(frame, "Yawning!", (10, 60),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)else:# 如果连续3次都小于阈值,则表示打了一次哈欠if mCOUNTER >= MOUTH_AR_CONSEC_FRAMES:# 阈值:3mTOTAL += 1# 重置嘴帧计数器mCOUNTER = 0cv2.putText(frame, "COUNTER: {}".format(mCOUNTER), (150, 60),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.putText(frame, "MAR: {:.2f}".format(mar), (300, 60),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)cv2.putText(frame, "Yawning: {}".format(mTOTAL), (450, 60),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,0), 2)"""瞌睡点头"""# 第十五步:获取头部姿态reprojectdst, euler_angle = get_head_pose(shape)har = euler_angle[0, 0]# 取pitch旋转角度if har > HAR_THRESH:# 点头阈值0.3hCOUNTER += 1else:# 如果连续3次都小于阈值,则表示瞌睡点头一次if hCOUNTER >= NOD_AR_CONSEC_FRAMES:# 阈值:3hTOTAL += 1# 重置点头帧计数器hCOUNTER = 0# 绘制正方体12轴for start, end in line_pairs:cv2.line(frame, reprojectdst[start], reprojectdst[end], (0, 0, 255))# 显示角度结果cv2.putText(frame, "X: " + "{:7.2f}".format(euler_angle[0, 0]), (10, 90), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 255, 0), thickness=2)# GREENcv2.putText(frame, "Y: " + "{:7.2f}".format(euler_angle[1, 0]), (150, 90), cv2.FONT_HERSHEY_SIMPLEX,0.75, (255, 0, 0), thickness=2)# BLUEcv2.putText(frame, "Z: " + "{:7.2f}".format(euler_angle[2, 0]), (300, 90), cv2.FONT_HERSHEY_SIMPLEX,0.75, (0, 0, 255), thickness=2)# RED    cv2.putText(frame, "Nod: {}".format(hTOTAL), (450, 90),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,255,0), 2)# 第十六步:进行画图操作,68个特征点标识for (x, y) in shape:cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)print('嘴巴实时长宽比:{:.2f} '.format(mar)+"\t是否张嘴:"+str([False,True][mar > MAR_THRESH]))print('眼睛实时长宽比:{:.2f} '.format(ear)+"\t是否眨眼:"+str([False,True][COUNTER>=1]))# 确定疲劳提示:眨眼50次,打哈欠15次,瞌睡点头15次if TOTAL >= 50 or mTOTAL>=15 or hTOTAL>=15:cv2.putText(frame, "SLEEP!!!", (100, 200),cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 255), 3)# 按q退出cv2.putText(frame, "Press 'q': Quit", (20, 500),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (84, 255, 159), 2)# 窗口显示 show with opencvcv2.imshow("Frame", frame)# if the `q` key was pressed, break from the loopif cv2.waitKey(1) & 0xFF == ord('q'):break# 释放摄像头 release cameracap.release()# do a bit of cleanupcv2.destroyAllWindows()

在这里插入图片描述
在这里插入图片描述

6 基于CNN与SVM的疲劳检测方法

6.1 网络结构

学长将卷积神经网络作为特征提取器, 支持向量机作为分类识别器并通过串联将两者结合 , 构造理想的深度识别模型, 提高对驾驶员疲劳的识别准确率。
本次课题主要以实现提高识别精度为目的, 设计使用的特征提取网络结构中卷积层、 池化层以及全连接层个数均为两层;
在网络的结尾处添加一层支持向量机作为识别分类器;

在这里插入图片描述
根据对卷积神经网络的描述, 这里设计使用的网络结构为: 输入层、 二层卷积层、 二层池化层、 二层全连接层以及 SVM
分类器组成的卷积神经网络对采集数据进行实验。

可将网络视为三个部分, 数据输入部分即网络输入层, 为特征提取部分由卷积层和池化层构成, SVM 为分类识别部分; 三部分网络串联出整体识别框架,
且相互间约束不大, 为后续优化工作提供了条件。

6.2 疲劳图像分类训练

网络的训练由于数据量较大进行实验时将数据分为多个批次, 每个批次中含有 20张图像, 经过前向、 反向传播后更新网络参数, 训练出误差合适的网络。 测试时,
图像由网络进行识别, 根据得到的识别正确率来验证网络的可行性。

在这里插入图片描述

疲劳驾驶检测需对网络进行训练, 在保证网络训练准确率达到一定精度后即可对图像进行判别; 疲劳驾驶网络训练算法过程如下:

  • Step1: 网络初始化: 初始化网络学习率η, 在数值范围[0, 1]中随机初始化网络参数权值及偏置值; 设置网络结构: 卷积核大小为 5×5, 每批次样本数量 20;
  • Step2: 随机选择数据库内面部表情图像并依次输入网络, 网络按照送入每一批次的图像进行训练;
  • Step3: 网络将训练得到的输出值同图像期望值进行比较, 计算出输出误差;
  • Step4: 根据反向传播原理将误差反向传播计算, 并调整网络参数权值和偏置值;
  • Step5: 判断迭代次数, 达到期望的迭代步数后转到 Step6, 否则转到 Step3;
  • Step6: 将 CNN 提取到的图像特征传入 SVM 中进行训练;
  • Step7: 结束。

6.3 训练结果

学长将对建立起的数据集进行实验, 实验中分别在每一批次下对识别正确和错误个数进行统计, 然后同批次中图片数量相比, 得出最终的准确率和损失率(错误率) 。

在这里插入图片描述
在这里插入图片描述

模型测试结果

在这里插入图片描述
在这里插入图片描述

7 最后

🧿 更多资料, 项目分享:

https://gitee.com/dancheng-senior/postgraduate

相关文章:

计算机竞赛 题目: 基于深度学习的疲劳驾驶检测 深度学习

文章目录 0 前言1 课题背景2 实现目标3 当前市面上疲劳驾驶检测的方法4 相关数据集5 基于头部姿态的驾驶疲劳检测5.1 如何确定疲劳状态5.2 算法步骤5.3 打瞌睡判断 6 基于CNN与SVM的疲劳检测方法6.1 网络结构6.2 疲劳图像分类训练6.3 训练结果 7 最后 0 前言 &#x1f525; 优…...

css--踩坑

1. 子元素的宽高不生效问题 设置flex布局后&#xff0c;子元素的宽高不生效问题。 如果希望子元素的宽高生效&#xff0c;解决方法&#xff0c;给子元素添加如下属性&#xff1a; flex-shrink: 0; flex-shrink: 0;2. 横向滚动&#xff08;子元素宽度不固定&#xff09; /* tab…...

C超市商品信息查询系统

一、系统界面介绍 1. 超市商品信息查询系统 1、显示商品信息&#xff0c;包括&#xff1a;商品名称、商品种类&#xff08;休闲食品、奶品水饮、生鲜水果&#xff09;、商品价格、商品保质期、商品生产日期&#xff1b; 2、从文件中导入数据、显示、排序、查询的功能。&…...

黑马JVM总结(二十七)

&#xff08;1&#xff09;synchronized代码块 synchronized代码块的底层原理&#xff0c;它是给一个对象进行一个加锁操作&#xff0c;它是如何保证如果你出现了synchronized代码块中出现了问题&#xff0c;它需要给这个对象有一个正确的解锁操作呢&#xff0c;加锁解锁是成对…...

软件测试/测试开发丨Python异常处理 学习笔记

点此获取更多相关资料 本文为霍格沃兹测试开发学社学员学习笔记分享 原文链接&#xff1a;https://ceshiren.com/t/topic/27722 异常处理 编写程序时&#xff0c;即使语句或表达式使用了正确的语法&#xff0c;执行时仍可能触发错误。执行时检测到的错误称为异常&#xff0c;大…...

026 - STM32学习笔记 - 液晶屏控制(三) - DMA2D快速绘制矩形、直线

026- STM32学习笔记 - 液晶屏控制&#xff08;三&#xff09; - DMA2D快速绘制矩形、直线等 上节直接操作LTDC在先视频上直接显示&#xff0c;我们直接操作显存地址空间中的内容&#xff0c;用来显示图形&#xff0c;但是相对来说&#xff0c;这种方法费时费力&#xff0c;这节…...

【牛客网】OR59 字符串中找出连续最长的数字串

题目 思路 创建两个字符串 temp 和 ret 创建指针i用来遍历字符串通过i遍历字符串,如果遇到数字则将这个数组加到字符串temp中 i,如果遇到字母,则判断temp字符串的长度和ret字符串的长度,如果temp<ret则说明这个字符串不是要的字符串,如果temp>ret则说明此时temp字符串是…...

云原生监控系统Prometheus:基于Prometheus构建智能化监控告警系统

目录 一、理论 1.Promethues简介 2.监控告警系统设计思路 3.Prometheus监控体系 4.Prometheus时间序列数据 5.Prometheus的生态组件 6.Prometheus工作原理 7.Prometheus监控内容 8.部署Prometheus 9.部署Exporters 10.部署Grafana进行展示 二、实验 1.部署Prometh…...

C++ 学习系列 -- std::list

一 std::list 介绍 list 是 c 中的序列式容器&#xff0c;其实现是双向链表&#xff0c;每个元素都有两个指针&#xff0c;分别指向前一个节点与后一个节点 链表与数组都是计算机常用的内存数据结构&#xff0c;与数组连续内存空间不一样的地方在于&#xff0c;链表的空间是不…...

YOLOv8血细胞检测(6):多维协作注意模块MCA | 原创独家创新首发

💡💡💡本文改进:多维协作注意模块MCA,效果秒杀ECA、SRM、CBAM,创新性十足,可直接作为创新点使用。 MCA | 亲测在血细胞检测项目中涨点,map@0.5 从原始0.895提升至0.910 收录专栏: 💡💡💡YOLO医学影像检测:http://t.csdnimg.cn/N4zBP ✨✨✨实战医学影…...

FFmpeg横竖版视频互换背景模糊一键生成

视频处理是现代多媒体应用中常见的需求。其中横竖版视频互换和背景模糊是视频编辑中常见的操作。FFmpeg是一个功能强大的工具,适用于这些任务。 本文将详细介绍如何使用FFmpeg进行横竖版视频互换和背景模糊。 文章目录 操作命令与命令说明横版转竖版竖版转横版背景模糊处理横…...

Java 华为真题-小朋友分班

需求&#xff1a; 题目描述 幼儿园两个班的小朋友在排队时混在了一起&#xff0c;每位小朋友都知道自己是否与前面一位小朋友同班&#xff0c;请你帮忙把同班的小朋友找出来小朋友的编号是整数&#xff0c;与前一位小朋友同班用Y表示&#xff0c;不同班用N表示学生序号范围(0&…...

机器学习必修课 - 编码分类变量 encoding categorical variables

1. 数据预处理和数据集分割 import pandas as pd from sklearn.model_selection import train_test_split导入所需的Python库 !git clone https://github.com/JeffereyWu/Housing-prices-data.git下载数据集 # Read the data X pd.read_csv(/content/Housing-prices-data/t…...

ClickHouse进阶(二十二):clickhouse管理与运维-服务监控

进入正文前,感谢宝子们订阅专题、点赞、评论、收藏!关注IT贫道,获取高质量博客内容! 🏡个人主页:IT贫道_大数据OLAP体系技术栈,Apache Doris,Kerberos安全认证-CSDN博客 📌订阅:拥抱独家专题,你的订阅将点燃我的创作热情! 👍点赞:赞同优秀创作,你的点赞是对我创…...

Hadoop使用hdfs指令查看hdfs目录的根目录显示被拒

背景 分布式部署hadoop,服务机只有namenode节点,主机包含其他所有节点 主机关机后,没有停止所有节点,导致服务机namenode继续保存 再次开启主机hadoop,使用hdfs查看hdfs根目录的时候显示访问被拒 解决方案 1.主机再次开启hadoop并继续执行关闭 2.服务器再次开启hadoop并继…...

[Mac] 安装paddle-pipelines出现 ERROR: Failed building wheel for lmdb

今天在mac换了新系统&#xff0c;然后重新安装paddle-piplines的时候出现了下面的问题&#xff1a; xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools), missing xcrun at: /Library/Developer/CommandLineTools/usr/bin/xcrunerror: comma…...

LED灯亮灭

.text .global _start _start: 设置GPIO寄存器的时钟使能  RCC_MP_AHB4ENSETR[4]->1 0x50000a28LDR R0,0x50000A28LDR R1,[R0] 从R0为起始地址的&#xff14;个字节数据取出放入R1中ORR R1,R1,#(0x1<<4) 第四位设置为1STR R1,[R0] 写回LDR R0,0x5000…...

Acwing.143 最大异或对(trie树)

题目 在给定的N个整数A1&#xff0c;A2 . …Ax中选出两个进行xor(异或)运算&#xff0c;得到的结果最大是多少? 输入格式 第一行输入一个整数N。 第二行输入N个整数A1~AN。 输出格式 输出一个整数表示答案。 数据范围 1 ≤N ≤105,0≤A<231 输入样例: 3 1 2 3输出样…...

day10.8ubentu流水灯

流水灯 .text .global _start _start: 1.设置GPIOE寄存器的时钟使能 RCC_MP_AHB4ENSETR[4]->1 0x50000a28LDR R0,0X50000A28LDR R1,[R0] 从r0为起始地址的4字节数据取出放在R1ORR R1,R1,#(0x1<<4) 第4位设置为1STR R1,[R0] 写回2.设置PE10管脚为输出模式 G…...

transformer系列5---transformer显存占用分析

Transformer显存占用分析 1 影响因素概述2 前向计算临时Tensor显存占用2.1 self-attention显存占用2.2 MLP显存占用 3 梯度和优化器显存占用3.1 模型训练过程两者显存占用3.2 模型推理过程两者显存占用 1 影响因素概述 模型训练框架&#xff1a;例如pytorch框架的cuda context…...

Docker项目部署

目录 一、前端项目部署 1、上传文件 2、开启容器 3、测试 二、后端项目部署 1、打包java项目 2、将jar包和Dockerfile文件长传到Linux系统 3、构建镜像 4、开启容器 5、测试 三、DockerCompose快速部署 基本语法 一、前端项目部署 1、上传文件 里面包括页面和配置文…...

vue3实现文本超出鼠标移入的时候文本滚动

判断文本长度是否大于容器长度 鼠标移入的时候判断&#xff0c;此处使用了tailwindcss&#xff0c;注意一下要设置文本不换行。 <divref"functionsItems"mouseenter"enterFunctionsItem($event, index)"><img class"w-5 h-5" :src&quo…...

光伏系统MPPT、恒功率控制切换Simulink仿真

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…...

mysql双主互从通过KeepAlived虚拟IP实现高可用

mysql双主互从通过KeepAlived虚拟IP实现高可用 在mysql 双主互从的基础上&#xff0c; 架构图&#xff1a; Keepalived有两个主要的功能&#xff1a; 提供虚拟IP&#xff0c;实现双机热备通过LVS&#xff0c;实现负载均衡 安装 # 安装 yum -y install keepalived # 卸载 …...

​苹果应用高版本出现:“无法安装此app,因为无法验证其完整性”是怎么回事?竟然是错误的?

最近经常有同学私聊我问苹果应用签名后用落地页下载出现高版本是什么意思&#xff1f;我一脸懵&#xff01;还有这个操作&#xff1f;高版本是个啥玩意&#xff01;所以我就上了一下科技去搜索引擎搜索了下&#xff0c;哈哈哈&#xff0c;然后了解下来发现是这样的首先我们确定…...

AF_UNIX和127.0.0.1(AF_INET)回环地址写数据速度对比

在linux下&#xff0c;存在着这样的情况&#xff0c;本地的进程间通信&#xff0c;并且其中一个是服务端&#xff0c;另外的都是客户端。 服务端通过绑定端口&#xff0c;客户端往127.0.0.1的对应端口发送&#xff0c;即可办到&#xff0c;不过这样会浪费一个端口&#xff0c;同…...

我在 NPM 发布了新包: con-colors

链接地址&#xff1a;npmjs.com con-colors 安装依赖 yarn add con-colors使用 导入&#xff1a; import { print } from "con-colors";使用&#xff1a; print.succ("成功的消息"); print.err("失败的消息")例子&#xff1a; import { p…...

【python数据建模】Scipy库

常用模块列表 模块名功能scipy.constants数学常量scipy.fft离散傅里叶变换scipy.integrate积分scipy.interpolate插值scipy.interpolate线性代数scipy.cluster聚类分析、向量量化scipy.io数据输入输出scipy.misc图像处理scipy.ndimagen维图像scipy.odr正交距离回归scipy.optim…...

C# App.xaml.cs的一些操作

一、保证只有一个进程 1.1 关闭旧的&#xff0c;打开新的 protected override void OnStartup(StartupEventArgs e) {base.OnStartup(e);var process Process.GetProcessesByName("Dog");if (process.Count() > 1) {var list process.ToList();list.Sort((p1,p2…...

【ORACLE】ORA-00972:标识符过长

问题 执行创建表结构sql&#xff0c;提示 ORA-00972&#xff1a;标识符过长&#xff1b; 如图所示&#xff0c;约束名称超过30个字符了 原因 一、11G and before 在使用11G数据库时&#xff0c;经常会遇到报错ORA-00972&#xff0c;原因是因为对象名称定义太长&#xff0c…...

【Vue】Vue快速入门、Vue常用指令、Vue的生命周期

&#x1f40c;个人主页&#xff1a; &#x1f40c; 叶落闲庭 &#x1f4a8;我的专栏&#xff1a;&#x1f4a8; c语言 数据结构 javaEE 操作系统 Redis 石可破也&#xff0c;而不可夺坚&#xff1b;丹可磨也&#xff0c;而不可夺赤。 Vue 一、 Vue快速入门二、Vue常用指令2.1 v…...

Pandas 数据处理 类别数据和数值数据

要是作深度学习的话&#xff0c;可以直接用tensoflow框架的预处理层&#xff0c;我试过&#xff0c;比PyTorch自己写出来的会好一点&#xff0c;主要是简单好用。处理CSV文件 它类别的处理逻辑是onehot&#xff0c;比较标准稀疏&#xff0c;数值的话就是归一化了。 有时候不需…...

Android攻城狮学鸿蒙 -- 点击事件

具体参考&#xff1a;华为官网学习地址 1、点击事件&#xff0c;界面跳转 对于一个按钮设置点击事件&#xff0c;跳转页面。但是onclick中&#xff0c;如果pages前边加上“/”&#xff0c;就没法跳转。但是开发工具加上“/”才会给出提示。不知道是不是开发工具的bug。&#…...

jmeter性能测试常见的一些问题

一、request 请求超时设置 timeout 超时时间是可以手动设置的&#xff0c;新建一个 http 请求&#xff0c;在“高级”设置中找到“超时”设置&#xff0c;设置连接、响应时间为2000ms。 1. 请求连接超时&#xff0c;连不上服务器。 现象&#xff1a; Jmeter表现形式为&#xff…...

利用国外 vps 为 switch 设置代理服务器加速游戏下载

switch 在国内通过 wifi 连网后如果直接下载游戏的话速度特别慢&#xff0c;据说要挂一个晚上才能下载成功一个游戏。当我尝试下载时发现进度条基本不动&#xff0c;怀疑软件源是在国外的原因&#xff0c;于是想到可以通过国外 vps 代理中转的方式。具体步骤如下&#xff08;以…...

云计算安全的新挑战:零信任架构的应用

文章目录 云计算的安全挑战什么是零信任架构&#xff1f;零信任架构的应用1. 多因素身份验证&#xff08;MFA&#xff09;2. 访问控制和策略3. 安全信息和事件管理&#xff08;SIEM&#xff09;4. 安全的应用程序开发 零信任架构的未来 &#x1f389;欢迎来到云计算技术应用专栏…...

基于SSM的药房药品采购集中管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用Vue技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…...

【GIT版本控制】--远程仓库

一、连接远程仓库 连接到远程仓库是在GIT中进行协作和备份的关键步骤。以下是连接到远程仓库的基本步骤&#xff1a; 获取远程仓库的URL&#xff1a;首先&#xff0c;你需要获得远程仓库的URL。通常&#xff0c;这是远程仓库提供给你的&#xff0c;可以是HTTPS或SSH URL。例如…...

1:Allotment,2:FeeSell,3:混合Allotment+FreeSell

根据您的描述&#xff0c;这似乎是与酒店预订相关的三种不同的方式。下面是对这三种方式的解释&#xff1a; Allotment&#xff08;配额&#xff09;&#xff1a;这是一种酒店预订方式&#xff0c;其中您可以与酒店签订协议&#xff0c;并购买其一定数量的房间或床位。在此之后…...

NFT Insider#110:The Sandbox与TB Media Global合作,YGG Web3游戏峰会阵容揭晓

引言&#xff1a;NFT Insider由NFT收藏组织WHALE Members、BeepCrypto出品&#xff0c;浓缩每周NFT新闻&#xff0c;为大家带来关于NFT最全面、最新鲜、最有价值的讯息。每期周报将从NFT市场数据&#xff0c;艺术新闻类&#xff0c;游戏新闻类&#xff0c;虚拟世界类&#xff0…...

在硅云上主机搭建wordpress并使用Astra主题和avada主题

目录 前言 准备 操作 DNS解析域名 云主机绑定域名 安装wordpress网站程序 网站内Astra主题设计操作 安装主题 网站内avada主题安装 上传插件 上传主题 选择网站主题 前言 一开始以为云虚拟主机和云服务器是一个东西&#xff0c;只不过前者是虚拟的后者是不是虚拟的…...

基于SSM+Vue的物流管理系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;VueHTML 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 …...

【洛谷】P1114 “非常男女”计划

思路&#xff1a;思路和上一篇一模一样哒~&#xff08;这里就不多解释啦&#xff09; ACcode: #include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N 2e510; int n,a[N],f[N]; int main() { ios::sync_with_st…...

list中符合 多条件中筛选符合条件的值

//查找身高在1.8米及以上的男生 // List<SsxlwdBean> boys list.stream().filter(s->s.getGender() && s.getHeight() > 1.8).collect(Collectors.toList()); xlseachitem list.stream().filter(list->list.xlname.contains(Upstrquery)||list.xlbm.…...

Amber中的信息传递——章节1.2-第三部分

程序列表 Amber 包含大量旨在帮助您进行化学系统计算研究的程序&#xff0c;而且发布的工具数量还在定期增加。 本节列出了 AmberTools 包含的主要程序。 这里列出了套件中包含的每个程序&#xff0c;并简要介绍了其主要功能&#xff0c;同时提供了相关文档参考。 对于大多数程…...

【嵌入式】常用串口协议与转换芯片详解

文章目录 0 前言1 一个通信的协议的组成2 常用协议名词解释2.1 UART2.2 RS-2322.3 RS-4852.4 RS-422 3 常用的芯片3.1 MAX2323.2 CP21023.3 CH3403.4 FT232 0 前言 最近有点想研究USB协议&#xff0c;正好也看到有评论说对如何选择USB转串口模块有些疑惑&#xff0c;其实我也一…...

缓存与数据库双写一致性问题解决方案

其实如果使用缓存&#xff0c;就会出现缓存和数据库的不一致问题&#xff0c;关键在于我们可以接受不一致的时间是多少&#xff0c;根据不同的需求采取不同的实现方案。 第一种&#xff1a;先更新数据库后更新缓存 做法简单&#xff0c;但是并发写情况下&#xff0c;会出现数…...

Java中的transient关键字是什么意思?

Java中的transient关键字是什么意思&#xff1f; 在Java中&#xff0c;transient 是一个关键字&#xff0c;用于修饰实例变量&#xff08;成员变量&#xff09;。当一个实例变量被声明为transient 时&#xff0c;它的值不会被持久化&#xff08;即不会被序列化&#xff09;。 …...

内存溢出和内存泄漏

内存溢出和内存泄漏 内存溢出 内存溢出相对于内存泄漏来说&#xff0c;尽管更容易被理解&#xff0c;但是同样的&#xff0c;内存溢出也是引发程序崩溃的罪魁祸首之一。由于GC一直在发展&#xff0c;所以一般情况下&#xff0c;除非应用程序占用的内存增长速度非常快&#xf…...

Java数组:没错,不装了我就是书架。

&#x1f451;专栏内容&#xff1a;Java⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、数组的概念1、什么是数组&#xff1f;2、数组的创建3、数组的初始化Ⅰ、动态初始化Ⅱ、静态初始化 二、数组的使用1、数组中…...