首页 > 其他分享 >基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案

基于米尔瑞芯微RK3576核心板/开发板的人脸疲劳检测应用方案

时间:2024-12-19 11:10:28浏览次数:3  
标签:RK3576 frame cv2 开发板 瑞芯微 future time np eye

本篇源自:优秀创作者 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,frame,cv2,开发板,瑞芯微,future,time,np,eye
From: https://www.cnblogs.com/cbd7788/p/18616725

相关文章

  • RTL8211F以太网千兆RGMII开发板 使用说明
    深圳市飞录科技有限公司www.szfpga.com1.概述    RGMII 开发板主芯片是RTL8211FD。配套国产GOWIN的2AR-18和NR-9C的开发板,测试RGMII的千兆以太网数据发送和接收功能。  开发板的代码是基于MAC模式,通过循环发送计数器来判断包发送和接收是否正确。   2.操......
  • NXP-IMX-8M 开发板-uuu工具下载、源码编译、添加环境变量
    前言全局说明一、说明1.1环境:Windows11家庭版23H222631.3737Ubuntu18.04.6LTS(Linuxqt-vm5.4.0-150-generic#167~18.04.1-UbuntuSMPWedMay2400:51:42UTC2023x86_64x86_64x86_64GNU/Linux)二、uuu刷机工具2.1下载https://github.com/nxp-imx/mfg......
  • VMware环境下,同时烧录固件检测不到设备如何解决?触觉智能鸿蒙开发板演示
    本文介绍PC电脑端运行VMware环境下,同时烧录固件检测不到设备的解决方法。触觉智能PurplePiOH鸿蒙开发板演示,搭载了瑞芯微RK3566芯片,类树莓派设计,Laval官方社区主荐,已适配全新OpenHarmony5.0Release系统!PC端烧录固件时提示没有发现设备按照各型号烧录手册中进入loader模式的操......
  • [迅为RK3568开发板]非科班也能玩转Android应用,体验QT跨平台能力
      QTforAndroid优势01-跨平台的优越性Qt是一个强大的跨平台框架,允许开发者使用相同的代码库来构建多个平台上的应用,包括Windows、macOS、Linux以及移动平台Android和iOS。这意味着开发者不需要为每个平台单独编写代码,可以显著减少开发时间和维护成本。同时,Qt提供......
  • 基于米尔全志T527开发板的OpenCV进行手势识别方案
    本文将介绍基于米尔电子MYD-LT527开发板(米尔基于全志T527开发板)的OpenCV手势识别方案测试。摘自优秀创作者-小火苗米尔基于全志T527开发板 一、软件环境安装1.安装OpenCVsudo apt-get install libopencv-dev python3-opencv  2.安装pipsudo apt-get install......
  • 使用全志H3开发板进行B站无人直播推流
    此篇文章在2023年5月24日被记录全志H3直播推流1、系统镜像烧录系统镜像尽量使用linux或者ubuntu原版镜像,不要使用不安全的三方镜像,我在这里使用friendlycore的卡刷包,代号focal,实际上就是ubuntu20.04,先使用工具烧录到内存卡里,然后插在机器上,使用eflash命令行或者图形化界面......
  • 瑞芯微主板/开发板Linux系统播放音频方法,触觉智能RK3562开发板演示
    通过桌面双击播放音频​通过桌面播放音频没有声音时,可以查看sound(声音)选项是否设置为speakers(扬声器)播放。命令行播放音频通过aplay-l查看声卡系统默认配置的声卡是rockchipes8388,通过aplay-l命令确定是第几个声卡,如下所示:root@Industio:/$aplay-l****ListofPLAYB......
  • 粤嵌GEC6818开发板 手动制作64位Linux系统启动SD卡
    背景:之前的帖子中也提到了,可以用FriendlyARM提供的sd_fuse工具制作可以给使用S5P6818SOC设备使用的SD卡,由于GEC6818的配置和三星Nexell的Raptor,drone开发板以及友善的nanopi3系列本质是很相近的,所以他们的系统、uboot、甚至是bootloader小加修改就可以跑在粤嵌的GEC6818开发......
  • RK3588主板/开发板Android12系统APK签名文件生成的方法,干货满满
    本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-I......
  • 基于STM32单片机的智能点滴输液报警器液位检测电机无线WiFi手机APP设计DR-01非接触液
    25-040-点滴检测+药水液位+电机控制+上下限+按键+声光提醒+TFT彩屏+WiFi产品功能描述:本系统由STM32F103C8T6单片机核心板、TFT液晶显示电路、无线无线WIFI/、点滴检测模块、步进电机控制电路、DR-01非接触液位传感器检测电路、蜂鸣器声光报警、按键电路、电源电路组成。【1......