计算机视觉:驾驶员疲劳检测(二)

简介: 计算机视觉:驾驶员疲劳检测(二)

计算机视觉:驾驶员疲劳检测(一)+https://developer.aliyun.com/article/1384996

改进方向(打哈欠检测疲劳方法)

我们知道在疲劳检测当中,光光检测眨眼可能不是特别准确,因此我们还要在其他可以展示驾驶员疲劳的点来结合展示驾驶员是否处于疲劳驾驶阶段。我们了解到还可以通过嘴巴打哈欠,和点头来展示驾驶员是否疲劳。我们首先来考虑嘴巴打哈欠。

首先我们来看一下嘴巴的关键点。

我们使用对眨眼检测的方法继续对嘴巴使用同样的方法检测是否张嘴!对应公式是:

                                               

def mouth_aspect_ratio(mouth):
  A = np.linalg.norm(mouth[2] - mouth[9])  # 51, 59
  B = np.linalg.norm(mouth[4] - mouth[7])  # 53, 57
  C = np.linalg.norm(mouth[0] - mouth[6])  # 49, 55
  mar = (A + B) / (2.0 * C)
  return mar

这里面我们选择的是嘴部区域内的六个点,来判断驾驶员是否进行了张嘴!

MAR_THRESH = 0.5
MOUTH_AR_CONSEC_FRAMES = 3

同样我们也要设置一个阈值,解释同对眨眼检测的时候一样。

(mStart, mEnd) = FACIAL_LANDMARKS_68_IDXS["mouth"]

首先我们取到68关键点中对应的嘴部区域。

mouth = shape[mStart:mEnd]
mar = mouth_aspect_ratio(mouth)

然后通过函数mouth_aspect_ratio来计算出来mar数值!然后进行凸包检测,并且要画出来。

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), 3)

这里面我们要加上一点就是说我们要绘制出来人脸框框!

if mar > MAR_THRESH:  # 张嘴阈值0.5
      mCOUNTER += 1
      cv2.putText(frame, "Yawning!", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
    else:
      # 如果连续3次都小于阈值,则表示打了一次哈欠
      if mCOUNTER >= MOUTH_AR_CONSEC_FRAMES:  # 阈值:3
        mTOTAL += 1
      # 重置嘴帧计数器
      mCOUNTER = 0
    cv2.putText(frame, "Yawning: {}".format(mTOTAL), (150, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
    cv2.putText(frame, "mCOUNTER: {}".format(mCOUNTER), (300, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
    cv2.putText(frame, "MAR: {:.2f}".format(mar), (480, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

然后进行判断,并且在视频当中展示出来!

改进方向(点头检测疲劳)

检测流程:

2D人脸关键点检测;3D人脸模型匹配;求解3D点和对应2D点的转换关系;根据旋转矩阵求解欧拉角。

一个物体相对于相机的姿态可以使用旋转矩阵和平移矩阵来表示。

!](https://ucc.alicdn.com/images/user-upload-01/a8286dc98d624f4183eed96daab991e2.png)

1. 欧拉角

简单来说,欧拉角就是物体绕坐标系三个坐标轴(x,y,z轴)的旋转角度。

2. 世界坐标系和其他坐标系的转换

坐标系转换:

                               

相机坐标系到像素坐标系转换:

                                 

因此像素坐标系和世界坐标系的关系如下:

                               

然后我们根据论文来定义一下:

object_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下巴角
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]
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]]

其中reprojectsrcline_pairs这两个属于矩形和矩形连接框框的操作。后续会用得到。

cam_matrix = np.array(K).reshape(3, 3).astype(np.float32)
dist_coeffs = np.array(D).reshape(5, 1).astype(np.float32)

这里我们对K和D矩阵进行了reshape了一下!

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#decomposeprojectionmatrix
  rotation_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  # 投影误差,欧拉角

这里我们对一些关键点进行了定位,并且我们将世界坐标系转化成了2D上的坐标。最后我们通过CV2计算出来了欧拉角,这样我们就可以判断司机是否点头了!

HAR_THRESH = 0.3
NOD_AR_CONSEC_FRAMES = 3
hCOUNTER = 0
hTOTAL = 0

同样这里我们也要设定一个阈值和计数器!

reprojectdst, euler_angle = get_head_pose(shape)
    har = euler_angle[0, 0]  # 取pitch旋转角度
    if har > HAR_THRESH:  # 点头阈值0.3
      hCOUNTER += 1
    else:
      # 如果连续3次都小于阈值,则表示瞌睡点头一次
      if hCOUNTER >= NOD_AR_CONSEC_FRAMES:  # 阈值:3
        hTOTAL += 1
      # 重置点头帧计数器
      hCOUNTER = 0
    # 绘制正方体12轴
    for start, end in line_pairs:
      cv2.line(frame, (int(reprojectdst[start][0]),int(reprojectdst[start][1])), (int(reprojectdst[end][0]),int(reprojectdst[end][1])), (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)  # GREEN
    cv2.putText(frame, "Y: " + "{:7.2f}".format(euler_angle[1, 0]), (150, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.75,
          (255, 0, 0), thickness=2)  # BLUE
    cv2.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)
    for (x, y) in shape:
      cv2.circle(frame, (x, y), 1, (0, 0, 255), -1)
  if TOTAL >= 50 or mTOTAL >= 15:
    cv2.putText(frame, "SLEEP!!!", (100, 200), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3)

这里也是一些判断操作和将信息在视频中展示出来。

最后的效果如下:

GUI界面设计展示

如果觉得博主的文章还不错或者您用得到的话,可以免费的关注一下博主,如果三连收藏支持就更好啦!这就是给予我最大的支持!

相关文章
|
6月前
|
机器学习/深度学习 编解码 监控
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-1
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-1
|
6月前
|
机器学习/深度学习 算法 计算机视觉
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A路径规划+单目测距与测速+行人车辆计数等)
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A路径规划+单目测距与测速+行人车辆计数等)
117 2
|
2月前
|
JSON 人工智能 数据格式
AI计算机视觉笔记二十六:YOLOV8自训练关键点检测
本文档详细记录了使用YOLOv8训练关键点检测模型的过程。首先通过清华源安装YOLOv8,并验证安装。接着通过示例权重文件与测试图片`bus.jpg`演示预测流程。为准备训练数据,文档介绍了如何使用`labelme`标注工具进行关键点标注,并提供了一个Python脚本`labelme2yolo.py`将标注结果从JSON格式转换为YOLO所需的TXT格式。随后,通过Jupyter Notebook可视化标注结果确保准确性。最后,文档展示了如何组织数据集目录结构,并提供了训练与测试代码示例,包括配置文件`smoke.yaml`及训练脚本`train.py`,帮助读者完成自定义模型的训练与评估。
|
6月前
|
机器学习/深度学习 算法 计算机视觉
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
计算机视觉实战项目3(图像分类+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A*路径规划+单目测距与测速+行人车辆计数等)
|
2月前
|
人工智能 计算机视觉
AI计算机视觉笔记十五:编写检测的yolov5测试代码
该文为原创文章,如需转载,请注明出处。本文作者在成功运行 `detect.py` 后,因代码难以理解而编写了一个简易测试程序,用于加载YOLOv5模型并检测图像中的对象,特别是“人”类目标。代码实现了从摄像头或图片读取帧、进行颜色转换,并利用YOLOv5进行推理,最后将检测框和置信度绘制在输出图像上,并保存为 `result.jpg`。如果缺少某些模块,可使用 `pip install` 安装。如涉及版权问题或需获取完整代码,请联系作者。
|
3月前
|
机器学习/深度学习 算法 大数据
【2023年MathorCup高校数学建模挑战赛-大数据竞赛】赛道A:基于计算机视觉的坑洼道路检测和识别 python 代码解析
本文提供了2023年MathorCup高校数学建模挑战赛大数据竞赛赛道A的解决方案,涉及基于计算机视觉的坑洼道路检测和识别任务,包括数据预处理、特征提取、模型建立、训练与评估等步骤的Python代码解析。
72 0
【2023年MathorCup高校数学建模挑战赛-大数据竞赛】赛道A:基于计算机视觉的坑洼道路检测和识别 python 代码解析
|
3月前
|
机器学习/深度学习 人工智能 数据处理
AI计算机视觉笔记一:YOLOV5疲劳驾驶行为检测
如何使用云服务器AutoDL进行深度学习模型的训练,特别是针对YOLOV5疲劳驾驶行为训练检测
|
5月前
|
机器学习/深度学习 人工智能 监控
一文读懂计算机视觉4大任务:分类任务、检测任务、目标分割任务、关键点检测任务
一文读懂计算机视觉4大任务:分类任务、检测任务、目标分割任务、关键点检测任务
|
6月前
|
机器学习/深度学习 算法 安全
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-2
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-2
计算机视觉实战项目4(单目测距与测速+摔倒检测+目标检测+目标跟踪+姿态识别+车道线识别+车牌识别+无人机检测+A_路径规划+行人车辆计数+动物识别等)-2
|
6月前
|
机器学习/深度学习 人工智能 算法
如何建立计算机视觉驱动的汽车损伤检测系统-------杂记
如何建立计算机视觉驱动的汽车损伤检测系统-------杂记
111 0

热门文章

最新文章