人脸疲劳检测应用-米尔基于RK3576核心板/开发板
2024-12-18
2041
来源:米尔电子
本篇源自:优秀创作者 lulugl
本文将介绍基于米尔电子MYD-LR3576开发板(米尔基于瑞芯微 RK3576开发板)的人脸疲劳检测方案测试。

米尔基于RK3576核心板/开发板
【前言】
人脸疲劳检测:一种通过分析人脸特征来判断一个人是否处于疲劳状态的技术。其原理主要基于计算机视觉和机器学习方法。当人疲劳时,面部会出现一些特征变化,如眼睛闭合程度增加、眨眼频率变慢、打哈欠、头部姿态改变等。
例如,通过检测眼睛的状态来判断疲劳程度是一个关键部分。正常情况下,人的眨眼频率相对稳定,而当疲劳时,眨眼频率会降低,并且每次眨眼时眼睛闭合的时间可能会延长。同时,头部可能会不自觉地下垂或者摇晃,这些特征都可以作为疲劳检测的依据。米尔MYC-LR3576采用8核CPU+搭载6 TOPS的NPU加速器,3D GPU,能够非常轻松的实现这个功能,下面就如何实现这一功能分享如下:
【硬件】
1、米尔MYC-LR3576开发板
2、USB摄像头
【软件】
1、v4l2
2、openCV
3、dlib库:dlib 是一个现代化的 C++ 工具包,它包含了许多用于机器学习、图像处理、数值计算等多种任务的算法和工具。它的设计目标是提供高性能、易于使用的库,并且在开源社区中被广泛应用。
【实现步骤】
1、安装python-opencv
2、安装dlib库
3、安装v4l2库
【代码实现】
1、引入cv2、dlib以及线程等:
import cv2 import dlib import numpy as np import time from concurrent.futures import ThreadPoolExecutor import threading
2、初始化dlib的面部检测器和特征点预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')3、定义计算眼睛纵横比的函数
def eye_aspect_ratio(eye): A = np.linalg.norm(np.array(eye[1]) - np.array(eye[5])) B = np.linalg.norm(np.array(eye[2]) - np.array(eye[4])) C = np.linalg.norm(np.array(eye[0]) - np.array(eye[3])) ear = (A + B) / (2.0 * C) return ear
4、定义计算头部姿势的函数
def get_head_pose(shape): # 定义面部特征点的三维坐标 object_points = np.array([ (0.0, 0.0, 0.0), # 鼻尖 (0.0, -330.0, -65.0), # 下巴 (-225.0, 170.0, -135.0), # 左眼左眼角 (225.0, 170.0, -135.0), # 右眼右眼角 (-150.0, -150.0, -125.0), # 左嘴角 (150.0, -150.0, -125.0) # 右嘴角 ], dtype=np.float32) image_pts = np.float32([shape[i] for i in [30, 8, 36, 45, 48, 54]]) size = frame.shape focal_length = size[1] center = (size[1] // 2, size[0] // 2) camera_matrix = np.array( [[focal_length, 0, center[0]], [0, focal_length, center[1]], [0, 0, 1]], dtype="double" ) dist_coeffs = np.zeros((4, 1)) (success, rotation_vector, translation_vector) = cv2.solvePnP( object_points, image_pts, camera_matrix, dist_coeffs, flags=cv2.SOLVEPNP_ITERATIVE ) rmat, _ = cv2.Rodrigues(rotation_vector) angles, _, _, _, _, _ = cv2.RQDecomp3x3(rmat) return angles
5、定义眼睛纵横比阈值和连续帧数阈值
EYE_AR_THRESH = 0.3 EYE_AR_CONSEC_FRAMES = 48
6、打开摄像头
我们先使用v4l2-ctl --list-devices来例出接在开发板上的列表信息:
USB Camera: USB Camera (usb-xhci-hcd.0.auto-1.2): /dev/video60 /dev/video61 /dev/media7
在代码中填入60为摄像头的编号:
cap = cv2.VideoCapture(60) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 480) # 降低分辨率 cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 320)
7、创建多线程处理函数,实现采集与分析分离:
# 多线程处理函数
def process_frame(frame):
global COUNTER, TOTAL
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray, 0) # 第二个参数为0,表示不使用upsampling
for face in faces:
landmarks = predictor(gray, face)
shape = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(68)]
left_eye = shape[36:42]
right_eye = shape[42:48]
left_ear = eye_aspect_ratio(left_eye)
right_ear = eye_aspect_ratio(right_eye)
ear = (left_ear + right_ear) / 2.0
if ear < EYE_AR_THRESH:
with lock:
COUNTER += 1
else:
with lock:
if COUNTER >= EYE_AR_CONSEC_FRAMES:
TOTAL += 1
COUNTER = 0
# 绘制68个特征点
for n in range(0, 68):
x, y = shape[n]
cv2.circle(frame, (x, y), 2, (0, 255, 0), -1)
cv2.putText(frame, f"Eye AR: {ear:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
cv2.putText(frame, f"Blink Count: {TOTAL}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
# 计算头部姿势
angles = get_head_pose(shape)
pitch, yaw, roll = angles
cv2.putText(frame, f"Pitch: {pitch:.2f}", (10, 120), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
cv2.putText(frame, f"Yaw: {yaw:.2f}", (10, 150), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
cv2.putText(frame, f"Roll: {roll:.2f}", (10, 180), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
# 判断疲劳状态
if COUNTER >= EYE_AR_CONSEC_FRAMES or abs(pitch) > 30 or abs(yaw) > 30 or abs(roll) > 30:
cv2.putText(frame, "Fatigue Detected!", (10, 210), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
return frame8、创建图像显示线程:
with ThreadPoolExecutor(max_workers=2) as executor:
future_to_frame = {}
while True:
ret, frame = cap.read()
if not ret:
break
# 提交当前帧到线程池
future = executor.submit(process_frame, frame.copy())
future_to_frame[future] = frame
# 获取已完成的任务结果
for future in list(future_to_frame.keys()):
if future.done():
processed_frame = future.result()
cv2.imshow("Frame", processed_frame)
del future_to_frame[future]
break
# 计算帧数
fps_counter += 1
elapsed_time = time.time() - start_time
if elapsed_time > 1.0:
fps = fps_counter / elapsed_time
fps_counter = 0
start_time = time.time()
cv2.putText(processed_frame, f"FPS: {fps:.2f}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if cv2.waitKey(1) & 0xFF == ord('q'):
整体代码如下:
import cv2
import dlib
import numpy as np
import time
from concurrent.futures import ThreadPoolExecutor
import threading
# 初始化dlib的面部检测器和特征点预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
# 修改字体大小
font_scale = 0.5 # 原来的字体大小是0.7,现在改为0.5
# 定义计算眼睛纵横比的函数
def eye_aspect_ratio(eye):
A = np.linalg.norm(np.array(eye[1]) - np.array(eye[5]))
B = np.linalg.norm(np.array(eye[2]) - np.array(eye[4]))
C = np.linalg.norm(np.array(eye[0]) - np.array(eye[3]))
ear = (A + B) / (2.0 * C)
return ear
# 定义计算头部姿势的函数
def get_head_pose(shape):
# 定义面部特征点的三维坐标
object_points = np.array([
(0.0, 0.0, 0.0), # 鼻尖
(0.0, -330.0, -65.0), # 下巴
(-225.0, 170.0, -135.0), # 左眼左眼角
(225.0, 170.0, -135.0), # 右眼右眼角
(-150.0, -150.0, -125.0), # 左嘴角
(150.0, -150.0, -125.0) # 右嘴角
], dtype=np.float32)
image_pts = np.float32([shape[i] for i in [30, 8, 36, 45, 48, 54]])
size = frame.shape
focal_length = size[1]
center = (size[1] // 2, size[0] // 2)
camera_matrix = np.array(
[[focal_length, 0, center[0]],
[0, focal_length, center[1]],
[0, 0, 1]], dtype="double"
)
dist_coeffs = np.zeros((4, 1))
(success, rotation_vector, translation_vector) = cv2.solvePnP(
object_points, image_pts, camera_matrix, dist_coeffs, flags=cv2.SOLVEPNP_ITERATIVE
)
rmat, _ = cv2.Rodrigues(rotation_vector)
angles, _, _, _, _, _ = cv2.RQDecomp3x3(rmat)
return angles
# 定义眼睛纵横比阈值和连续帧数阈值
EYE_AR_THRESH = 0.3
EYE_AR_CONSEC_FRAMES = 48
# 初始化计数器
COUNTER = 0
TOTAL = 0
# 创建锁对象
lock = threading.Lock()
# 打开摄像头
cap = cv2.VideoCapture(60)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 480) # 降低分辨率
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 320)
# 初始化帧计数器和时间戳
fps_counter = 0
start_time = time.time()
# 多线程处理函数
def process_frame(frame):
global COUNTER, TOTAL
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray, 0) # 第二个参数为0,表示不使用upsampling
for face in faces:
landmarks = predictor(gray, face)
shape = [(landmarks.part(i).x, landmarks.part(i).y) for i in range(68)]
left_eye = shape[36:42]
right_eye = shape[42:48]
left_ear = eye_aspect_ratio(left_eye)
right_ear = eye_aspect_ratio(right_eye)
ear = (left_ear + right_ear) / 2.0
if ear < EYE_AR_THRESH:
with lock:
COUNTER += 1
else:
with lock:
if COUNTER >= EYE_AR_CONSEC_FRAMES:
TOTAL += 1
COUNTER = 0
# 绘制68个特征点
for n in range(0, 68):
x, y = shape[n]
cv2.circle(frame, (x, y), 2, (0, 255, 0), -1)
cv2.putText(frame, f"Eye AR: {ear:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
cv2.putText(frame, f"Blink Count: {TOTAL}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
# 计算头部姿势
angles = get_head_pose(shape)
pitch, yaw, roll = angles
cv2.putText(frame, f"Pitch: {pitch:.2f}", (10, 120), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
cv2.putText(frame, f"Yaw: {yaw:.2f}", (10, 150), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
cv2.putText(frame, f"Roll: {roll:.2f}", (10, 180), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
# 判断疲劳状态
if COUNTER >= EYE_AR_CONSEC_FRAMES or abs(pitch) > 30 or abs(yaw) > 30 or abs(roll) > 30:
cv2.putText(frame, "Fatigue Detected!", (10, 210), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (0, 0, 255), 2)
return frame
with ThreadPoolExecutor(max_workers=2) as executor:
future_to_frame = {}
while True:
ret, frame = cap.read()
if not ret:
break
# 提交当前帧到线程池
future = executor.submit(process_frame, frame.copy())
future_to_frame[future] = frame
# 获取已完成的任务结果
for future in list(future_to_frame.keys()):
if future.done():
processed_frame = future.result()
cv2.imshow("Frame", processed_frame)
del future_to_frame[future]
break
# 计算帧数
fps_counter += 1
elapsed_time = time.time() - start_time
if elapsed_time > 1.0:
fps = fps_counter / elapsed_time
fps_counter = 0
start_time = time.time()
cv2.putText(processed_frame, f"FPS: {fps:.2f}", (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()【总结】
【米尔MYC-LR3576核心板及开发板】
这块开发板性能强大,能轻松实现对人脸的疲劳检测,通过计算结果后进入非常多的工业、人工智能等等的实用功能。

米尔RK3576开发板折扣活动火热进行中,购买链接:
2026-04-16
引入STM32MP135F安全芯!米尔MYD-YF13X系统、安全、功能三重升级
米尔电子MYD-YF13X平台资料及SDK迎来重要更新。本次发布的V2.0.0版本在系统版本、安全能力以及功能支持方面进行了全面升级。本次发布引入安全芯片STM32MP135F,并推出搭载该芯片的全新产品MYD-YF135F。同时,对U-Boot、Linux Kernel 以及 Yocto 构建系统进行了升级和优化,为开发者提供更加安全、稳定和完善的软件平台。一、版本升级概览二、U-Boot 更新
2026-04-16
米尔RK3506 DSMC实战,Local Bus高速互联
在工业控制场景中,芯片间的高速数据交互是一个核心需求。传统方案要么依赖串口/网络等低速通道,要么需要昂贵的共享内存架构。米尔RK3506核心板的DSMC接口提供了一种新选择——通过Local Bus协议,用少量引脚实现跨芯片的高速地址空间访问。本文基于MYD-YR3506 Host+MYD-YR3506 Slave的实板联调验证,确认DSMC Local Bus链路能够稳定建立,并在512B、8-
2026-04-16
OpenClaw秒级上线!JishuShell适配米尔RK3576开发板
随着端侧AI从“实验室探索”迈向量产化,“效率”成为了产业落地的生命线。米尔电子联合安谋科技(Arm China)极术社区,通过硬件与软件工具链的深度协同,正式推出了“MYD-LR3576核心板+JishuShell”一体化部署方案。该方案让备受关注的端侧AI Agent——OpenClaw在边缘侧的部署门槛降至冰点。步入2026年,大模型技术的竞争重心正从云端参数规模向端侧应用落地转移。端侧AI
2026-04-10
米尔RK3576 + ROS2 进阶:NPU加速MixFormerV2目标跟随与机械臂抓取实战
回顾上篇:基于RK3576+ROS2 Humble+SLAM Toolbox+Nav2,我们实现了机器人的建图与自主导航。机器人已经能够“走到哪里”。但真正的智能机器人不仅要“走到哪”,还要“看到并操作”——识别特定物体、主动跟随、近距离抓取。本文将在此基础上,集成深度摄像头,实现机器人核心功能:使用米尔RK3576 NPU加速MixFormerV2进行目标跟踪,替代传统OpenCV算法;移动底盘
2026-04-10
智造新方向 · 国产芯未来,米尔即将亮相新唐2026研讨会
在全球绿色能源与智能制造浪潮推动产业升级的当下,半导体技术的创新正持续为各领域发展注入核心动力。为深化产业技术交流、携手共探国产芯发展新机遇,新唐科技携手芯唐南京将于2026年4月14日至5月28日在全国城市巡回举办年度研讨会 ——“智造新方向・国产芯未来”。米尔电子作为新唐的合作伙伴,将携米尔基于新唐MA35D1核心板开发板及解决方案,亮相0417深圳、0421南京、0423北京等场次的研讨会。
2026-04-02
当6 TOPS不再是极限:RK3576+Hailo-8,让高帧率摄像头真正“实时”
在边缘计算领域,算力与实时性之间的博弈从未停止。近期基于米尔MYD-LR3576 开发板+PCIe M.2接口Hailo-8算力卡进行了一系列深度测试,一组实测数据,或许能帮你重新审视边缘AI的“性能天花板”。图:米尔基于RK3576开发板一、RK3576 的算力极限在哪里?RK3576内置NPU由2核组成,具备6 TOPS 算力,在常规轻量级模型推理中表现不俗。但在实际项目中,我们通过多路并发测
2026-03-27
新品!从MINI到工业板:米尔T153开发板工业场景全覆盖
今年1月,米尔发布了MYD-YT153MX-MINI开发板,该产品精准切入国产核心板在中端市场领域,具有极致性价比,自上市即获得良好的市场反响。为方便开发者灵活选择、适配更专业的场景,米尔电子正式推出基于同款全志T153四核异构工业处理器的MYD-YT153MX工业开发板,两款开发板形成完整组合,下面来详细介绍工业开发板的不同之处。工业开发板——为严苛场景而生工业开发板:定位工业应用开发与评估,接
2026-03-19
新品!瑞萨RZ/T2H驱控一体单芯、多轴实时控制,助力工业以太网
米尔电子发布基于瑞萨高端MPU处理器RZ/T2H的CPU模组-MYC-YT2HX核心板及开发板。该产品在前代产品RZ的基础上进行了全面升级,RZ/T2H以其强大的硬件支持、全面的软件开发工具、丰富的工业以太网协议和安全解决方案,以及多操作系统的灵活配置,为客户提供了一个全方位、高效率的开发环境。MYC-YT2HX核心板的推出,旨在解决工业数字化进程中对高性能产品升级以及对复杂网络控制的需求,如工业
2026-03-12
RK3576 + ROS2 SLAM建图与导航实战
前言文档定位与目标读者本文档面向具备一定ROS基础、希望深入理解并在实际项目中部署ROS2 Humble + SLAM Toolbox + Nav2完整建图与导航系统的机器人工程师。我们将从零开始,基于米尔RK3576开发板逐步构建一个功能完备的自主移动机器人系统,涵盖环境搭建、机器人建模、SLAM建图、自主导航以及生产级系统的优化与排错。为什么选择SLAM Toolbox + Nav2?在ROS
2026-03-12
米尔亮相德国嵌入式展2026 Embedded World
2026年3月10日,全球嵌入式系统领域的年度盛会——Embedded World在德国纽伦堡展览中心盛大启幕。作为领先的嵌入式处理器模组厂商,米尔电子携全系列嵌入式核心板、开发板及创新解决方案重磅亮相,与来自全球40多个国家的1100余家展商、32000余名专业观众共赴这场技术盛宴。Embedded World自创办以来,已成为全球规模最大、影响力最深远的嵌入式系统展览会,聚焦嵌入式硬件系统、软