YOLOv11+Django+DeepSeek:课堂行为检测系统完整实现

发布时间:2026/10/19 3:10:06

YOLOv11+Django+DeepSeek:课堂行为检测系统完整实现 我最早是在给某课程试点项目搭课堂行为监测功能时接触到这个组合的。课堂场景里老师真正想知道的不是“模型输出了多少种框”而是“这节课哪些学生在低头、哪些在趴桌、哪些在频繁玩手机”。标题里的 YOLOv11 Django DeepSeek 这套搭配恰好把“看到行为”“管理数据”“组织语言”三件事各管一摊还带登录界面的精美 Web 前端。这篇文章我按实际开发顺序把整套系统拆开讲清楚——从模型推理、后端接口、前端展示到报告生成每一步为什么这么做、卡住了怎么办尽量一次性讲到位适合想拿这套技术栈快速落地课堂行为检测系统的开发者做参考。1. 行为检测系统最容易被低估的需求不是模型而是“从模型到老师看到报告”的链路很多人听到“学生课堂行为检测系统”第一反应就是“训练一个 YOLOv11 模型检测睡觉、玩手机、举手”。实际上模型能顺利跑出框只是这个项目里最简单的一层。真正让系统可用要解决的是行为数据从哪来、往哪去、老师怎么看、异常怎么提醒这一整套链路问题。1.1 课堂场景里逐帧全量推理并不划算课堂监控和普通的安防识别不太一样。学生在座位上长时间保持相似姿态教室摄像头一节课动辄上万帧如果每帧都送进模型推理GPU 确实费、卡顿也明显但老师要看的只是几个关键指标这节课有多少次低头、总共睡了多久、举手几次、答题互动是否频繁。我在实践里的做法是降低采样频率摄像头画面按每秒 1~2 帧抽帧推理其余时间用来做跟踪和状态累积。课堂行为本身是慢变化过程1 秒抽 1 帧已经能捕捉到够用的行为变化。对应的行为类别我选的是这几种常用组合类别标签检测难点抬头听讲focusing摄像头俯拍时和低头难区分低头looking_down遮挡多角度敏感书写writing手部动作快举手hand_raising遮挡严重玩手机phone手机目标小趴桌sleeping头肩特征变化大这套类别列表不用贪多类别越多单个类别的精度和稳定性越难兼顾和课堂老师真正关心的指标直接相关就够用了。1.2 定位练习 DeepSeek 和 Django 的分工在这个系统里YOLOv11 负责“看”从一帧画面中框出学生个体给出行为类别和置信度。Django 负责“管”接收推理结果、存储行为数据、管理登录用户、向浏览器推送实时告警。DeepSeek 负责“说”检测数据是零散的老师不可能一节课盯着一堆数字看于是把聚合后的行为统计抛给大模型让它生成像“这节课整体专注度偏低后排第三列玩手机次数较多建议增加提问互动”这样的报告。三者的边界划分很重要。不要让 Django 去做模型推理也不要让前端直接请求大模型接口。检测、后端、生成报告各司其职整个系统在出现问题的时候单点排查会容易很多。2. 项目整体架构与数据流设计下面这张是我最终采用的模块布局不画复杂架构图直接文字说明每个模块之间怎么流转这样更容易对应到代码结构。2.1 Django 工程的分层结构我建议把工程分成 apps 分层的模式便于扩展。model 推理部分单独抽成一个 service不塞在 views.py 里行为聚合逻辑独立成 serviceWeb 前端使用静态页面加一套轻量后台模板DeepSeek API 调用封装成独立 client。Django 工程的核心目录大致如下project_root/ ├── manage.py ├── requirements.txt ├── config/ │ ├── settings.py │ └── urls.py ├── behavior/ │ ├── camera.py # 视频源采集与抽帧 │ ├── detector.py # ONNX 模型推理 │ ├── tracker.py # 目标跟踪与ID维护 │ ├── aggregation.py # 行为统计聚合 │ └── report_client.py # DeepSeek 接口封装 └── web/ ├── views.py # 登录、页面、状态接口 ├── urls.py └── templates/behavior 是纯算法侧不依赖 Django 的 ORMweb 是展示和对外接口层。这样做的好处是将来如果要把同样的推理能力换成一个独立的服务进程behavior 目录可以直接搬走不用改业务代码。2.2 数据流从视频帧到行为报告摄像头连续采集画面在抽帧后交给 detector 推理YOLOv11 输出检测框、类别和置信度。检测框接着进入跟踪模块给每个框分配稳定的学生 ID——这一步很关键如果不做跟踪前一秒检测到的“张三”和后一秒的“张三”模型无法确定是不是同一个人也就没法累计“某位学生低头了多久”。因此我用了一种轻量跟踪策略给每个学生分配一个持续存在的 ID按帧更新其位置和行为状态。行为统计会每隔 N 帧聚合一次写入数据库同时通过 Django 接口把实时状态推给 Web 页面。整节课结束后聚合器把班级级别的行为分布整理成结构化的 JSON 数据。report_client 读取这份 JSON组装成 prompt 后请求 DeepSeek把返回的课堂总结文本存入库中老师登录系统后在报告页看到。整个链路最核心的原则是模型推理的输出要尽量结构化避免直接把原始检测结果丢给 LLM。原始检测里一帧可能产生 20 条框输出老师要的却是“这 20 个框对应 6 个学生其中 3 个总低头”。结构化要付出额外的聚合代码但从使用体验来看值。3. YOLOv11 模型导出与 ONNX 推理实操细节YOLOv11 训练时的产物通常是 .pt 权重文件但在这个项目里我实际部署用的是 ONNX 版本。Django 侧不依赖 PyTorch 的完整训练环境推理速度快也更容易做 CPU 部署在没 GPU 的教室环境里CPU也能艰难跑起来。3.1 从训练权重到 ONNX 的导出命令导出命令本身不复杂关键是参数别选错。使用 ultralytics 框架导出 ONNX 时以下几处参数需要注意。yolo export modelyolov11n-behavior.pt formatonnx opset12 imgsz640 simplifyTrue dynamicFalse我解释下这几个参数的用意。imgsz 设为 640是因为训练时的输入尺寸就是 640导出推理尺寸和训练尺寸保持一致能避免尺寸变化导致的精度下降。dynamicFalse 意味输入形状固定为 [1, 3, 640, 640]固定形状在 ONNX Runtime 下的优化更充分速度更稳定。opset 使用 12兼容性比较好新老环境都能跑。simplify 使用 onnxsim 做简化可以把一些冗余算子合并减少推理时的计算开销。建议导出后顺手验证一次模型精度python -c import onnx m onnx.load(yolov11n-behavior.onnx) onnx.checker.check_model(m) print(ONNX model OK) 这一步很多人忽略但 ONNX 模型有时会包含训练阶段才用到的算子部署时直接报错提前 check model 可以省掉大量排查时间。3.2 ONNX Runtime 推理代码的标准化写法写推理代码时最需要注意的是预处理和后处理和 PyTorch 推理不太一样。ONNX Runtime 读进来的图像要完成 BGR 转 RGB、归一化到 0~1、resize 到 640、以及 HWC 到 CHW 的维度变换否则模型输出结果会明显异常。import cv2 import numpy as np import onnxruntime as ort class YOLOv11ONNX: def __init__(self, model_path, conf_thres0.35, iou_thres0.45): self.session ort.InferenceSession( model_path, providers[CUDAExecutionProvider, CPUExecutionProvider] ) self.conf_thres conf_thres self.iou_thres iou_thres self.input_name self.session.get_inputs()[0].name self.output_names [o.name for o in self.session.get_outputs()] self.class_names [focusing, looking_down, writing, hand_raising, phone, sleeping] def preprocess(self, image): img cv2.cvtColor(image, cv2.COLOR_BGR2RGB) img img.astype(np.float32) / 255.0 img cv2.resize(img, (640, 640)) img img.transpose(2, 0, 1) return np.expand_dims(img, axis0).astype(np.float32) def infer(self, image): input_tensor self.preprocess(image) outputs self.session.run(self.output_names, { self.input_name: input_tensor }) return self.postprocess(outputs[0])后处理时要把模型的输出从中心点坐标格式转换成 xyxy再做置信度过滤和 NMS。这部分代码每个版本输出格式略有差异我这里的经验是YOLOv11 导出的 ONNX 输出为 [1, 84, 8400]84 是 4 个坐标 80 个 COCO 类别对应的置信度如果是自定义类别要把对应的维度改成 4 类别数。3.3 推理性能实测与稳定性的平衡我分别跑过 CPU 和 GPU 环境。i5 级别 CPU 单帧 640 推理约为 150ms~200msRTX 3060 上能做到 15ms~25ms。要是按每秒 1 帧抽帧CPU 也能支撑起一个教室的单路摄像头如果需要多路摄像头建议上 GPU 或者把推理放到独立进程里避免阻塞 Django 请求线程。最影响体验的地方其实是 NMS 参数。conf_thres 不建议设太低课堂场景下 0.35 左右比较合适。设成 0.1会出现大量低质量重复框跟踪 ID 频繁切换行为统计反而乱设太高虽然框少但漏检多像玩手机这类小目标更容易漏。4. Django 后端与精美 Web 界面的集成思路后端部分我重点讲两件事直播监视页面怎么做、行为数据怎么实时刷新到前端。登录界面和权限体系相对常规只简单轻点一下。4.1 摄像头画面和检测结果如何推送到浏览器常见的方案有两种MJPEG 流或多线程帧缓存轮询。课堂行为检测系统对实时性要求没那么极端我用的是多线程帧缓存方案一个后台线程持续抓帧并推理把最新的带框画面保存成 JPEG 编码的内存帧前端通过一个定时刷新的接口拿到静止图片实现类似“准直播”的效果。import threading import cv2 _camera_lock threading.Lock() _global_frames {} def capture_worker(camera_id, camera_url): cap cv2.VideoCapture(camera_url) while True: ret, frame cap.read() if not ret: continue frame detector.infer_and_draw(frame) _, jpeg cv2.imencode(.jpg, frame, [int(cv2.IMWRITE_JPEG_QUALITY), 80]) with _camera_lock: _global_frames[camera_id] jpeg.tobytes()前端如果直接拿这个接口返回的图片刷新能简化很多 WebSocket 的配置。每一帧大约几十 KB一秒刷 1~2 次带宽完全够用。唯一要提醒的是Django 的 runserver 自带开发服务器不适合长时间跑视频流线程部署时得用 gunicorn 或者 uWSGI并且要把抓帧任务独立到后台进程管理工具里避免工作进程重启时重复启动线程。4.2 实时行为统计图表的实现实时统计部分我采用一个 JSON 接口定期拉取最近 5 分钟的班级行为分布每名学生的当前状态、最近一段时间内各类行为的次数以及趴桌、玩手机的告警提示。前端基于这些数据绘制行为趋势折线图和状态分布饼图。接口返回结构可以设计成下面这种{ timestamp: 2025-04-01 10:23:00, students: 42, class_aggregate: { focusing: 28, looking_down: 7, writing: 5, sleeping: 1, phone: 1 }, alerts: [ {student_id: 17, behavior: phone, duration_seconds: 180} ] }前端拿到这份数据后不需要理解模型输出只需要渲染键值。给老师看的页面重点突出“异常”和“整体趋势”而不是一屏幕的检测框。这也是 Web 界面好不好用的分水岭——框花花绿绿可不代表老师觉得好用一眼能看出“谁在睡觉谁在玩手机全班整体状态如何”才叫好用。4.3 登录界面与权限控制的实现策略登录界面用 Django 自带的认证模块就够但有两个细节值得处理第一登录成功后系统会创建与用户绑定的会话教师的会话里可以配置所管理的班级管理员可以查看所有班级的数据。第二课堂画面属于敏感信息任何页面在展示摄像头内容之前都要做登录校验。我用了一个简单的 LoginRequiredMiddleware在请求入口统一拦截而不是在每个视图函数里重复写装饰器。课堂行为系统的权限不太复杂做成“教师可看自己负责的教室管理员可看全局”就能覆盖绝大多数需求。真正要留神的是登录失败尝试次数限制防止课堂上被外界暴力尝试密码简单加个 IP 维度限流就够了。5. DeepSeek 接入与课堂报告生成的工程化做法这是这套系统相对有亮点的部分。检测数据本身只是一种客观行为统计但老师需要的可能是“为什么这节课堂氛围偏低”“应该怎么调整教学节奏”这些判断交给 DeepSeek 去做性价比很高。5.1 为什么把结构化统计而不是原始检测交给大模型原始检测输出是密集的框和置信度直接发给大模型既浪费 token又很容易让大模型淹没在无用细节里。我实际做法是先聚合再传入。聚合后的数据形如“总人数 42俯视低头累计 12 人次平均单次低头时长 65 秒后排靠窗位置出现连续趴桌”。这种数据量小、语义清晰大模型能准确抓住重点生成的报告也更贴近教学语言。5.2 Prompt 模板设计DeepSeek 入口调用时我设计了一个固定格式的 prompt把班级行为统计、检测时间、学科类型作为变量传入并要求输出定向结构。一个大约可用的 prompt 如下你是一名教学观察助手。以下是某课堂内摄像头行为识别系统统计到的班级行为数据 - 上课时长45分钟 - 学生人数42 - 各行为累计时长书写210分钟抬头听讲850分钟低头360分钟玩手机45分钟趴桌18分钟 - 偶发事件后排3名学生频繁玩手机 请根据以上数据生成一份300字以内的课堂行为反馈包含 1. 班级整体专注度评价 2. 需要关注的异常行为 3. 可操作的教学建议 要求语言客观不做人身评价输出为markdown格式。注意 prompt 里的一个重要边界要求大模型“不做人身评价”这样既能克制输出风险也符合教师端工具的产品伦理。检测系统只是辅助工具最终判断权一定留在老师手里。5.3 DeepSeek 调用的超时、重试与降级任何大模型接口都可能超时或返回异常工程上要设计三件事超时控制requests 库设置 timeout我这里设置为 10 秒避免阻塞报告页长时间白屏重试策略对 5xx 和超时做最多 2 次重试每次间隔递增降级策略调用失败时不弹错误页而是展示本地预先写好的模板报告并在页面上提示“AI 分析暂不可用已展示基础统计”。import json import requests API_KEY your_deepseek_api_key API_URL https://your_deepseek_endpoint def generate_report(structured_data: dict) - str: prompt build_prompt(structured_data) headers {Authorization: fBearer {API_KEY}, Content-Type: application/json} payload { model: your_model_name, messages: [ {role: user, content: prompt} ], temperature: 0.4, max_tokens: 600 } for attempt in range(3): try: resp requests.post(API_URL, jsonpayload, headersheaders, timeout10) if resp.status_code 200: content resp.json()[choices][0][message][content] return content except Exception: if attempt 2: break time.sleep(2 * (attempt 1)) return load_fallback_report()温度参数我一般设到 0.3~0.5 之间。设太高生成报告会充满推测性描述课堂行为分析要的是客观、稳定、可复现的输出不是天马行空的评语。6. 部署上线过程中容易踩的坑与应对方案这部分全是实际操作里趟出来的经验。项目看起来每个模块单独跑都没问题一组合起来问题就浮出来了。6.1 多线程抓帧与 Django 请求的冲突最开始抓帧逻辑写在视图函数内部导致每打开一个页面就多启动一个抓帧线程时间一长整个机器卡死。后来换成独立的后台进程由进程管理器拉起摄像头抓帧任务Django 只负责读取内存中最新帧问题才彻底解决。线程安全也要注意。多个线程同时读写一个 JPEG 帧不加锁会在极少数情况下读到半张图。写入和读取都加锁代价很小却能让系统稳定很多。6.2 ONNX Runtime 的 GPU 版本安装陷阱onnxruntime-gpu 版本和 CUDA 版本不对应是最常见的问题。你很可能安装一个新版 onnxruntime-gpu但机器上 CUDA 版本较老推理时直接找不到 CUDA 环境自动退化到 CPU性能自然掉下来。部署前用一条命令确认是否真正调用 GPUimport onnxruntime as ort print(ort.get_available_providers())只有输出了 CUDAExecutionProvider 才说明 GPU 可用。如果没出现要么换对应版本的 onnxruntime-gpu要么升级 CUDA 工具链。考虑到教室边缘环境复杂我的建议是优先做好 CPU 推理的性能优化GPU 预留为可选增强。6.3 行为统计的累积误差比单帧误差更难排查单帧漏检一眼就能看到不容易察觉的是统计链条里的误差累积。比如某学生被跟踪 ID 频繁切换就会把同一段低头时长计成两个学生。我加了一个跟踪阈值同一检测框与已有轨迹 IoU 超过 0.5 才更新 ID小于阈值的暂时保留 3 帧待匹配超过 3 帧没有匹配才判定为新 ID。这样能显著降低 ID 抖动。另一个坑是视频流断流后行为时长还在继续累计。抓帧线程要维护一个“最后更新时间”超过设定阈值就自动终止该摄像头会话直到视频流重新恢复。6.4 前端显示时间戳与检测帧不同步摄像头的视频流可能持续掉线前端的“实时状态”如果直接取接口返回时刻作为时间戳会掩盖掉视频流断流的真实现象。我在帧数据里额外写入帧原始采集时间前端展示时以这个字段为准一旦发现采集时间与当前系统时间差距超过 10 秒就明确提示“画面延迟过高”避免老师误判课堂实时状态。7. 这套系统后续还可以扩展的三个方向项目跑通后我积累了三条很明确的扩展思路这里一并分享。一是多摄像头教室聚合。一个教室装多路摄像头通过跟踪关联同一学生在不同机位下的检测结果行为统计会更完整。实现时可以把 camera_id 加进统计数据表前端按教室分组汇总。二是把行为检测和课堂互动工具对接。检测到举手行为后自动标记对应学生检测到低头频繁的时段自动记录教学节点老师课后复盘时直接定位时间轴。三是引入边缘盒子部署。现在整套系统跑在一台带 GPU 的服务器上但很多学校希望摄像头本地完成推理再把结构化结果传到中心服务器。ONNX 模型已经具备部署到边缘的条件只要把 detector 独立成子进程上传过程中合并班级维度的聚合数据带宽压力也不大。做一个课堂行为检测系统模型选型和训练只是开始难度其实在后端的稳定性、前端的信息组织、大模型的语义概括。把这三样整合到一条顺畅的链路上会比单纯追求几个点的 mAP 更有实际意义。只要链路完整、数据可靠老师不用理解技术细节就能轻松拿到“这节课谁在认真听、哪个环节需要调整”的可读结论。
延伸阅读

更多相关文章

2026/10/19 3:10:06

TensorFlow 2 单卡多模型训练:显存分配与训练循环实践

在训练资源比较紧张的环境里,单张 GPU 往往要同时扛好几个实验。我常遇到的情况是:白天要跑一个基线模型,晚上想再插一个对比实验;或者某个大模型把显存占得七七八八,剩下的一小块显存既放不下完整 batch,又…

2026/10/19 3:10:06

抵御压缩与对抗扰动:深度伪造检测的鲁棒性设计

先说一个我印象很深的实验。某次我把训练好的深度伪造检测器从实验室测试集切换到真实社交网络链路采集的数据上,AUROC直接从0.98掉到0.84。这还没完,一旦有人对伪造视频做了针对性的对抗扰动,再丢给模型,模型几乎变成瞎猜。这个方…

2026/10/19 3:10:06

YOLOv11工业表面缺陷检测实战:从数据准备到部署全流程

这两年我一直在做工业质检方向的视觉项目,从传统图像处理转到深度学习方法,说实话踩过的坑比走过的路还多。最近把一套表面缺陷检测流程整体升级到YOLOv11,从数据准备到模型训练再到部署推理,整套链路跑通之后,回过头来…

2026/10/19 4:20:10

Pulsar与Presto集成实战:构建实时可查的流式虚拟表

1. 项目概述:为什么要把 Pulsar 和 Presto 拉到一张表上干活?“Pulsar集成presto”这六个字,乍看像两个技术名词的简单拼接,但背后是一条真实存在的、高频发生的工程痛点链路:某公司实时风控系统每天要处理200亿条用户…

2026/10/19 4:20:10

JavaScript Tab栏切换效果:语义化、性能与可访问性实战

1. 项目概述:为什么一个Tab栏切换效果值得花时间深挖?“JavaScript-Tab栏切换效果”这八个字,看起来平平无奇,像是前端新手入门练习册里第3页的课后题。但在我带过的几十个前端实习项目、参与评审过的上百份求职作品中&#xff0c…

2026/10/19 4:20:10

Pulsar集成Presto实现流式SQL实时查询实战

1. 项目概述:为什么要把 Pulsar 和 Presto 拉到一张表上干活?“Pulsar集成presto”——这六个字背后,藏着一个在实时数据架构演进中越来越普遍、也越来越迫切的工程现实:流批一体不是口号,而是每天要跑通的SQL。我最早…

2026/10/19 4:20:10

网页课群自动答题与题库爬取教学实践

1. 项目概述:这不是“外挂”,而是一次标准的网页自动化教学实践“某班网页课群自动答题,爬取题库(1)”——这个标题乍看像某个学生在找捷径,但在我带过十几届网页开发实训课、参与过多个在线教育平台后端维…

2026/10/19 4:20:10

位运算入门:LeetCode 476与1009补数反码的掩码异或解法

1. 题目解读与位运算基础先聊点实在的。LeetCode 476“数字的补数”和1009“十进制整数的反码”,这两道题放在一起刷是特别聪明的选择——它们几乎共享同一个核心逻辑,只是稍微改了改边界条件。如果你刚接触位运算,这两道题能帮你把“按位取反…

2026/10/19 4:15:09

Android简易播放器开发实战:MediaPlayer、Service与音频焦点全解析

简介:面向安卓移动开发初学者的简易音乐播放器完整工程,覆盖登录页面、音乐列表展示、播放控制、进度同步与后台通知栏控制等典型功能模块。资源包共 68 个文件,压缩后 3.22 MB,主要包括 Java 源码、XML 布局与配置、APK 安装包、…

2026/10/18 0:01:50

金融AI落地指南:从调研报告到技术选型与工程实践

简介:这份PDF报告聚焦2025年金融服务业中国AI现状与趋势,面向金融科技从业者、AI战略规划人员及关注行业数字化转型的研究者,帮助读者把握生成式AI在银行、支付、交易等场景中的落地路径与投资方向。资源包内含1个PDF文件,大小约1…

2026/10/19 0:04:56

悟空开源无代码平台实战:从实体建模到应用设计避坑指南

简介:基于悟空开源无代码平台的多种应用设计源码,面向希望在不编写代码的情况下快速搭建CRM、HRM、财务系统、ERP、SRM等业务应用的企业与技术人员,通过拖放式界面和内置模板即可完成应用定制与部署。压缩包共697个文件,约10.74MB…

2026/10/19 0:04:56

基于.NET9的多租户权限系统:数据权限与动态API落地实践

简介:这份资源是一套面向 .NET 与 Vue 全栈开发者的中台权限管理系统,后端基于 .Net9,前端采用 Vue3 Element Plus,并配套 uniapp uviewui 移动端方案,实现前后端分离。系统覆盖多租户隔离、数据权限、动态 Api、任务…

2026/10/19 0:04:56

场地预约小程序毕设实战:SSM+微信小程序+MySQL数据库设计到避坑

简介:面向毕业设计场景的场地预约小程序完整项目,基于微信小程序SSMMySql技术栈开发,适合计算机相关专业学生作为选题参考、功能扩展或二次开发起点。系统实现场地类型管理、场地管理、预约管理、取消申请与押金退回等功能,分为管…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑