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

2024-12-18

969

来源:米尔电子
本篇源自:优秀创作者 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-04-25
喜讯!米尔电子与安路科技达成IDH生态战略合作,共筑FPGA创新生态
以芯为基,智创未来。近日,领先的嵌入式模组厂商-米尔电子正式与国产FPGA企业安路科技达成IDH生态战略合作。双方将围绕安路科技飞龙SALDRAGON系列高性能FPSoC,联合开发核心板、开发板及行业解决方案,助力开发者开发成功,加速工业控制、边缘智能、汽车电子等领域的创新应用落地。米尔电子&安路科技IDH生态合作证书硬核技术+生态协同安路科技作为国产FPGA领域的标杆企业,其S
2025-04-25
名单揭晓,狂送30套开发板!米尔-安路飞龙派「硬核创造力」
经过米尔电子和安路科技的严格筛选,30位「硬核玩家」从千帆竞逐中脱颖而出,正式成为米尔-安路飞龙派创意秀的玩家。开发者们将以MYD-YM90X开发板为起点,开启一场FPGA的盛宴,在安路飞龙派的赛道上探索无限可能!现将入选的30位开发者/团队名单公布如下(排名不分先后):入选名单后续流程第一步:板卡领取入选的开发者将在近日收到米尔工作人员的联系,我们将为您提供专属优惠券,以便您以1元的价格在myi
2025-04-17
如何在米尔-STM32MP257开发板上实现环境监测系统
本文将介绍基于米尔电子MYD-LD25X开发板(米尔基于STM35MP257开发板)的环境监测系统方案测试。摘自优秀创作者-lugl4313820一、前言环境监测是当前很多场景需要的项目,刚好我正在论坛参与的一个项目:Thingy:91X 蜂窝物联网原型开发平台的试用。把两个项目结合起来,实现一个简单的环境监测系统。二、硬件平台1、米尔-STM32MP257开发板2、Thingy:91X三、项目规
2025-04-10
OpenCV行人检测应用方案--基于米尔全志T527开发板
本文将介绍基于米尔电子MYD-LT527开发板(米尔基于全志T527开发板)的OpenCV行人检测方案测试。摘自优秀创作者-小火苗一、软件环境安装1.安装OpenCVsudoapt-getinstalllibopencv-devpython3-opencv2.安装pipsudoapt-getinstallpython3-pip二、行人检测概论使用HOG和SVM构建行人检测器的关键步骤包括:准备训练
2025-04-03
免费送30套开发板!米尔-安路飞龙派创意秀限时活动
大赛简介为鼓励工程师勇于创新探索的精神,提升实践动手能力,更深度的体验安路飞龙派产品,米尔电子发起“米尔基于安路DR1M90开发板创意秀”,提供米尔安路DR1M90开发板支持开发者创新应用。报名条件:需关注米尔电子公众号的用户;报名对象:面向企业、创客团队、工程师、电子爱好者、研究院等人士,不限个人或团体形式参赛。大赛日程01-活动申请【时间:即日起-2025/04/21】在线填《报名申请表》(见
2025-03-20
一篇文章玩转T113的ARM+RSIC V+DSP三核异构!
近年来,随着半导体产业的快速发展和技术的不断迭代,物联网设备种类繁多(如智能家居、工业传感器),对算力、功耗、实时性要求差异大,单一架构无法满足所有需求。因此米尔推出MYD-YT113i开发板(基于全志T113-i)来应对这一市场需求。米尔基于全志T113-i核心板及开发板part 01T113-i芯片及OpenAMP简介T113-i芯片简介T113-i由两颗ARM A7 、一颗C906(RISC
2025-03-13
ST×米尔STM32MP25x高阶实战培训会
STM32MP25x是ST推出的搭载了双核Cortex-A35@1.5 GHz和Cortex-M33@400 MHz的微处理器。米尔电子基于STM32MP25x推出了MYD-LD25X开发板,开发板配备丰富的扩展接口。为助力开发者深度掌握与应用STM32MP25x处理器,米尔将与ST在2025年4月11日和2025年4月18日分别于深圳、上海联合举办线下高阶实战培训会,本次培训在上一期“Bring
2025-03-13
瑞萨交流日进行中,米尔演讲-RZ/T2H高性能模组赋能工业产品创新
3月12日,2025瑞萨工业以太网技术日在深圳拉开序幕。会议全方位解读瑞萨电子最新EtherCAT/PROFINET/EIP解决方案,洞察行业发展趋势,助力企业高效开发更具竞争力的工业以太网产品。米尔电子作为瑞萨的IDH生态合作伙伴发表演讲,并展出RZ/T2H的核心板开发板、技术方案等。米尔活动现场会上,米尔电子产品经理张先生发表了题为"米尔RZ/T2H高性能模组赋能工业产品创新&quo
2025-03-13
米尔闪耀德国纽伦堡Embedded World 2025,展现嵌入式技术无限可能
2025年3月11日,全球领先的嵌入式解决方案提供商米尔电子,在德国纽伦堡盛大亮相全球规模最大的嵌入式系统展览会Embedded World 2025。此次展会,米尔电子携多款重磅新品和前沿技术方案惊艳登场,为嵌入式开发者带来了一场科技盛宴。米尔展台现场展会现场,米尔电子展示全系列产品,基于国内外知名厂商ST、TI、NXP、瑞萨、AMD(Xilinx)、瑞芯微、全志、新唐、芯驰、海思、紫光同创等主
2025-03-07
六城共启 | 米尔邀您预约2025瑞萨工业以太网技术日
随着工业4.0和工业物联网(IIoT)的发展,现代制造工厂设备的数据传输和自动化控制对实时性、带宽和可靠性提出了更高要求。各类工业以太网技术的普及和迭代不断为拓扑节点设备的确定性、安全通信提供了保障。聚焦工业4.0核心需求,瑞萨电子将于2025年3-4月在全国六大城市(深圳、广州、北京、苏州、西安、上海)巡回举办2025瑞萨工业以太网技术日,为工程师与企业决策者提供实时通信技术最佳解决方案,通过案