多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

基于Python+Django+OpenCV的疲劳检测系统开发实践

基于Python+Django+OpenCV的疲劳检测系统开发实践 简介面向毕业设计或课程设计场景这份资料提供基于PythonDjangoOpenCV的疲劳检测系统完整论文文档包含系统设计思路、OpenCV人脸与人眼识别实现、眨眼频次与眼睑闭合判断逻辑以及Python与MySQL数据库支撑的业务模块说明适合需要快速搭建疲劳检测方向毕设框架、撰写设计文档或复现图像识别流程的读者参考。资源为单个docx文件约1.01MB内容涵盖摘要、关键词、目录与正文结构可直接作为学位论文写作模板或功能设计对照材料。目前已有365人浏览学习能够帮助理解从图像采集、人脸检测到疲劳判定的完整链路并对Django系统平台及MySQL数据存储方案形成清晰认知是计算机视觉与Web开发结合类课题的实用参考资料。1. 疲劳检测系统的核心问题一段视频帧怎么变成一条可查的疲劳记录疲劳检测系统的目标很朴素用摄像头实时判断一个人是否处于疲劳状态。基于pythonDjangoopencv的这套组合是个人和中小团队落地时用得最多的方案。OpenCV负责图像处理dlib提取眼睛关键点计算EAR值Django把判定结果写入数据库并在网页端查询统计。整条链路要回答的问题是一段连续的视频帧怎么变成带时间戳、可统计、可回查的疲劳事件记录。这个方向适合三类人做毕业设计需要完整演示系统的学生想在企业值班室、在线监考场景做状态监测的工程师刚接触OpenCV和Django、想找经典项目练手的开发者。难点不在单个算法而在实时视频检测与Web后端之间的衔接。下文按选型、算法、后端、排错、验证五步走参数和坑都摊开讲。2. 技术选型与整体架构Python、Django、OpenCV各自在忙什么2.1 为什么是这套组合Django管业务OpenCV管视觉疲劳检测的完整链路包含六件事图像采集、人脸检测、特征提取、状态判定、业务存储、结果展示。没有哪个框架能一个人全包常见做法是分工OpenCV负责前四件里的图像相关部分Django负责后两件Python把中间逻辑串起来。需要先说明的是这里的OpenCV是广义的指OpenCV加dlib的组合——前者负责图像读写、预处理和绘制后者负责关键点回归。OpenCV在这套系统里的角色是眼睛。它读摄像头、转灰度图、缩放、画框、输出每一帧的检测结果本身不关心疲劳不疲劳只负责把图像变成可计算的数值。dlib是它的重要搭档提供预训练的68点人脸关键点模型眼睛轮廓的六个关键点坐标就是从模型输出里拿到的。为什么不直接用OpenCV自带的haar级联检测器定位眼睛因为haar给的是眼睛矩形框头稍微偏一点或者戴眼镜框就飘了dlib的68点回归模型输出的是坐标抗姿态变化能力强得多后续算EAR也更稳。Django在这套系统里管的是记忆。检测结果不能只停留在屏幕和内存里必须落库。每一次判定为疲劳的事件连同时间戳、EAR值、闭眼时长、用户编号写进数据表网页端要看的今日疲劳次数、连续工作时段曲线、某个用户的疲劳趋势都由Django的ORM查询聚合得出。这也是为什么很多同类项目用Flask而不是Django——Flask写demo更轻但一旦涉及用户管理、后台管理、分页查询、图表接口Django的admin和ORM能省掉大量重复代码。做论文或正式交付项目我一般建议直接用Django源码可读性也更高。Python在链路里是胶水。OpenCV和dlib都是C写的库Python有现成绑定Django本身也在Python生态里。选Python意味着从摄像头取帧到数据库写入全程用一门语言写完不用在C和Web框架之间来回切换。对于要交付源码和论文的项目这种一条语言链路走到底的可读性非常关键。有人会问能不能用OpenCV的C接口加Qt做界面再用数据库直连可以但维护成本完全不同。C方案在人脸检测性能上有优势适合嵌入式设备而Django方案的强项是业务扩展——你要增加用户角色、导出报表、对接企业微信告警Web框架的生态直接就能用。性能上CPU上dlib单帧检测大约15到25毫秒配合跳帧处理普通笔记本能跑到8到10帧每秒对疲劳判定这种低频事件完全够用。2.2 疲劳判定指标怎么定EAR、PERCLOS与闭眼时长先说结论疲劳判定不是检测到闭眼就报警这么简单。论文里用得最多的指标有三个——EAR、PERCLOS、连续闭眼时长三者解决的问题不同落地时通常组合使用。EAR即眼睛纵横比是两段垂直眼距的平均值除以水平眼距。正常睁眼在0.25到0.35之间完全闭眼会跌到0.1以下。它最大的好处是归一化人脸大小、摄像头距离变化之后比值基本稳定不需要对每个人单独标定。计算只需要眼睛的六个关键点左右眼各算一次再取平均。PERCLOS指单位时间内眼睛闭合程度超过某阈值的时间占比。疲劳驾驶研究里常用P80标准眼睛闭合超过80%的时间比例达到设定值就判疲劳。它和EAR的区别在于自带时间窗口能反映长时间眼皮耷拉这个状态而不是某几帧瞬间闭合。第三个指标是连续闭眼时长和眨眼频率。清醒的人每分钟眨眼15到20次单次闭眼很少超过0.2秒疲劳时会出现闭眼超过0.5秒甚至2秒、眨眼频率显著下降的现象。这个指标对打盹的识别最直接。实际落地我不会只用一个指标。我一般用双阈值EAR低于0.2且持续超过0.5秒记一次闭合事件60秒内闭合事件累计超过次数上限或单次闭合超过2秒直接判定疲劳。这样既能识别频繁打盹也能识别深度入睡。论文的实验部分也更有东西可写——你可以对比单指标和双指标在相同数据集上的准确率和误报率差异。2.3 整体数据流与目录规划从摄像头帧到数据库记录把上面串起来系统数据流是这样的摄像头或视频文件逐帧输出BGR图像 → OpenCV转灰度图并缩放 → dlib检测人脸、提取68个关键点 → 取左右眼各6点算EAR → 统计闭眼时长和眨眼频率套判定规则得到正常或疲劳状态 → Django视图或后台脚本把结果连同时间戳写入数据库 → 网页端通过ORM查询生成统计报表。这条链路有两个容易忽视的设计决策。第一检测逻辑放哪。常见做法是把OpenCV的检测封装成独立Python模块Django通过两种方式调用一是用后台线程跑实时检测二是封装成HTTP接口、浏览器通过摄像头权限把帧传给后端。第二种是很多论文系统的做法因为前端采集、后端判定在架构图上更清晰但要考虑帧传输延迟。第一版我建议直接用本地摄像头接OpenCV把检测跑顺再考虑Web化否则问题叠加在一起很难排查。第二数据库写什么、不写什么。不要每帧都写库30帧每秒一分钟就是1800条无意义的中间记录。合理粒度是写状态变化点和周期汇总每次从正常变为疲劳插入一条事件记录每分钟汇总一次平均EAR、闭眼次数写入统计表。一天检测下来也就几百条量级论文里的图表绘制和分页查询都轻松。fatigue_system/ ├── manage.py ├── detection/ # 检测核心独立于Django │ ├── detector.py # 人脸检测与EAR计算 │ ├── judge.py # 疲劳状态机 │ └── shape_predictor_68_face_landmarks.dat ├── web/ # Django项目 │ ├── settings.py │ ├── urls.py │ └── apps/ │ └── fatigue_monitor/ │ ├── models.py │ ├── views.py │ └── migrations/ └── requirements.txt目录这样拆的核心目的是让检测模块不依赖Django。你可以在命令行单独跑detection也可以把它import进Django的视图。requirements.txt里固定好依赖版本Django3.2.x、opencv-python、dlib、numpy、scipy。版本锁定是论文复现的前提不然评委换个环境跑不出来责任很难说清。3. 核心算法落地用OpenCV和dlib把眼睛状态算出来3.1 环境准备与模型文件python安装与opencv安装的前置条件Python版本我建议3.8到3.10Django用3.2 LTSOpenCV用opencv-pythondlib用pip安装。python官网下载对应版本后记得在虚拟环境里装依赖避免和系统Python冲突。Windows上dlib经常编译失败需要先装Visual Studio的C生成工具或者改用conda安装预编译的dlib包。Linux服务器上如果报libGL.so.1找不到说明缺OpenCV的图形依赖常见做法是apt安装libgl1或者直接用opencv-python-headless。关键点模型用dlib官方的shape_predictor_68_face_landmarks.dat约95MBOpenCV里不包含这个文件需要单独下载放到项目目录。注意路径要写稳定可靠的相对路径别在代码里硬编码临时下载目录否则换机器就翻车。# 建议在项目根目录建虚拟环境 python3 -m venv venv source venv/bin/activate # Windows下执行 venv\Scripts\activate # 安装核心依赖 python -m pip install --upgrade pip python -m pip install opencv-python dlib numpy scipy Django3.2 # 验证安装输出dlib和cv2版本 python -c import dlib, cv2; print(dlib.__version__, cv2.__version__)在Ubuntu上安装opencv有两种路径apt装系统库或者pip装Python绑定。做这个项目用pip就够apt的版本往往偏旧opencv 3.4.1那类老版本和dlib新版配合容易出现接口不兼容。验证安装这步不能省import失败越早暴露越好不要等到代码写了一半才发现环境不对。3.2 人脸关键点检测与EAR计算最小可运行代码import cv2 import dlib import numpy as np from scipy.spatial import distance as dist # 初始化检测器与关键点模型 detector dlib.get_frontal_face_detector() predictor dlib.shape_predictor(detection/shape_predictor_68_face_landmarks.dat) # 68点模型中左右眼各取6个关键点索引 LEFT_EYE list(range(42, 48)) RIGHT_EYE list(range(36, 42)) def eye_aspect_ratio(eye_points): # 垂直距离上下眼睑两对点 A dist.euclidean(eye_points[1], eye_points[5]) B dist.euclidean(eye_points[2], eye_points[4]) # 水平距离左右眼角 C dist.euclidean(eye_points[0], eye_points[3]) return (A B) / (2.0 * C) def compute_ear(frame): gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces detector(gray, 0) if len(faces) 0: return None, None face faces[0] shape predictor(gray, face) coords np.zeros((68, 2), dtypeint) for i in range(68): coords[i] (shape.part(i).x, shape.part(i).y) left_ear eye_aspect_ratio(coords[LEFT_EYE]) right_ear eye_aspect_ratio(coords[RIGHT_EYE]) return (left_ear right_ear) / 2.0, coords cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break ear, coords compute_ear(frame) if ear is not None: # 画眼睛轮廓调试时确认关键点没偏 cv2.polylines(frame, [coords[LEFT_EYE]], True, (0, 255, 0), 1) cv2.polylines(frame, [coords[RIGHT_EYE]], True, (0, 255, 0), 1) cv2.putText(frame, fEAR: {ear:.2f}, (30, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) cv2.imshow(Fatigue Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码是最小可运行版本。detector的输入是灰度图第二个参数0表示不做图像上采样速度优先predictor返回68个关键点shape.part(i).x和.y拿到坐标。EAR计算用scipy的euclidean函数其实自己用np.linalg.norm也能算但scipy写法更清晰。左右眼EAR取平均可以抵消侧脸角度造成的单侧偏差。polylines画轮廓只是调试辅助正式批量处理时应该去掉。参数说明detector的采样参数0是原图检测1会对图像做一次上采样能提高小脸检测率但速度下降约四倍。我的经验是摄像头画面里人脸宽度大于150像素时用0就够了如果检测不到人脸优先调这个参数而不是盲目换模型。waitKey(1)的1毫秒也是可调参数值越大画面刷新越慢CPU占用下降但实时性变差。这里只做了灰度化和缩放两种图像处理够用就好不要一上来就上高斯模糊、边缘检测那会拖慢帧率对关键点定位帮助有限。3.3 从EAR到疲劳判定时间阈值与状态机光有EAR还不够需要一个状态机记录当前是否闭眼以及闭了多久。故障点是如果只按单帧EAR低于0.2就报警人正常眨眼也会触发误报所以必须引入时间维度。class FatigueJudge: def __init__(self, ear_thresh0.2, close_time0.5, fatigue_time2.0): self.ear_thresh ear_thresh # EAR低于该值视为闭眼 self.close_time close_time # 小于该时长的闭合忽略容忍眨眼 self.fatigue_time fatigue_time # 单次闭合超过该时长判疲劳 self.eye_closed False self.closed_start 0.0 self.is_fatigue False self.frame_time 0.0 def update(self, ear, fps): self.frame_time 1.0 / fps if ear self.ear_thresh: if not self.eye_closed: self.eye_closed True self.closed_start self.frame_time elif self.frame_time - self.closed_start self.fatigue_time: self.is_fatigue True else: self.eye_closed False if self.is_fatigue: # 一次疲劳事件结束这里可以回调保存到数据库 self.is_fatigue False return self.is_fatigue这段状态机解决两个问题短于close_time的闭合不算疲劳只有连续闭合超过fatigue_time才置位。fps参数理论上由VideoCapture的CAP_PROP_FPS获得但实际摄像头返回的fps经常不准更稳的做法是自己统计帧间隔时间用实际帧率喂给状态机。三个阈值是论文里必须交代的参数。ear_thresh的0.2是经验值多数论文用0.2到0.25close_time设0.5秒是为了容忍正常眨眼fatigue_time设2秒参考了驾驶疲劳研究里闭眼超过2秒视为微睡眠的标准。这些值不是死的第六章会讲怎么用视频回放标定自己的阈值。4. Django后端搭建把检测结果变成可查可统计的记录4.1 创建项目与Appdjango创建app的命令与目录结构检测算法跑通后就到了Django侧。业务后端要干的事很清楚接收检测结果、写入数据库、提供查询接口、在admin后台里能看能筛。# 进入项目根目录创建Django工程 django-admin startproject web cd web # 创建存放检测业务逻辑的app python manage.py startapp fatigue_monitor # 把fatigue_monitor注册进settings.py的INSTALLED_APPS后执行迁移 python manage.py makemigrations fatigue_monitor python manage.py migrate # 创建后台管理员账号admin里查看记录用 python manage.py createsuperuser这里的一个常见误区是很多人把整个检测逻辑也写进app里。我建议保持第二章的目录规划检测模块在Django项目外app里只做接收结果和展示。这样检测模块可以单独测试不依赖Django的启动上下文。数据库方面开发阶段用默认的SQLite够用提交论文或部署到服务器时再切MySQL——settings.py里配置DATABASES用pymysql做驱动注意在__init__.py里执行pymysql.install_as_MySQLdb()不然会报找不到MySQLdb模块。4.2 数据模型设计疲劳事件表与按分钟汇总表# fatigue_monitor/models.py from django.db import models from django.contrib.auth.models import User class FatigueEvent(models.Model): 单次疲劳事件只在状态从正常变为疲劳时插入 user models.ForeignKey(User, on_deletemodels.CASCADE, verbose_name用户) ear_value models.FloatField(平均EAR, nullTrue, blankTrue) closed_duration models.FloatField(闭眼时长(秒)) fatigue_level models.IntegerField(疲劳等级, default1) # 0正常 1轻度 2重度 created_at models.DateTimeField(auto_now_addTrue) class Meta: ordering [-created_at] def __str__(self): return f{self.user_id} {self.created_at} {self.fatigue_level} class FatigueMinuteStats(models.Model): 按分钟汇总供论文图表和网页统计使用 user models.ForeignKey(User, on_deletemodels.CASCADE) minute_start models.DateTimeField() avg_ear models.FloatField(default0) blink_count models.IntegerField(default0) fatigue_count models.IntegerField(default0) class Meta: unique_together (user, minute_start)设计要点有三条。第一FatigueEvent只记录状态跳变不记录逐帧数据这和2.3节说的写入策略对应一张表存一天的疲劳事件不过几百条。第二FatigueMinuteStats做按分钟聚合论文里的疲劳趋势图、平均值曲线都从这张表取数不要现场去扫事件表聚合查询会慢一个数量级。第三外键用Django内置的User论文的ER图可以直接引用这张表画关联关系省得自己再造一套用户表。closed_duration存的是闭眼持续时长不是疲劳状态持续时长。早期版本我犯过混用的错误导致论文里的阈值设置和实验数据对不上。一个事件只关心这次闭了多久疲劳等级由上层综合判断别把所有逻辑压在一张表里。4.3 视图、路由与写入接口检测结果怎么进数据库# fatigue_monitor/views.py import json from django.http import JsonResponse from django.views.decorators.csrf import csrf_exempt from django.core.paginator import Paginator from .models import FatigueEvent, FatigueMinuteStats # 内部服务调用用csrf_exempt避免跨域麻烦 csrf_exempt def report_event(request): if request.method POST: data json.loads(request.body) FatigueEvent.objects.create( user_iddata.get(user_id, 1), ear_valuedata.get(ear), closed_durationdata.get(duration, 0), fatigue_leveldata.get(level, 1), ) return JsonResponse({code: 0, msg: ok}) return JsonResponse({code: 1, msg: method not allowed}) def list_events(request): 查询最近100条事件带用户信息要用select_related避免N1查询 events FatigueEvent.objects.select_related(user).all()[:100] rows [{ user: e.user.username, time: e.created_at.strftime(%Y-%m-%d %H:%M:%S), duration: e.closed_duration, level: e.fatigue_level, } for e in events] return JsonResponse({code: 0, data: rows})# fatigue_monitor/urls.py from django.urls import path from . import views urlpatterns [ path(api/report, views.report_event, namereport_event), path(api/events, views.list_events, namelist_events), ]写入接口是检测进程调用Django的唯一入口。检测脚本里在状态机的is_fatigue刚置位或刚复位时拿本地缓存的user_id、EAR、闭眼时长拼一个JSON用requests.post发给这个接口。注意三点第一csrf_exempt只对内部接口开放不要套用到面向普通用户的表单接口上第二请求体用JSON而不是form表单Python两端都好解析第三接口要幂等——同一个事件如果因为网络超时重发要么先查重要么接受重复记录否则后台数据会越看越乱。4.4 查询优化与论文章节对应select_related怎么用、论文怎么写Django的ORM过滤和查询是常规操作真正值得注意的是select_related。list_events视图里如果直接FatigueEvent.objects.all()Django在循环里每访问一次e.user就发一条SQL100条事件就是101条查询页面会明显卡顿。加了select_related(user)之后一条JOIN搞定这是Django性能优化里最常用的手段也是论文里的系统设计章节可以写的一页内容。论文章节和系统实现是对应关系不是写完代码再硬凑。拿到这种源码数据库论文的打包项目我的建议是先核对四样东西算法章节的阈值是否和代码里的默认参数一致、实验章节的数据集标签有没有附在代码仓库里、数据库表结构是否和论文的ER图一致、运行环境版本是否和README对得上。四样里最容易出问题的是阈值论文写0.2代码里写0.25答辩演示一跑就露馅。调试期清数据也是常见场景。Django的批量删除FatigueEvent.objects.all().delete()是级联的会连带删除关联对象如果FatigueMinuteStats的外键指向事件表或者反过来先用shell看清楚on_delete参数再动手。按分钟统计表是论文图表的直接数据源清空事件表后一定要同步重建统计表否则图表上出现空洞没法解释。5. 疲劳检测系统避坑指南环境、实时性与数据对齐的五个翻车现场这一章是血泪经验集中区。以下五个坑按出现频率排基本覆盖从环境搭建到论文交付的全过程。5.1 Windows下dlib安装失败编译报错还是换conda现象pip install dlib在Windows上编译几分钟后报ERROR: Failed building wheel for dlib提示缺少CMake或C编译器在Ubuntu上装到一半提示找不到boost/python3-dev。原因dlib没有官方Windows预编译wheelpip会尝试源码编译依赖完整的Visual Studio C工具链和CMakeLinux缺系统编译依赖。解决Windows上最省事的路径是conda install -c conda-forge dlib直接拿预编译包坚持用pip就先装Visual Studio Build Tools勾选使用C的桌面开发再装CMake。Linux先执行sudo apt install build-essential cmake libboost-all-dev再python -m pip install dlib。装完务必执行python -c import dlib; print(dlib.version)验证别等到import报错才回头查环境。5.2 报错ModulenotFoundError: no module named cv2现象代码开头import cv2直接报ModulenotFoundError或者no module named opencv更隐蔽的是终端里能import但Django runserver启动后报错。原因装到了另一个Python环境。终端默认解释器和Django项目虚拟环境不是同一个pip install opencv-python装进了系统Python而Django跑在venv里。解决先做两个确认。终端执行which python和python -m pip list看当前解释器路径再确认Django启动时用的是同一个解释器manage.py头部有#!/usr/bin/env python虚拟环境激活状态下启动就能对上。装包时显式写python -m pip install opencv-python不要只写pip install避免pip和python指向不同版本。服务器无显示环境用opencv-python-headless功能和cv2一致省掉libGL依赖。5.3 摄像头越跑越卡检测帧率和Django请求互相拖累现象系统运行几分钟后画面掉帧严重内存持续上涨打开Django后台页面也变慢重启后又恢复正常。原因主线程里dlib检测本身耗时加上每帧写数据库再加上Django开发服务器的同步请求处理三者互相拖累。dlib在CPU上单帧15到25毫秒单看不吓人但叠加画框、ORM写入和HTTP解析之后30帧每秒的输入根本处理不完积压的帧在内存里排队。解决做三项改造。第一检测只处理每三帧中的一帧视觉上几乎无感CPU占用直接降三分之一第二数据库只写状态跳变不写逐帧数据配合第三章的状态机第三检测进程和Django进程分离检测脚本独立运行通过HTTP接口交数据Django只负责读。实测把每帧全量处理改成跳帧事件写入后CPU占用能降一半以上内存不再增长。5.4 白天正常晚上全报警光照变化与EAR阈值漂移现象白天阈值0.2工作正常晚上开灯或侧光照时人明明睁着眼EAR频繁跌破阈值误报刷屏。原因暗光下灰度图噪声大dlib关键点定位偏移上下眼睑点被拉近EAR整体被压低侧光在眼窝形成阴影也会有同样效果。关键点定位对光照敏感这是dlib的先天弱点不是代码bug。解决在灰度化之后加CLAHE自适应直方图均衡化增强局部对比度能明显改善暗光下的关键点稳定性。阈值不要拍脑袋定用第六章的离线视频回放分别采集白天和晚上的样本各自跑一遍EAR分布再定阈值。条件允许时固定摄像头位置和补光方向让检测环境可控——别指望一个阈值通吃所有光照论文里也要如实写光照条件。5.5 论文数据对不上时间戳、标签聚合与批量删除的连锁问题现象论文实验表里的准确率和答辩演示结果对不上或者调试期清空数据库后分钟统计表出现空档图表上有一段断层。原因数据集标签是人眼标注的判定阈值和系统里的EAR阈值不一致两边对同一段视频的判定自然不同数据库只存状态跳变但论文实验需要按分钟统计两套聚合逻辑不统一数字对不上很正常。批量删除事件后分钟统计表没有同步重建出现空窗。解决用统一的离线回放脚本对同一批视频重新跑一遍输出带帧号的判定序列再与人工标签逐帧比对这是消除数据分歧的唯一可靠办法。清数据前先停掉检测进程再执行FatigueEvent.objects.all().delete()同时确认分钟表要不要一并清空重建。论文的实验设置一节必须写清三个参数EAR阈值、处理帧率、标签标注标准三者缺一复现就是空话。6. 验证与进阶用一段离线视频把整个系统变成可信结果6.1 离线回放怎么算准确率、召回率与F1论文和交付最需要的其实是一句系统准确率是多少。口说无凭得用离线视频回放验证。思路是把摄像头源换成视频文件同一套检测代码逐帧跑输出判定序列再和人工标注的标签比对。import cv2 import json from detection.judge import FatigueJudge from detection.detector import compute_ear cap cv2.VideoCapture(test_video.mp4) judge FatigueJudge() frame_idx 0 results [] while cap.isOpened(): ret, frame cap.read() if not ret: break if frame_idx % 3 0: # 每3帧检测一次和线上策略一致 ear, _ compute_ear(frame) if ear is not None: results.append({frame: frame_idx, ear: ear, fatigue: judge.update(ear, 25)}) frame_idx 1 cap.release() with open(result.json, w) as f: json.dump(results, f)跑完把result.json和人工标注逐帧对齐统计真正例、假正例、假负例。准确率看整体召回率更重要——疲劳漏报比误报危险得多所以论文里最好同时给准确率、召回率、F1三个数。6.2 进阶把检测服务独立成进程再进一步是把检测从Django里彻底拆出去。检测进程只负责读摄像头、判疲劳、写数据库Django只做读取和展示。常见做法是检测脚本里用while循环加sleep数据库连不上时先落本地JSON做补偿等数据库恢复后再回放补写避免检测进程被数据库故障拖死。到这一步整个系统的架构就从能跑变成了可信。这套系统我自己从零搭过不止一次最大的教训是别急着写论文先把离线视频回放这条验证通道做出来。没有它你调阈值全是玄学答辩前才发现数据和系统对不上。先跑通回放把指标算出来再回头调阈值和数据库逻辑顺序对了能省一半时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表