人脸疲劳检测应用-米尔基于RK3576核心板/开发板

2024-12-18

1358

来源:米尔电子
本篇源自:优秀创作者 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 frame
8、创建图像显示线程:
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开发板折扣活动火热进行中,购买链接:
2025-08-14
12路1080P高清视频流,米尔RK3576开发板重塑视频处理极限
在智能视觉技术不断发展的今天,多路摄像数据的处理与传输已成为众多应用场景的核心需求。从智能安防监控领域的全面覆盖,到工业视觉处理网关的精准检测,再到车载环视融合平台的实时驾驶辅助以及智慧社区AI防控的快速响应,多路摄像数据的处理与传输已成为关键需求,而高效且低延时的解决方案则是实现这些应用的核心。目前多路摄像传输方案往往存在一定局限,接入路数有限,难以满足大规模监控场景的需求,且延迟较高,影响实时
2025-08-14
共建生态,米尔将出席2025安路科技FPGA技术沙龙
在数字化浪潮席卷全球的今天,FPGA技术正成为驱动创新的核心引擎。2025年8月21日,深圳将迎来一场聚焦FPGA技术与产业应用的盛会——2025安路科技FPGA技术沙龙。本次沙龙以“定制未来 共建生态”为主题,汇聚行业专家、企业代表及技术开发者,探讨前沿技术趋势,解锁定制化解决方案,共建开放共赢的FPGA生态圈!米尔作为领先的嵌入式处理器模组厂商,将携安路FPGA核心板和开发板亮相,并发表主题演
2025-08-08
如何在RK3576开发板上板端编译OpenCV并搭建应用
本文将介绍基于米尔电子MYD-LR3576开发板(米尔基于瑞芯微 RK3576开发板)的板端编译OpenCV及环境搭建方案的开发测试。摘自优秀创作者-短笛君RK3576具有如下配置:4× Cortex-A72(大核,主频最高 2.2GHz)4× Cortex-A53(小核,主频最高 1.8GHz)NPU(AI加速单元):独立 NPU,算力典型值6 TOPS(INT8)支持 TensorFlow L
2025-08-08
倒计时!米尔-安路飞龙派创意秀奖品等您领~~
创意秀活动进入倒计时阶段2025年米尔-安路飞龙派FPGA FPSoC创意开发大赛即将于8月15日正式收官(原定于6月15日,已延期到8月15日)。作为国产工业级FPGA领域的赛事,本次活动已吸引多支开发团队参与,基于MYD-YM90X开发板产出了众多创新解决方案。现距截稿仅剩7天,米尔特别提醒尚未提交作品的开发者把握最后几天,分享您的技术创作,申领米尔电子的奖品。活动链接:https://mp
2025-07-25
如何在RK3576开发板上运行TinyMaix :超轻量级推理框架--基于米尔MYD-LR3576开发板
本文将介绍基于米尔电子MYD-LR3576开发平台部署超轻量级推理框架方案:TinyMaix摘自优秀创作者-短笛君TinyMaix 是面向单片机的超轻量级的神经网络推理库,即 TinyML 推理库,可以让你在任意低资源MCU上运行轻量级深度学习模型。关键特性核心代码少于 400行(tm_layers.c+tm_model.c+arch_cpu.h),代码段(.text)少于3KB低内存消耗支持 I
2025-07-21
RKDC2025 丨米尔亮相第九届瑞芯微开发者大会,共绘工业数智新图景
2025年7月17日,第九届瑞芯微开发者大会(RKDC!2025)在福州海峡国际会展中心开幕。米尔电子作为瑞芯微IDH生态合作伙伴受邀出席此次盛会。米尔不仅为广大用户带来米尔基于RK35系列处理器的核心板和开发板/工控机,更展示了多款针对不同行业的解决方案,吸引了广大参观者前来参观了解。展台现场此次米尔电子重点展出了基于瑞芯微RK3576、RK3568、RK3562、RK3506处理器的核心板,搭
2025-07-10
米尔将出席瑞芯微第九届开发者大会
2025年7月17日~18日,第九届瑞芯微开发者大会(RKDC!2025)将在福州海峡国际会展中心盛大启幕。米尔电子作为瑞芯微IDH生态合作伙伴,将携RK系列核心板、开发板、解决方案等产品出席此次盛会。届时,诚邀您莅临现场参观指导(展位号:F11),共话AI新技术的浪潮,推动电子产品从“IoT功能设备”向“场景化智能终端的演进,见证技术突破与生态协同!
2025-07-10
两款SoC方案评测:国产芯遍地开花
在工业自动化、电力智能设备等领域,传统欧美芯片长期占据主导地位。瑞芯微推出的RK3506J以及RK3562J工业级处理器,以“性价比+多核异构+工业级设计”为核心竞争力,直面工业场景对实时性、可靠性的严苛需求。米尔电子基于该系列芯片打造的开发板(MYD-YR3506J & MYD-YR3562J)凭借工业级的宽温运行、丰富的高速接口、多种外设资源,成为国产工业芯片落地的重要载体。本期视频与
2025-07-03
如何部署流媒体服务实现监控功能--基于米尔TI AM62x开发板
本文将介绍基于米尔电子MYD-YM62X开发板(米尔基于TI AM62开发板)的部署流媒体服务实现监控功能方案的开发测试。摘自优秀创作者-HonestQiao米尔-TI AM62x开发板除了可以用官方的CSI摄像头,还可以直接使用第三方的USB摄像头,我手头正好有几个个USB摄像头:经过实测,可以很好的在米尔-TI AM62x开发板上使用。这篇分享,就是在这块开发板上部署流媒体服务,通过USB摄像
2025-06-26
米尔STM32MP25系列产品荣获“2024‘物联之星’创新产品奖”
在“2024‘物联之星’中国物联网行业年度评选”中,米尔电子的MYC-LD25X核心板及开发板凭借其高性能、多接口、边缘算力等优势,荣获2024“物联之星”创新产品奖。米尔MYC-LD25X核心板及开发板获奖图获奖产品介绍MYC-LD25X核心板及开发板:米尔基于STM32MP257设计的嵌入式处理器模块MYC-LD25X核心板及开发板。核心板基于STM32MP2系列是意法半导体推出最新一代工