社区所有版块导航
Python
python开源   Django   Python   DjangoApp   pycharm  
DATA
docker   Elasticsearch  
aigc
aigc   chatgpt  
WEB开发
linux   MongoDB   Redis   DATABASE   NGINX   其他Web框架   web工具   zookeeper   tornado   NoSql   Bootstrap   js   peewee   Git   bottle   IE   MQ   Jquery  
机器学习
机器学习算法  
Python88.com
反馈   公告   社区推广  
产品
短视频  
印度
印度  
Py学习  »  Python

MediaPipe+Python,疲劳驾驶系统搭建实战

江大白 • 1 年前 • 385 次点击  

以下章来源于微信公众号:OpenCV与AI深度学习
作者:Color Space
链接:https://mp.weixin.qq.com/s/UfGxTC5FEb-94rd_fy15Vw
本文仅用于学术分享,如有侵权,请联系台作删文处理
导读
道路千万条,安全第一条。疲劳驾驶的危害不堪设想,据了解,21%的交通事故原因都是疲劳驾驶。本文将使用Python和MediaPipe搭建一个嗜睡检测系统以检测疲劳驾驶,并及时提醒驾驶员注意休息,保障大家的人身安全。

背景介绍

疲劳驾驶的危害不堪设想,据了解,21%的交通事故都因此而生,尤其是高速路上,大多数车辆都是长途驾驶,加之速度快,危害更加严重。

相关部门一般都会建议司机朋友及时休息调整后再驾驶,避免酿成惨剧。

作为视觉开发人员,我们可否帮助驾驶人员设计一套智能检测嗜睡的系统,及时提醒驾驶员注意休息?如下图所示,本文将详细介绍如何使用Python和MediaPipe来实现一个嗜睡检测系统。

实现步骤

思路:疲劳驾驶的司机大部分都有打瞌睡的情形,所以我们根据驾驶员眼睛闭合的频率和时间来判断驾驶员是否疲劳驾驶(或嗜睡)。
详细实现步骤
【1】眼部关键点检测。
关于MediaPipe前面已经介绍过,具体可以查看下面链接的文章:
------MediaPipe介绍与手势识别------

我们使用Face Mesh来检测眼部关键点,Face Mesh返回了468个人脸关键点:

由于我们专注于驾驶员睡意检测,在468个点中,我们只需要属于眼睛区域的标志点。眼睛区域有 32 个标志点(每个 16 个点)。为了计算 EAR,我们只需要 12 个点(每只眼睛 6 个点)。
    以上图为参考,选取的12个地标点如下:
  1. 对于左眼:  [362, 385, 387, 263, 373, 380]

  2. 对于右眼:[33, 160, 158, 133, 153, 144]

    选择的地标点按顺序排列:P1、P2、P3、P4、P5、P6 
import cv2import numpy as npimport matplotlib.pyplot as pltimport mediapipe as mp
mp_facemesh = mp.solutions.face_meshmp_drawing = mp.solutions.drawing_utilsdenormalize_coordinates = mp_drawing._normalized_to_pixel_coordinates
%matplotlib inline
获取双眼的地标(索引)点。
# Landmark points corresponding to left eyeall_left_eye_idxs = list(mp_facemesh.FACEMESH_LEFT_EYE)# flatten and remove duplicatesall_left_eye_idxs = set(np.ravel(all_left_eye_idxs)) 
# Landmark points corresponding to right eyeall_right_eye_idxs = list(mp_facemesh.FACEMESH_RIGHT_EYE)all_right_eye_idxs = set(np.ravel(all_right_eye_idxs))
# Combined for plotting - Landmark points for both eyeall_idxs = all_left_eye_idxs.union(all_right_eye_idxs)
# The chosen 12 points: P1, P2, P3, P4, P5, P6chosen_left_eye_idxs = [362, 385, 387, 263, 373, 380]chosen_right_eye_idxs = [33, 160, 158, 133, 153, 144]all_chosen_idxs = chosen_left_eye_idxs + chosen_right_eye_idx

【2】检测眼睛是否闭合——计算眼睛纵横比(EAR)。

要检测眼睛是否闭合,我们可以使用眼睛纵横比(EAR) 公式:

EAR 公式返回反映睁眼程度的单个 标量:

1. 我们将使用 Mediapipe 的 Face Mesh 解决方案来检测和检索眼睛区域中的相关地标(下图中的点P 1 - P 6)。

2. 检索相关点后,会在眼睛的高度和宽度之间计算眼睛纵横比 (EAR)。

当眼睛睁开并接近零时,EAR 几乎是恒定的,而闭上眼睛是部分人,并且头部姿势不敏感。睁眼的纵横比在个体之间具有很小的差异。它对于图像的统一缩放和面部的平面内旋转是完全不变的。由于双眼同时眨眼,所以双眼的EAR是平均的。

上图:检测到地标P i的睁眼和闭眼。
底部:为视频序列的几帧绘制的眼睛纵横比 EAR。存在一个闪烁。
首先,我们必须计算每只眼睛的 Eye Aspect Ratio:

|| 表示L2范数,用于计算两个向量之间的距离。
为了计算最终的 EAR 值,作者建议取两个 EAR 值的平均值。

一般来说,平均 EAR 值在 [0.0, 0.40] 范围内。在“闭眼”动作期间 EAR 值迅速下降。

现在我们熟悉了 EAR 公式,让我们定义三个必需的函数:distance(…)、get_ear(…)和calculate_avg_ear(…)。

def distance(point_1, point_2):    """Calculate l2-norm between two points"""    dist = sum([(i - j) ** 2 for i, j in zip(point_1, point_2)]) ** 0.5    return dist
get_ear (…)函数将.landmark属性作为参数。在每个索引位置,我们都有一个NormalizedLandmark对象。该对象保存标准化的x、y和z坐标值。
def get_ear(landmarks, refer_idxs, frame_width, frame_height):    """    Calculate Eye Aspect Ratio for one eye.
Args: landmarks: (list) Detected landmarks list refer_idxs: (list) Index positions of the chosen landmarks in order P1, P2, P3, P4, P5, P6 frame_width: (int) Width of captured frame frame_height: (int) Height of captured frame
Returns: ear: (float) Eye aspect ratio """ try: # Compute the euclidean distance between the horizontal coords_points = [] for i in refer_idxs: lm = landmarks[i] coord = denormalize_coordinates(lm.x, lm.y, frame_width, frame_height) coords_points.append(coord)
# Eye landmark (x, y)-coordinates P2_P6 = distance(coords_points[1], coords_points[5]) P3_P5 = distance(coords_points[2], coords_points[4]) P1_P4 = distance(coords_points[0], coords_points[3])
# Compute the eye aspect ratio ear = (P2_P6 + P3_P5) / (2.0 * P1_P4)
except: ear = 0.0 coords_points = None
return ear, coords_points
最后定义了calculate_avg_ear(…)函数:
def calculate_avg_ear(landmarks, left_eye_idxs, right_eye_idxs, image_w, image_h):    """Calculate Eye aspect ratio"""
left_ear, left_lm_coordinates = get_ear( landmarks, left_eye_idxs, image_w, image_h ) right_ear, right_lm_coordinates = get_ear( landmarks, right_eye_idxs, image_w, image_h ) Avg_EAR = (left_ear + right_ear) / 2.0
return Avg_EAR, (left_lm_coordinates, right_lm_coordinates)
让我们测试一下 EAR 公式。我们将计算先前使用的图像和另一张眼睛闭合的图像的平均 EAR 值。
image_eyes_open  = cv2.imread("test-open-eyes.jpg")[:, :, ::-1]image_eyes_close = cv2.imread("test-close-eyes.jpg")[:, :, ::-1]
for idx, image in enumerate([image_eyes_open, image_eyes_close]): image = np.ascontiguousarray(image) imgH, imgW, _ = image.shape
# Creating a copy of the original image for plotting the EAR value custom_chosen_lmk_image = image.copy()
# Running inference using static_image_mode with mp_facemesh.FaceMesh(refine_landmarks=True) as face_mesh: results = face_mesh.process(image).multi_face_landmarks
# If detections are available. if results: for face_id, face_landmarks in enumerate(results): landmarks = face_landmarks.landmark EAR, _ = calculate_avg_ear( landmarks, chosen_left_eye_idxs, chosen_right_eye_idxs, imgW, imgH )
# Print the EAR value on the custom_chosen_lmk_image. cv2.putText(custom_chosen_lmk_image, f"EAR: {round(EAR, 2)}", (1, 24), cv2.FONT_HERSHEY_COMPLEX, 0.9, (255, 255, 255), 2 ) plot(img_dt=image.copy(), img_eye_lmks_chosen=custom_chosen_lmk_image, face_landmarks=face_landmarks, ts_thickness=1, ts_circle_radius=3, lmk_circle_radius=3 )
结果:
如您所见,睁眼时的 EAR 值为0.28,闭眼时(接近于零)为 0.08
【3】设计一个实时检测系统。

  1. 首先,我们声明两个阈值和一个计数器。

    1. EAR_thresh: 用于检查当前EAR值是否在范围内的阈值。

    2. D_TIME:一个计数器变量,用于跟踪当前经过的时间量EAR < EAR_THRESH.

    3. WAIT_TIME:确定经过的时间量是否EAR < EAR_THRESH超过了允许的限制。 

  2. 当应用程序启动时,我们将当前时间(以秒为单位)记录在一个变量中t1并读取传入的帧。

  3. 接下来,我们预处理并frame通过Mediapipe 的 Face Mesh 解决方案管道。 

  4. 如果有任何地标检测可用,我们将检索相关的 ( Pi )眼睛地标。否则,在此处重置t1 和重置以使算法一致)。D_TIME (D_TIME

  5. 如果检测可用,则使用检索到的眼睛标志计算双眼的平均EAR值。

  6. 如果是当前时间,则加上当前时间和to之间的差。然后将下一帧重置为。EAR < EAR_THRESHt2t1D_TIMEt1 t2

  7. 如果D_TIME >= WAIT_TIME,我们会发出警报或继续下一帧。

参考链接:
https://learnopencv.com/driver-drowsiness-detection-using-mediapipe-in-python/

推荐阅读

AIHIA | AI人才创新发展联盟2023年盟友招募

AI同学会 | AI同学会开启试运营,快来Pick你的AI同学

AI融资 | 智能物联网公司阿加犀获得高通5000W融资

Yolov5应用 | 家庭安防告警系统全流程及代码讲解

江大白 | 这些年从0转行AI行业的一些感悟

注意:大白梳理对接AI行业的一些中高端岗位,年薪在50W~120W之间,图像算法、搜索推荐等热门岗位,欢迎感兴趣的小伙伴联系大白,提供全流程交流跟踪,各岗位详情如下:

《AI未来星球》陪伴你在AI行业成长的社群,各项福利重磅开放:

(1)198元《31节课入门人工智能》视频课程;

(2)大白花费近万元购买的各类数据集;

(3)每月自习活动,每月17日星球会员日,各类奖品送不停;

(4)加入《AI未来星球》内部微信群;

还有各类直播时分享的文件、研究报告,一起扫码加入吧!

人工智能行业,研究方向很多,大大小小有几十个方向
为了便于大家学习交流,大白创建了一些不同方向的行业交流群
每个领域,都有各方向的行业实战高手,和大家一起沟通交流。
目前主要开设:Opencv项目方面、目标检测方面模型部署方面,后期根据不同领域高手的加入,建立新的方向群!
大家可以根据自己的兴趣爱好,加入对应的微信群,一起交流学习!
© THE END 


大家一起加油! 

Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/156559
 
385 次点击