☰
Python疲劳驾驶检测系统:dlib人脸关键点与EAR/MAR算法实现
2026/10/11 4:27:48 网站建设 项目流程

简介:这是一套基于Python与面部特征识别的驾驶员疲劳检测系统源码,主要面向计算机、人工智能相关专业毕业设计学生,以及需要快速落地疲劳驾驶预警场景的开发者。系统通过摄像头捕捉驾驶员面部关键点,结合眼睛闭合频率、打哈欠等特征判断疲劳状态,并给出提醒,可直接应用于驾校培训、长途运输监控或高速收费站辅助检查。源码压缩包共24个文件,以5个Python脚本为核心实现检测逻辑,10个XML文件用于工程配置,另含项目说明文档、提示音频及开发环境配置等,整体约68.33MB,下载解压后即可运行。目前已有1359人学习下载,适合作为毕业设计参考或二次开发基础。包内包含可直接运行的检测主程序、模型配置文件与项目说明文档,目录结构清晰,便于快速理解各模块分工并上手修改调试。

1. 驾驶员面部疲劳检测系统是什么:一套 Python 毕设源码包的完整技术画像

“Python 基于驾驶员面部特征的疲劳检测系统”是典型的计算机视觉毕业设计选题。它用普通摄像头对准驾驶员,实时识别闭眼、频繁眨眼和打哈欠,把“困了”这个主观状态变成一组可计算的数值,再由报警模块提醒驾驶人。相比脑电、心电这类接触式方案,它只用视觉数据,部署成本低、展示直观,因此在高校毕业设计题目里常年排在前列。如果你手头已经拿到一份 .rar 源码包,或者正打算按这个题目从零写一个,这篇笔记会把算法原理、代码结构、阈值调优、常见故障和验证方法从头到尾拆开讲,目标是省掉你大半周的绕路时间。

常见做法是 dlib 正面人脸检测器外加 68 点关键点回归,再用眼睛纵横比 EAR 和嘴巴纵横比 MAR 两个指标做疲劳判断。整套系统只需要一个普通 USB 摄像头,代码量不大,却覆盖了图像采集、特征提取、状态判断、报警联动四个完整环节。这也是它为什么在毕业设计里受欢迎:既有理论深度,又能在答辩现场做实时演示,非常适合用来展示。接下来直接从算法原理进入代码层面,讲清楚这套系统是怎么从一帧画面推演出一声报警的。

2. 核心算法拆解:dlib 68 点关键点与 EAR/MAR 特征怎么算

2.1 人脸 68 点关键点定位:选 dlib 还是别的方案

疲劳检测的第一步不是算眼睛,而是先找到人脸和五官的位置。常见方案有两类:一类是 dlib 的 frontal face detector 配 shape_predictor_68_face_landmarks.dat 模型,另一类是 MediaPipe 的 Face Mesh。毕业设计源码里绝大多数采用前者,原因很直接:它把检测和人脸关键点标定做成了一个稳定封装,单帧在普通笔记本上只需要几毫秒到十几毫秒,文档和论文可引用的案例也最多。

dlib 的 68 点模型把一张人脸拆成 68 个坐标点:轮廓 0~16,眉毛 17~26,鼻子 27~35,右眼 36~41,左眼 42~47,外唇 48~59,内唇 60~67。正因为眼睛和嘴巴的关键点索引是固定的,后续计算 EAR、MAR 时只需要按索引取坐标,代码写起来非常直白。MediaPipe 的 468 点方案精度更高、移动端友好,但返回的数据结构和 dlib 完全不一样,改成它等于重写整套特征计算逻辑,除非你有特殊需求,否则不建议在毕业设计阶段折腾这个替换。

模型选型上还有个容易被忽略的点:dlib 的正面人脸检测器对偏转角度敏感。驾驶员低头看手机、大幅转头时,检测框会丢失或漂移。解决思路一般是摄像头安装在仪表盘上方尽量正对驾驶员,或者通过设置最小检测框面积来过滤远距离误检,而不是盲目换更贵的检测模型。

2.2 眼睛纵横比 EAR:一个公式把“闭眼”变成连续数值

眨眼检测不能只靠“眼睛区域像素颜色变暗”来判断,侧面光线、肤色、眼镜都会干扰。业界普遍采用眼睛纵横比 EAR,它基于六个人脸关键点的欧氏距离比例,描述的是眼睑相对张开度。闭眼时两条垂直距离趋近于零,水平距离变化不大,所以 EAR 会明显下降;睁眼时 EAR 落在相对稳定的区间,典型值一般在 0.25~0.4 之间。

import numpy as np def eye_aspect_ratio(landmarks, eye_indices): # eye_indices 传入 6 个关键点索引,例如右眼 [36,37,38,39,40,41] # 垂直方向的欧氏距离:眼角内侧向上/向下各取一对点 A = np.linalg.norm(landmarks[eye_indices[1]] - landmarks[eye_indices[5]]) B = np.linalg.norm(landmarks[eye_indices[2]] - landmarks[eye_indices[4]]) # 水平方向的欧氏距离:内眼角到外眼角 C = np.linalg.norm(landmarks[eye_indices[0]] - landmarks[eye_indices[3]]) # 纵横比 = (垂直距离之和) / (2 * 水平距离) return (A + B) / (2.0 * C)

逻辑说明:landmarks 是 68 个 (x, y) 坐标组成的 Numpy 数组,eye_indices 是眼睛对应的索引列表。A、B 分别表示上下眼睑两对关键点之间的垂直距离,C 是眼角连线长度。EAR 本质上是一个比例值,跟人脸在画面里的绝对大小无关,所以摄像头远近变化不会导致数值剧烈漂移,这是它适合做实时的原因。

参数说明:右眼使用索引 36~41,左眼使用 42~47,两个眼睛分别算 EAR 后取平均。初始化阈值时可以参考 0.2~0.3 区间,但实际值跟摄像头角度、人脸距离、眼镜框都有关系,后面第 4 章会专门讲标定。

2.3 嘴巴纵横比 MAR:“打哈欠”和“说话”靠持续时间分开

打哈欠检测的思路跟闭眼类似,用嘴巴纵横比 MAR 描述嘴部张开程度。MAR 用的是外唇 6 个关键点:左右嘴角、上下嘴唇各取两个点,同样计算垂直距离与水平距离的比例。张嘴时 MAR 显著升高,闭嘴状态则稳定在较低区间。

def mouth_aspect_ratio(landmarks): # 外唇点索引 48~59,这里取 48、51、53、54、57、59 六个点做比例 p48 = landmarks[48] # 右嘴角 p54 = landmarks[54] # 左嘴角 p51 = landmarks[51] # 上唇中心 p57 = landmarks[57] # 下唇中心 p53 = landmarks[53] # 上唇偏左(靠近左嘴角) p59 = landmarks[59] # 下唇偏左 A = np.linalg.norm(p51 - p57) B = np.linalg.norm(p53 - p59) C = np.linalg.norm(p48 - p54) return (A + B) / (2.0 * C)

说话时嘴也在不停开合,MAR 会产生快速上下波动的波形;打哈欠则不同,嘴部会持续保持张开状态 3~5 秒。所以代码里不会单独看某一帧的 MAR,而是统计连续多少帧超过阈值。常见的处理窗口是 15~25 帧,对应大约 0.5 秒左右的持续张开。只凭单帧阈值判断,会把一次普通说话误判成打哈欠,这是新手最容易踩的坑。

3. 源码结构与主循环:从摄像头画面到报警触发的完整链路

3.1 项目目录结构:看清源码包里每个文件是干什么的

拿到一份疲劳检测的毕设源码包,先把目录结构理清再跑代码。常见做法的模块划分大概是这样的:

fatigue_detect/ ├── main.py # 主循环,摄像头采集与各模块调用 ├── config.py # 所有阈值参数集中管理 ├── feature.py # EAR/MAR 特征计算函数 ├── alarm.py # 报警逻辑:声音与画面提示 ├── calibration.py # 个性化标定脚本 ├── models/ │ └── shape_predictor_68_face_landmarks.dat ├── sounds/ │ └── alarm.wav └── requirements.txt

main.py 是整个系统的入口,负责打开摄像头、逐帧调用检测和特征计算;feature.py 里是 2.2 和 2.3 写的 EAR/MAR 函数;alarm.py 负责播放提示音或在画面里叠加文字。config.py 的出现很重要,把阈值集中到一个文件里,调参的时候不用满项目翻代码。你拿到的源码不一定完全同名,但模块职责大体逃不出这套结构。

初次跑通之前不要急着改任何算法,先按 requirements.txt 把 opencv-python、dlib、numpy、pygame 这几样装好,再把模型文件放在对应路径。Windows 上如果 pip 安装 dlib 报编译错误,优先找预编译好的 wheel 安装,省掉大量折腾时间。

3.2 主循环:逐帧完成人脸检测、特征计算与事件计数

主循环是整个系统的骨架。每一帧的流程是:读取画面、转灰度、人脸检测、关键点定位、计算 EAR/MAR、更新连续帧计数、判断是否触发报警。下面这段代码是主循环的核心逻辑,可以直接用来理解源码里的执行顺序。

import cv2 import dlib import numpy as np import pygame # 初始化模型 detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat") # 参数集中定义 EYE_AR_THRESH = 0.25 # 闭眼判定阈值 EYE_CONSEC_FRAMES = 20 # 连续闭眼多少帧算一次疲劳事件 MOUTH_AR_THRESH = 0.65 # 打哈欠判定阈值 MOUTH_CONSEC_FRAMES = 15 # 连续张嘴多少帧算一次哈欠事件 cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) eye_counter = 0 mouth_counter = 0 while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = detector(gray, 0) for face in faces: shape = predictor(gray, face) # 转换成 Numpy 坐标数组 landmarks = np.array([[shape.part(i).x, shape.part(i).y] for i in range(68)]) # 双眼 EAR 取平均 left_ear = eye_aspect_ratio(landmarks[42:48]) right_ear = eye_aspect_ratio(landmarks[36:42]) ear = (left_ear + right_ear) / 2.0 mar = mouth_aspect_ratio(landmarks) # 闭眼事件连续计数 if ear < EYE_AR_THRESH: eye_counter += 1 else: eye_counter = 0 # 哈欠事件连续计数 if mar > MOUTH_AR_THRESH: mouth_counter += 1 else: mouth_counter = 0 # 输出报警状态 if eye_counter >= EYE_CONSEC_FRAMES: cv2.putText(frame, "FATIGUE!", (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2) if mouth_counter >= MOUTH_CONSEC_FRAMES: cv2.putText(frame, "YAWN!", (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 128, 255), 2) cv2.imshow("Fatigue Detection", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break cap.release() cv2.destroyAllWindows()

逻辑说明:主循环每一帧先做一次人脸检测,得到人脸框后传给关键点预测器,接着把 68 个坐标点放入 landmarks 数组。EAR 和 MAR 的计算复用第 2 章的独立函数。连续帧计数只有在一整段视频里持续超过阈值时才触发报警,这样单帧噪声不会制造假警报。

参数说明:cv2.VideoCapture 的第二个参数 cv2.CAP_DSHOW 在 Windows 下可以避免摄像头启动慢或黑屏的问题;detector(gray, 0) 的第二个参数表示对图像不做金字塔上采样,速度更快但小脸检测会弱一些。main.py 里真正跑起来的逻辑基本就是这一段,剩下的报警联动只是把这个循环的计数结果接出去。

3.3 疲劳状态机:不靠单次信号报警,靠事件序列

很多同学拿到源码后会有一个困惑:为什么我闭了一下眼,系统没有报警?因为单次连续闭眼 20 帧在 30 帧率下意味着眼睛闭了接近 0.7 秒,这已经是明显疲劳信号。但更严谨的做法是设计一个疲劳状态机,把“连续闭眼”和“打哈欠”当作两类独立事件,各自累计分值,达到阈值后才触发声光报警。这样能显著降低正常驾驶时被误报的频率。

class FatigueStateMachine: def __init__(self): self.score = 0 # 当前疲劳分 self.last_event_time = 0 # 上一次事件发生时间 self.alarmed = False # 当前是否处于报警状态 def update(self, is_blink_event, is_yawn_event, now_time): # 事件到达:闭眼事件加 2 分,哈欠事件加 1 分 if is_blink_event: self.score += 2 if is_yawn_event: self.score += 1 # 两分钟内没有新事件,分数缓慢衰减 if now_time - self.last_event_time > 120: self.score = max(0, self.score - 1) self.last_event_time = now_time # 分数达到 3,触发报警并锁定,避免反复响 if self.score >= 3 and not self.alarmed: self.alarmed = True return True return False

逻辑说明:闭眼事件是强疲劳信号,一次给 2 分;打哈欠是弱信号,一次给 1 分。两分钟内没有新事件就自动衰减,避免长时间驾驶累积到一个不可逆的高分。报警后进入 alarmed 状态,直到手动重置或分数降回安全区间。加了这一层之后,误报率通常能明显下降。

参数说明:score 的触发值设为 3,等于说“一次连续闭眼加一次哈欠”或者“两次连续闭眼”才报警。如果你希望系统更保守,可以把触发值提高到 4;如果希望更敏感,改成 2 也行。这个数值没有绝对标准,取决于应用场景和验收要求。

4. 阈值参数怎么调:三个关键旋钮与一个 10 秒标定流程

4.1 三个关键参数:EAR 阈值、MAR 阈值、连续帧数

疲劳检测系统里真正决定行为的是三个参数:EAR 阈值、MAR 阈值和连续帧数。很多人拿到源码后直接跑,发现系统要么对闭眼毫无反应,要么正常眨眼都被报警,问题几乎都出在这三个值上。下面这张表是我在实际调参时常用的初始范围:

参数初始值调低效果调高效果
EYE_AR_THRESH0.25更不容易触发闭眼更敏感,但误报多
EYE_CONSEC_FRAMES20报警更快报警延迟更久
MOUTH_AR_THRESH0.65更容易识别张嘴必须张大嘴才触发
MOUTH_CONSEC_FRAMES15对短暂张嘴敏感只识别持续哈欠

这里的关键认知是:EAR 阈值不是由代码决定的,而是由被检测者的脸部特征和摄像头角度决定的。有的人睁眼时 EAR 基线是 0.35,有的人只有 0.28,一刀切用 0.25 对前者太宽松,对后者又太敏感。MAR 同理,打哈欠时张嘴幅度因人而异,固定在 0.65 对嘴小的人其实很容易漏检。

连续帧数的选择需要结合帧率理解。假设摄像头实际帧率是 30 FPS,那么连续 20 帧 EAR 低于阈值意味着眼睛持续闭合约 0.67 秒;如果机器性能不行帧率掉到 15 FPS,同样 20 帧变成 1.3 秒,疲劳响应就慢了一倍。所以调帧数前先确认当前实际帧率,不能只看代码里的数字。

4.2 十秒个性化标定:用统计分布代替拍脑袋设阈值

与其把阈值当成玄学反复试,不如加一个 10 秒的标定流程。让被测者坐正,面对摄像头正常睁眼 10 秒,程序采集这一段时间的 EAR 数据,用百分位数自动推一个适合这个人的阈值。这种做法的好处是,换一个驾驶员时不用重新手工调参,跑一遍标定脚本即可。

def calibrate_eye_threshold(detector, predictor, video_source=0, seconds=10): cap = cv2.VideoCapture(video_source, cv2.CAP_DSHOW) ear_values = [] start = time.time() while time.time() - start < seconds: ret, frame = cap.read() if not ret: continue gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = detector(gray, 0) if len(faces) == 1: shape = predictor(gray, faces[0]) landmarks = np.array([[shape.part(i).x, shape.part(i).y] for i in range(68)]) ear = (eye_aspect_ratio(landmarks[36:42]) + eye_aspect_ratio(landmarks[42:48])) / 2.0 ear_values.append(ear) arr = np.array(ear_values) p5 = np.percentile(arr, 5) p50 = np.percentile(arr, 50) # 阈值取中位数与 5% 分位数之间的一个保守折中 suggested = p50 - (p50 - p5) * 0.7 return round(suggested, 3)

逻辑说明:10 秒内被测者正常睁眼会有几次自然眨眼,自然眨眼时的 EAR 会瞬间掉下去,所以直接取平均会被眨眼拉低。取 5% 分位数和中位数,再向中位数方向回退 70%,得到的值既能避开自然眨眼的低谷,又不会比真实闭眼阈值高太多。实测下来比手工猜 0.25 靠谱得多。

参数说明:seconds 是采集时长,10 秒足够覆盖十几次自然眨眼;返回的 suggested 是单眼平均 EAR 的阈值。标定的前提是画面里始终只有一张脸,并且被测者坐姿正对摄像头,否则统计值会失真。MAR 阈值也可以用同样思路,让被测者正常说话或念一段文字,统计闭嘴时的 MAR 分布再推阈值。

4.3 提速优化:跳帧、分辨率与多线程

实时检测最怕的就是帧率不够,画面一卡一卡,驾驶员已经闭眼 2 秒报警还没弹出来。常见瓶颈不是 EAR 计算,而是每帧都做全图人脸检测。dlib 的正面人脸检测器对 640x480 的灰度图单次大约耗时 10~30 毫秒,机器配置一般的情况下很容易吃掉全部帧时间。

常见的优化手段是跳帧检测。人脸在连续帧之间位移很小,完全没有必要每帧都跑检测器。可以让检测每隔一帧执行一次,中间帧直接复用上一帧的人脸框做关键点定位。这样检测耗时直接减半,关键点定位本身很快,帧率能明显回升。另外把处理分辨率从 1280x720 降到 640x480,灰度转换和检测都有收益,代价只是远距离小脸的检出率下降。

frame_count = 0 skip_detect = 1 # 每 2 帧检测一次人脸框 while True: ret, frame = cap.read() if not ret: break frame_count += 1 if frame_count % (skip_detect + 1) == 0 or last_face is None: gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = detector(gray, 0) last_face = faces[0] if len(faces) > 0 else None else: # 使用上一帧的人脸框位置,跳过整帧检测 pass

多线程是另一个方向:图像采集线程只负责把摄像头帧放进队列,检测线程从队列取帧计算,两件事并行。Python 的 GIL 对这种混合工作负载影响不算致命,因为 OpenCV 的帧读取和 dlib 的底层检测都会释放 GIL。如果源码里没有多线程也能跑得流畅,那就不必引入额外复杂度,毕业设计稳定性优先。

5. 避坑指南:这套系统最容易翻车的五个位置及应对

5.1 现象:模型文件加载失败,程序启动即闪退

很多同学拿到源码第一件事是直接运行 main.py,结果报错说找不到 shape_predictor_68_face_landmarks.dat,或者文件打不开。原因通常有两种:一是模型文件路径写的是相对路径,但当前工作目录不在项目根目录下;二是文件本身下载不完整,只有几 KB,明显是残包。

解决方法是把模型路径改成基于项目根目录的绝对路径,用 os.path.join 拼接,不要依赖命令行启动时的目录。下载方面,dlib 官方渠道发布的 shape_predictor_68_face_landmarks.dat 体积在 90MB 以上,如果文件明显小于这个量级,重新下载一次。程序里加上启动检查,文件不存在时直接打印清晰错误再退出,方便定位问题。

5.2 现象:摄像头打不开或者画面只有十几帧

代码没有问题但画面一直黑屏或提示摄像头被占用,这在 Windows 上比较常见。原因是 OpenCV 默认使用 VFW 后端访问摄像头,兼容性不佳。解决方法是显式指定 DirectShow 后端,并设置画面分辨率,避免系统自动选择一个奇怪的分辨率导致解码变慢。

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) cap.set(cv2.CAP_PROP_FPS, 30)

如果换了后端还打不开,先排查摄像头是否被其他软件占用,再用第三方工具测一下摄像头本身工作状态。笔记本自带的摄像头有时候会被驱动管理软件禁用,需要到系统设置里手动启用。

5.3 现象:戴眼镜的测试者被反复误判成闭眼

深色镜框、镜片反光、眼角被镜框遮挡,都会让关键点定位出现漂移,EAR 计算值偏低,系统误以为人在闭眼。更麻烦的是两眼的 EAR 值会明显不对称:一只眼睛正常,另一只因为反光接近闭眼数值。

解决思路是对两只眼睛分别计算 EAR,然后做差值校验。如果一眼 EAR 远低于另一眼,说明是单侧遮挡或反光,这帧不应该进入疲劳计数。代码里加一个判断,只有当双眼 EAR 同时低于阈值时才累计闭眼帧数。这样戴眼镜者的误报会大幅下降,代价是真正的单眼疲劳信号被忽略,不过驾驶场景里闭眼通常都是双眼同时发生,这个取舍完全可以接受。

5.4 现象:夜间弱光下人脸检测直接失灵

dlib 的正面人脸检测器依赖灰度图像的梯度特征,光线不足时特征消失,检测框直接找不到。这个问题无解于纯软件层面,司机夜间开车是疲劳检测最重要的应用场景,放弃夜间就等于系统名存实亡。

常见的可靠方案是换用带红外补光的摄像头。红外光在可见光弱时依然可以清晰照亮人脸轮廓,dlib 检测器对红外图像依然有效。如果硬件不允许,也可以尝试对灰度图做直方图均衡化再送进检测器,能在弱光下挽回一部分检测率,但效果有限。毕业设计演示如果安排在室内,问题不大;如果要做夜间实验,提前准备红外摄像头。

5.5 现象:正常驾驶被频繁报警,系统像个重复告警的“狼来了”

过度报警的根因几乎都是阈值不合理和报警无抑制。阈值不合理在前面 4.2 节已经给过标定方案,这里重点说报警抑制。就算阈值正确,累积分触发报警后如果不清除状态,系统会在短时间内反复响,每次响完分数没降下来紧接着又触发第二次。

解决方法是给报警模块加一个冷却时间,比如触发报警后 60 秒内不再响应,同时把疲劳分数在报警后清零或衰减回安全区。状态机里加一条:报警事件触发后强制冷却 60 秒,期间只继续统计事件不触发新报警。实际跑车场景里,持续报警只会让驾驶员烦躁然后关掉系统,理性做法是报警后留出反应时间。

6. 验证与升级:用离线录像和公开数据集让毕业设计数据有据可依

6.1 离线回归测试:把真人录像变成可重复执行的用例

很多人在答辩前才慌慌张张开摄像头演示,结果现场光线不对或人脸距离变了,系统失灵。比较靠谱的做法是先录制几段短视频作为回归测试用例,离线跑代码统计报警次数。用录像测试的好处是可重复:每次改完参数,跑同一段视频,看报警结果有没有变差。

cap = cv2.VideoCapture("test_normal_driving.mp4") # 分别录制正常驾驶、模拟闭眼、模拟打哈欠三段视频 # 循环播放时记录每次报警时刻对应的时间戳

对照表是答辩时最直观的材料:每段视频里人工标出疲劳事件起始时间,运行系统后对比报警触发时刻,统计漏报次数和误报次数。至少准备三段素材:正常驾驶 5 分钟、模拟闭眼 10 次、打哈欠 8 次,这三组已经能覆盖核心功能验证,数据量也适合毕设篇幅。

6.2 公开数据集与论文对比:毕设数据表格怎么出

国内外的疲劳检测方向有一些公开数据集,常见的有 NTHU-DDD、YAWDD 等,里面包含不同光照、不同人种的睁眼闭眼视频序列。用数据集里的视频跑一遍你的系统,算准确率和召回率,再把结果整理成表格,比只拿自己拍的录像更有说服力。不过要注意,代码里的阈值可能需要针对数据集重新标定,直接用默认阈值跑出来的指标往往很难看。

整理数据时用三张表通常就够:第一张是自录视频的报警对照表,第二张是公开数据集上的检测准确率、召回率、F1 值,第三张是不同参数组合下的误报率对比。答辩老师最关心的不是绝对数字多高,而是你知不知道这些数字是怎么来的、影响因素是什么。

我自己的习惯是每次跑实验都把参数和结果记录成一个文本文件,日期、阈值、帧数、准确率都写清楚,省得回头调参调乱了不知道是哪版参数跑出的好结果。疲劳检测这种东西,模型结构大家都知道,最后拼的就是参数适不适合现场环境,整个项目做完你会意识到,最难的部分不是写代码,而是把阈值标定这个看似不起眼的环节做到不出岔子。希望这篇笔记能帮你少走一段弯路,也希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询