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

米尔电子嵌入式 2024-12-20 08:03

本篇源自:优秀创作者 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 cv2import dlibimport numpy as npimport timefrom concurrent.futures import ThreadPoolExecutorimport 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.00.00.0),             # 鼻尖        (0.0-330.0-65.0),        # 下巴        (-225.0170.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 [30836454854]])    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((41))    (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.3EYE_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(068):            x, y = shape[n]            cv2.circle(frame, (x, y), 2, (02550), -1)
        cv2.putText(frame, f"Eye AR: {ear:.2f}", (1030), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)        cv2.putText(frame, f"Blink Count: {TOTAL}", (1060), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)
        # 计算头部姿势        angles = get_head_pose(shape)        pitch, yaw, roll = angles        cv2.putText(frame, f"Pitch: {pitch:.2f}", (10120), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)        cv2.putText(frame, f"Yaw: {yaw:.2f}", (10150), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)        cv2.putText(frame, f"Roll: {roll:.2f}", (10180), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)
        # 判断疲劳状态        if COUNTER >= EYE_AR_CONSEC_FRAMES or abs(pitch) > 30 or abs(yaw) > 30 or abs(roll) > 30:            cv2.putText(frame, "Fatigue Detected!", (10210), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)
return frame

8、创建图像显示线程:

with ThreadPoolExecutor(max_workers=2as 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}", (1090), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (00255), 2)
if cv2.waitKey(1) & 0xFF == ord('q'):

实现效果:


根据检测的结果,我们就可以来实现疲劳提醒等等的功能。
整体代码如下:
import cv2import dlibimport numpy as npimport timefrom concurrent.futures import ThreadPoolExecutorimport 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.00.00.0),             # 鼻尖        (0.0-330.0-65.0),        # 下巴        (-225.0170.0-135.0),     # 左眼左眼角        (225.0170.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 [30836454854]])    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]],         [001]], dtype="double"    )
    dist_coeffs = np.zeros((41))    (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.3EYE_AR_CONSEC_FRAMES = 48
# 初始化计数器COUNTER = 0TOTAL = 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 = 0start_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(068):            x, y = shape[n]            cv2.circle(frame, (x, y), 2, (02550), -1)
        cv2.putText(frame, f"Eye AR: {ear:.2f}", (1030), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 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}", (10120), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)        cv2.putText(frame, f"Yaw: {yaw:.2f}", (10150), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 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!", (10210), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (00255), 2)
    return frame
with ThreadPoolExecutor(max_workers=2as 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开发板折扣活动火热进行中,购买链接:

https://detail.tmall.com/item.htm?id=846172160887


米尔电子最新“明星产品”速报







 米尔电子 
领先的嵌入式处理器模组厂商
关注“米尔MYiR”公众号
不定期分享产品资料及干货
第一时间发布米尔最新资讯

米尔电子嵌入式 米尔-领先的嵌入式处理器模组厂商,专业为您提供CPU模组,NXP、ST、全志、XILINX等核心板开
评论
  • 概述 Intel 要求用户为其10代FPGA器件使用特定的上电和掉电顺序,这就要求用户在进行FPGA硬件设计的时候必须选择恰当的FPGA供电方案,并合理控制完整的供电上电顺序。经过在Cyclone 10 GX测试板上实际验证,统一上电确实会导致FPGA无法正常工作,具体表现为JTAG接口无法探测或识别到目标器件。上电顺序要求 Cyclone 10 GX,Arria 10以及Stratix 10系列器件所有的电源轨被划分成了三个组合,三组电源轨要求依次上电,如图1所示,为三组电源轨上电顺序示意图。
    coyoo 2024-12-25 14:13 38浏览
  • “金字招牌”的户外叙事。2024年的夏天似乎异常炙热,体育迷们的心跳也随之澎湃,全球瞩目的体育盛宴——巴黎奥运会在此刻上映。在这个充满荣耀与梦想的夏天,我们见证了无数激动人心的瞬间:男子4X100米混合泳接力决赛中,潘展乐的最后一棒,气壮山河,中国队的历史性夺冠,让整个泳池沸腾;射击10米气步枪混合团体决赛,黄雨婷和盛李豪的精准射击,为中国队射落首金,展现了年轻一代的力量;乒乓球男单四分之一比赛中,樊振东的惊天逆转令人难以忘怀,凭借坚韧不拔的意志和卓越的技术,成功挺进半决赛,并最终夺冠……在这一
    艾迈斯欧司朗 2024-12-25 19:30 53浏览
  • 据IDTechEx最新预计,到2034年,全球汽车舱内传感(In-Cabin Sensing,ICS)市场将超过85亿美元。若按照增长幅度来看,包含驾驶员监控系统(DMS)、乘员监控系统(OMS)、手势控制和生命体征监测等高级功能在内的舱内传感市场预计2020年到2034年将增长11倍。感光百科:ICS中的光源选择01、政策推动带来的“硬”增长作为其中的增长主力,舱内监控系统应用(包含DMS和OMS等)被推动增长的首要因素正是法规。据统计,中国、欧盟、美国、韩国、印度等主要汽车国家或地区已推出相
    艾迈斯欧司朗 2024-12-25 19:56 53浏览
  • 引言  LIN(Local Interconnect Network)是一种针对汽车电子系统应用的串行通信协议,主要用于汽车电子控制单元(ECU)之间的通信。LIN总线的特点是成本低、速率低、通信距离短、连接节点少,主要用于对带块要求低、实时性要求不高的控制任务,例如车门控制、天窗控制、座椅控制、车内照明等功能。LIN总线采用的是主从式架构,由主节点基于调度表调度网络中的通信。  LIN总线的错误类型  尽管LIN协议设计简单,具有低带
    北汇信息 2024-12-25 14:18 46浏览
  • RK3506是瑞芯微Rockchip在2024年第四季度全新推出的Arm嵌入式芯片平台,三核Cortex-A7+单核Cortex-M0多核异构设计,CPU频率达1.5Ghz, M0 MCU为200Mhz。RK3506平台各型号芯片该怎么选,看这篇文章就够了。RK3506各型号RK3506有3个型号,分别是RK3506G2、RK3506B、RK3506J,配置参数如图: 配置差异解析总的来说,RK3506各型号间的差异主要体现在内存、工作温度和封装上‌:内存差异‌:RK3506G2‌集成
    Industio_触觉智能 2024-12-25 10:27 23浏览
  • 全球照明技术创新领航者艾迈斯欧司朗,于2024年广州国际照明展览会同期,举办【智慧之光】· 艾迈斯欧司朗-照明应用研讨会,以持续的技术创新,推动光+概念的全面落地。现场还演示了多款领先照明技术,且由资深工程师倾情解读,另有行业大咖深度洞察分享,助你开启“光的无限可能”探索之旅!精彩大咖分享引领未来照明无限遐想艾迈斯欧司朗精心准备了照明领域专业大咖的深度分享,无论是照明领域的资深从业者,还是对照明科技充满好奇的探索者,在这里,您都将大有所获。在艾迈斯欧司朗照明全球产品市场VP Geral
    艾迈斯欧司朗 2024-12-25 20:05 44浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-26 09:19 75浏览
  • 在谐振器(无源晶振)S&A250B测试软件中,DLD1到DLD7主要用于分析晶体在不同驱动功率下的阻抗变化。此外,还有其他DLD参数用于反映晶振的磁滞现象,以及其频率和功率特性。这些参数可以帮助工程师全面了解KOAN晶振在不同功率条件下的动态特性,从而优化其应用和性能。磁滞现象晶振的磁滞现象(Hysteresis)是指在驱动功率变化时,晶体的阻抗或频率无法立即恢复至初始状态,而表现出滞后效应。1. DLDH: Hysteresis Ratio (MaxR/MinR)在不同驱动
    koan-xtal 2024-12-26 12:41 52浏览
  • 本文介绍瑞芯微开发板/主板Android系统APK签名文件使用方法,触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,各类接口一应俱全,帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。系统签名文件生成APK系统签名文件,具体可参考此文章方法RK3588主板/开发板Android12系统APK签名文件生成方法,干货满满使用方法第一步,修改APK工程文件app/src/build.gradle,并添加以下内容: android {     na
    Industio_触觉智能 2024-12-26 09:20 54浏览
  • 今年AI技术的话题不断,随着相关应用服务的陆续推出,AI的趋势已经是一个明确的趋势及方向,这也连带使得AI服务器的出货量开始加速成长。AI服务器因为有着极高的运算效能,伴随而来的即是大量的热能产生,因此散热效能便成为一个格外重要的议题。其实不只AI服务器有着散热的问题,随着Intel及AMD 的CPU规格也不断地在提升,非AI应用的服务器的散热问题也是不容小觑的潜在问题。即便如此,由于目前的液冷技术仍有许多待克服的地方,例如像是建置成本昂贵,机壳、轨道、水路、数据中心等项目都得重新设计来过,维修
    百佳泰测试实验室 2024-12-26 16:33 30浏览
  • 新能源汽车市场潮起潮落,只有潮水退去,才能看清谁在裸泳。十年前,一批新能源汽车新势力带着创新的理念和先进的技术,如雨后春笋般涌入中国汽车市场,掀起一场新旧势力的角逐。经历市场的激烈洗礼与投资泡沫的挤压,蔚来、理想、小鹏等新势力车企脱颖而出,刷爆网络。不曾想,今年新势力车企杀出一匹“超级黑马”,爬上新势力车企销量榜前三,将蔚来、小鹏等昔日强者甩在了身后,它就是零跑汽车。公开数据显示,11月份,零跑汽车实现新车交付量约4.02万辆,同比增长117%,单月销量首次突破4万辆;小鹏汽车当月共交付新车约3
    刘旷 2024-12-26 10:53 86浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦