ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python违规驾驶行为识别系统:基于YOLO的目标检测与毕设实战指南

Python违规驾驶行为识别系统:基于YOLO的目标检测与毕设实战指南 简介面向课程设计与毕业设计准备的Python违规驾驶行为识别系统源码是一套覆盖从环境搭建、数据准备、模型训练到检测结果输出的完整项目适合计算机视觉、人工智能方向的学生用作毕设基线或进行二次功能扩展。压缩包共128个文件整体约64.93MB。81个Python脚本承载核心算法与流程控制Shell脚本提供一键运行或环境初始化入口Markdown和TXT文档用于说明使用方式、目录结构与配置参数pkl、pth权重文件可直接加载预训练模型PNG与npy数据文件配合完成效果预览和输入验证。整体目录组织清晰方便按模块定位阅读。资源目前已有1061人学习/下载对缺少完整可运行代码的同学尤其友好。通过源码可理解驾驶行为识别的主流技术路线包括数据读取、特征提取/模型搭建、训练验证、结果可视化等环节配套文档和脚本能帮助快速复现运行环境理清模块间调用关系同时附带的版本变更记录与License信息也有助于追溯更新动态和合规使用在此代码基础上替换数据集或调整网络结构即可开展进一步实验有效降低毕设开发门槛。1. Python违规驾驶行为识别系统这东西到底解决什么问题你手上这份「Python违规驾驶行为识别系统源码可用做毕设.zip」说白了就是一个用摄像头画面自动判断司机有没有在打电话、抽烟、打瞌睡、分神看手机的系统。它属于计算机视觉里的目标检测加行为分类输入是一段视频或实时摄像头流输出是“第几秒、哪个区域、什么违规行为、置信度多少”。对毕设来说它的价值在于技术栈完整Python、OpenCV、YOLO系列目标检测、时序判定逻辑、GUI展示一套下来能撑起一个完整的本科课题。适合的人群很明确计算机、软件、大数据相关专业想做一个有实际场景、能演示、能讲清楚原理的毕业设计而不是纯算法玩具。这套系统还能继续往疲劳驾驶、车队管理、驾校考试等方向延伸是你毕设里少数几个能“做完还有商业想象力”的方向。我见过太多人拿到这类压缩包解压完发现跑不起来就放弃了实际上问题大多出在环境、路径和模型权重这三处这篇文章就是把这条路给你趟平。2. 系统的整体构成与数据准备先搞清楚一个识别系统里都有什么2.1 模块拆分检测、分类、决策、展示四层结构不管压缩包里代码怎么组织一个能用的违规驾驶行为识别系统在逻辑上一定分四层。第一层是图像采集与预处理负责从视频文件或者摄像头读帧、缩放、转色彩空间这一层通常由OpenCV完成代码里体现为cv2.VideoCapture加一个while True循环。第二层是目标检测常见做法是用YOLO系列模型检测画面里的“人手”“手机”“香烟”“人脸”这些对象输出边界框和类别。第三层是行为判定也是这个系统真正有“智能”的地方——检测到手机和人手同时出现在画面里不代表司机在打电话可能是正在拿手机导航所以需要结合边界框位置关系、持续帧数、手与耳朵或嘴部的距离做时序判断。第四层是展示与告警把检测结果画在画面上、记录日志、触发声音或截图报警。理解了这四层你去读zip里的源码就不会懵。绝大多数毕设源码的组织方式都是main.py做入口、detector.py封装模型、utils.py放工具函数、models/放权重文件。如果压缩包里连这个基本结构都没有说明这份源码质量存疑。另外提醒一句拿到压缩包第一件事不是打开代码看而是先看有没有requirements.txt和README.md这两个文件决定你本地能不能在两小时内跑起来。2.2 数据集从哪来公开数据集与自建数据集怎么选违规驾驶行为识别这个方向公开数据集说多不多说少不少。常见的有State Farm的驾驶员状态检测数据集分心驾驶分类、SFU3D手势数据集、以及一些开源项目里整理好的“打电话/抽烟/正常驾驶”三分类图片集。这些数据集的特点是场景偏美国或欧洲方向盘在左边司机的人种和穿着跟你最终演示环境有差异导致你直接拿训练好的权重在本地跑效果可能不理想。我建议的做法是两条腿走路先下载公开数据集比如从Kaggle找distracted driver detection相关的数据用现成的跑通整个pipeline然后自己录20到30分钟视频覆盖打电话、抽烟、看手机、正常驾驶四个场景用OpenCV把视频抽帧成图片再用标注工具框出目标。自建数据的好处是你答辩时导师问“这个样本从哪来的”你可以理直气壮说现场采集的而不是支支吾吾说从网上扒的。抽帧代码很简单一个cap.read()循环加间隔计数每5帧存一帧就能用。2.3 标注与格式转换把标注结果变成YOLO能吃的TXT数据集准备好后最花时间的环节就是标注。常见标注工具有LabelImg和Labelme前者输出的是Pascal VOC格式的XML后者输出JSON。YOLO系列训练需要的格式是每个图片对应一个TXT文件每行内容为类别id x_center y_center width height四个坐标值都是归一化到0到1之间的浮点数。import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(xml_folder, txt_folder, class_namesNone): xml_files Path(xml_folder).glob(*.xml) class_map {} if class_names else {phone: 0, smoke: 1, normal: 2} for xml_file in xml_files: tree ET.parse(str(xml_file)) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) txt_path Path(txt_folder) / (xml_file.stem .txt) lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_map: class_map[cls_name] len(class_map) cls_id class_map[cls_name] box obj.find(bndbox) xmin int(box.find(xmin).text) ymin int(box.find(ymin).text) xmax int(box.find(xmax).text) ymax int(box.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) return class_map这段代码读入XML里的目标框把左上右下的像素坐标换算成归一化的中心点和宽高。换算公式不复杂核心就一句(xmin xmax) / 2 / 图片宽得到中心点x坐标宽高同理除以图片尺寸。这里有个新手容易踩的坑YOLO的坐标是中心点加宽高不是左上角加右下角如果你用VOC标注工具习惯了x1 y1 x2 y2的思维写转换脚本时很容易忘记这步。标注的类别不要设太多我见过有人把“打电话”拆成“左手打电话”“右手打电话”“拿手机到耳边”三个类训练出来一团糟。类别就设phone、smoke、normal三个最多加一个drink喝水够了。2.4 数据集划分按“采集成片”划分别按单张图随机打乱划分训练集和验证集看似简单实际上有个容易翻车的细节。一张一张图随机划分会导致同一个人的同一段视频帧既出现在训练集又出现在验证集里模型等于提前见过答案验证指标虚高答辩现场换成新视频立刻现原形。正确做法是先按视频片段分组整个片段的帧要么全进训练集要么全进验证集。import os import shutil import random from pathlib import Path def split_by_video(src_img_dir, src_txt_dir, train_dir, val_dir, split_ratio0.8): videos {} for img_path in Path(src_img_dir).glob(*.jpg): video_id img_path.stem.split(_frame_)[0] videos.setdefault(video_id, []).append(img_path.stem) video_ids list(videos.keys()) random.seed(42) random.shuffle(video_ids) train_count int(len(video_ids) * split_ratio) for i, vid in enumerate(video_ids): target train_dir if i train_count else val_dir for stem in videos[vid]: shutil.copy(str(Path(src_img_dir) / f{stem}.jpg), str(Path(target) / images / f{stem}.jpg)) shutil.copy(str(Path(src_txt_dir) / f{stem}.txt), str(Path(target) / labels / f{stem}.txt))注意这里的文件名命名规则我习惯把视频ID放在文件名最前面比如video01_frame_0012.jpg这样按split(_frame_)[0]就能取出视频ID。如果你的源码里文件名格式不同那这行切片逻辑就要相应改掉。划分完以后YOLO训练时还需要一个data.yaml文件声明训练集路径、验证集路径和类别名列表很多毕设源码里的yaml路径是写死的绝对路径你换台电脑就报错这也属于常规操作了。3. 模型训练路线与关键参数直接用现成权重还是从零微调3.1 三条路线对比YOLOv5微调、YOLOv8微调、传统OpenCV方案对于毕设这个场景目标检测部分不外乎三条路线。第一条是用YOLOv5的官方预训练权重做迁移学习只冻结骨干backbone微调检测头head优点是对硬件要求低、社区资料多、网上能找到大量现成经验帖。第二条是用YOLOv8也就是现在ultralytics主推的系列API更友好、训练命令更简单、精度略高但配套的毕设代码相对少一些。第三条是用传统OpenCV加HOG特征或者肤色检测做手和手机的定位优点是代码量看起来“很硬核”缺点是鲁棒性差稍微换个光线就崩。我的建议是选YOLOv8理由很实在ultralytics这个库把训练、验证、导出、推理封装得极其顺滑你不需要写太多底层代码可以把精力放在行为判定逻辑和系统集成上这两个部分才是答辩时能讲出东西的地方。不要从零训练一个YOLO模型。YOLO的预训练权重是在COCO数据集上训出来的COCO里有person、cell phone这些类别直接在这个基础上去微调你自建的违规行为数据集数据量只要几百张也能出效果。从零训练的话没有几万张图根本训不出来那是把毕设搞成科研项目了。3.2 训练命令与核心参数跑通一个最小可用的训练流程选定路线后训练本身不复杂复杂的是参数理解和环境配置。先给一个最小可用的YOLOv8训练命令pip install ultralytics opencv-python numpy yolo train datadataset/data.yaml modelyolov8n.pt epochs50 batch16 imgsz640 device0这段命令里modelyolov8n.pt是从官方下载nano版本的预训练权重dataset/data.yaml换成你的数据配置文件路径。epochs设50轮足够判断模型能不能收敛batch16在8GB显存上跑nano模型没有问题device0指定使用第一块GPU纯CPU环境改成devicecpu但速度会慢得多。有几个参数需要格外解释。imgsz是训练时输入图像的尺寸640是默认值也是性价比最高的值。超过640精度提升有限但显存占用和推理耗时直线上升对于毕设场景完全没必要。patience参数控制早停如果验证集损失连续多少轮不下降就提前结束训练我一般设20防止过拟合。lr0初始学习率默认0.01不用动。还有一个参数mosaic是数据增强里的马赛克拼接YOLOv8默认开启它会同时拼4张图训练小数据集上效果很好但如果你发现训练曲线震荡得厉害可以先关掉试一轮。训练过程里重点看两个指标mAP50和mAP50-95。前者是IoU阈值0.5时的平均精度后者是0.5到0.95的均值毕设答辩你只需要讲明白mAP50就够了它衡量的是“模型框得准不准”。如果训完mAP50低于0.8先别急调参去检查标注文件里的坐标值有没有归一化错、类别id有没有对不上。3.3 自建数据集的训练策略数据增广与类别不均衡怎么处理如果你最终用的是自建数据集几个问题会立刻冒出来。第一个是类别不均衡正常驾驶的帧数可能占了70%打电话和抽烟各占15%模型会倾向于把所有图都判成normal。解决办法是在训练命令里加cls参数提升小类别的损失权重YOLOv8里对应的是cls0.7之类的配置。第二个问题是样本多样性不足你的自建数据可能只有固定角度、固定光线模型上了考场换个摄像头就翻车此时加大hsv_h、hsv_s、hsv_v这些颜色增广参数会有效果默认值分别是0.015、0.7、0.4。还有一个值得说的技巧单类别训练和双类别训练的区别。如果你只检测手机和手就设两个类如果想把“手拿着手机靠近耳朵”这种动作也检测出来那要加一个phone_to_ear类但代价是标注工作量翻倍。毕设不需要做那么细你可以在行为判定逻辑层用距离关系推出来这个后面第4章会讲到。4. 行为识别逻辑与推理管线从检测框到“违规”判断4.1 后处理的核心连续帧判定、重叠度计算、行为冲突消解目标检测模型输出的只是一堆边界框和置信度真正决定“有没有违规”的是一段决策逻辑。常见的坑是单帧判定也就是某一帧检测到手机就直接截图报警这样误报率极高。合理的做法是加一个帧计数窗口连续N帧中至少M帧检测到同一行为才触发报警N和M的关系一般是M ceil(N * 0.6)比如5帧里至少3帧判定违规才报警相当于做了一次简单的时间维度的去抖。第二个关键点是行为冲突消解。检测器可能在同一次推理里既输出了phone又输出了smoke这往往是因为手部区域同时和手机、香烟的框高度重叠。处理方式是按置信度排序高置信度的类别胜出或者按优先级表比如打电话的优先级高于看手机。更稳妥的做法是引入类别间互斥规则一个手部区域同一时刻只能关联一种违规行为。第三个点是IoU重叠计算用来判断检测框是否在同一个手部区域。这个计算在ultralytics的utils里有现成函数但如果你的源码里不是用YOLOv8而是自己写的后处理就需要手算。10行左右就能实现核心公式是交集面积除以并集面积不需要额外装库。4.2 推理代码的可复现示例摄像头流接入与行为判定下面这段代码展示了一个完整的推理循环读取本地视频逐帧送入模型根据检测框位置关系做行为判定连续触发后输出告警。import cv2 from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) cap cv2.VideoCapture(test_video.mp4) frame_buffer [] alert_triggered False while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame, conf0.45, iou0.5, verboseFalse) boxes results[0].boxes phone_boxes [] smoke_boxes [] for box in boxes: cls_id int(box.cls[0]) xyxy box.xyxy[0].cpu().numpy() if cls_id 0: phone_boxes.append(xyxy) elif cls_id 1: smoke_boxes.append(xyxy) violation False for phone in phone_boxes: for hand in hand_boxes: iou compute_iou(phone, hand) if iou 0.3: violation True break if violation: frame_buffer.append(1) else: frame_buffer.append(0) if sum(frame_buffer[-5:]) 3: if not alert_triggered: cv2.imwrite(alert_snapshot.jpg, frame) print(违规驾驶行为触发截图已保存) alert_triggered True else: alert_triggered False cap.release()说明几个关键点。conf0.45是置信度阈值低于这个值的检测结果会被丢弃。这个参数直接影响误报和漏报的平衡调低到0.3会漏检变少但误报变多调高到0.6则反过来建议在0.4到0.5之间。iou0.5是NMS的IoU阈值控制重叠框的合并力度一般不需要动。frame_buffer[-5:]取最近5帧的判定结果sum 3就是前面说的“5帧里至少3帧违规”。这里有个隐藏问题frame_buffer列表无限增长的话切片操作会越来越慢严谨的写法是用collections.deque(maxlen5)替代列表。压缩包里如果连这种细节都注意到了起码说明源码作者是认真写的。4.3 手部区域检测单独检测手还是用人体关键点推理很多违规驾驶系统在实现“打电话”行为时不只是看手机有没有出现还要看手离耳朵近不近。这里有两条路一条是单独训练一个hand类别然后用手机框和手框的IoU判断另一条是用人体姿态估计模型如YOLOv8-pose或MediaPipe提取手腕和耳朵的关键点坐标计算欧氏距离。后者的优势是抗遮挡能力强手举起来但被方向盘挡住一半时关键点仍然能估算出来劣势是计算量更大推理速度可能会掉到10帧以下。毕设演示场景用的是录好的视频帧率要求不高姿态估计路线显得更“高级”答辩时有得讲。如果用的是实时摄像头我建议还是走第一条路因为关键点模型的稳定性在教室灯光、摄像头角度受限的情况下并不好容易抖动。5. 毕设集成与排查避坑源码跑不通的常见原因和处理办法5.1 环境与依赖解压后第一小时最容易踩的四个坑拿到zip压缩包后第一小时里踩的坑往往不在代码本身而在环境。第一个坑是Python版本不对很多老毕设源码基于Python 3.8或3.9你用Python 3.12直接pip install -r requirements.txt大概率有包编译失败。常见做法是先用python --version确认版本再决定是装一个虚拟环境还是降级。第二个坑是torch和torchvision版本对不上YOLOv5源码要求torch1.7但如果你的显卡驱动只支持新版CUDA装老版本torch反而起不来。第三个坑是路径中文问题压缩包解压出来如果路径里带了中文opencv读图片和torch加载权重时经常报找不到文件的错把整个项目挪到纯英文路径下能解决90%的加载报错。第四个坑是缺失opencv-python的特定版本有些源码里用了cv2.dnn模块默认装最新的opencv会报属性错误这时候pip install opencv-python4.5.5.64这类老版本反而稳。5.2 运行报错排查从“No module named”到“CUDA out of memory”下面按概率从高到低列几个高频报错和处理办法。现象一ModuleNotFoundError: No module named ultralytics。原因就是没装依赖包。解决按源码里requirements.txt逐个安装不要用pip install -r requirements.txt一次跑完然后坐等而是装完一个包就导入验证一次至少能定位到哪个包装失败了。现象二RuntimeError: CUDA out of memory.。原因有两个可能一是batch size设太大二是显存被其他进程占了。解决先看nvidia-smi确认显存占用再调小batchYOLOv8推理模式下加batch1训练模式调成batch4或batch8。还不行就换yolov8n.ptnano模型显存占用只有几百兆。现象三AttributeError: NoneType object has no attribute shape。这个报错几乎都出现在视频路径错误或摄像头读取失败。原因代码里cv2.VideoCapture(video.mp4)打开失败返回的cap是空对象而代码没有判断ret就继续读帧。解决在cap.read()后加一个判空同时确认视频文件路径有没有写错。这一步也是源码里最常见的偷懒点。现象四训练时loss一直不降反而震荡上升。原因大概率是学习率过大或者标注文件有脏数据。解决先关掉mosaic增强试一轮再检查标注TXT里有没有数值大于1或小于0的坐标这类脏数据会直接拉崩训练曲线。现象五中文路径导致yolo train报找不到data.yaml。解决路径里不要出现任何中文字符包括你的用户名目录比如C:\Users\张三\这种就是典型的雷区。5.3 效果不好时优先调整的三个方向如果模型训练完了但实际效果差先别急着换模型架构。优先调整三个方向第一个是置信度阈值把推理时的conf从0.25往0.5方向调往往误报会显著下降。第二个是训练数据的光线多样性如果你只用白天录的数据加一批夜间或逆光的帧效果提升往往比调参更明显。第三个是输入分辨率推理时把imgsz从640降到480速度变快但精度略降从640升到960则反过来。这三个方向成本低、见效快比你去换检测头或者改backbone实际得多。6. 进阶功能与效果验证让系统从“能跑”到“能答辩”6.1 验证方法量化指标与演示视频录制系统做完了怎么证明它有效我见过太多同学在答辩时只会说“看能检测出来”然后被老师一个问题问倒“准确率多少误报率多少”所以模型训完后第一件事是在测试集上跑一个指标统计脚本计算每个类别的精确率Precision、召回率Recall和F1值。精确率衡量的是“你报警的里面有多少是真正违规的”召回率衡量的是“真正违规的有多少被你报出来了”。对于一个毕设来说精确率比召回率更重要因为误报会严重损害系统的可信度漏报反而可以解释为“受限于摄像头视角”。ultralytics自带的model.val()会输出这些指标直接抄进论文即可。演示视频的录制也有讲究别用训练集里的视频片段做演示导师一眼就能看出来效果虚高。正确做法是单独录一段2到3分钟的视频包含两次打电话、一次抽烟和几段正常驾驶的过渡注意一个细节动作要缓慢、明显、持续别一晃而过检测器还没反应就结束了。如果演示时画面是黑的或者卡帧大概率是摄像头读取问题提前用ffplay或VLC测试一下视频文件的编码格式H.264通常没问题某些特殊编码会导致OpenCV打不开。6.2 轻量化与落地导出成ONNX模型提升推理速度如果演示时觉得推理速度太慢可以做一个轻量化操作把训练好的模型导出成ONNX格式用ONNX Runtime做推理速度通常能提升1.5到3倍。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.export(formatonnx, imgsz640, halfTrue, simplifyTrue)这段代码把PyTorch权重导出为ONNX格式。halfTrue开启半精度推理显存占用减半但精度损失很小simplifyTrue会做一些图优化去掉冗余计算。导出后可以用onnxruntime加载做推理或者再进一步转成TensorRT或OpenVINO的格式。不过这一步对毕设来说是加分项不是必选项只有在答辩演示电脑性能比较差时才需要。导出成功以后记得验证一下输入输出维度ONNX的输入张量格式是NCHW部分代码里会用torch.randn(1, 3, 640, 640)做一次假推理确认没有报错。6.3 我习惯的一个收尾动作把“误报样本”收集起来一个我自己吃了亏才养成的习惯系统跑了一段时间后把每次误报的截图都自动存档单独建一个false_positive_samples/目录。这些误报样本后续有两种用途一是追加到训练集里做增量训练模型会慢慢学会之前不会的东西二是答辩时可以作为“系统局限性分析”的素材主动说出你的系统在什么场景下会误报、为什么误报、怎么改善这比被导师问住然后支支吾吾要体面得多。很多毕设系统做完即弃能主动收误报样本的答辩时讲出来的东西完全不是一个层次。市面上有些源码包里会附带一个hard_examples目录里面放的就是这类样本如果没有你自己建一个花不了多少时间。另一个收尾动作是检查告警日志的格式。系统里应该有一个log目录每次违规行为触发时记录时间、类别、置信度和截图文件名的对应关系。日志别用中文命名编码会折腾你violation_20250101_153025.jpg这种命名足够直观且不会有编码问题。有了日志你论文里就能写“本系统对X段测试视频进行验证共检出违规事件N次其中真实违规M次误报K次精确率P%召回率R%”这一串数据下来毕设的实证章节就是实的不是虚的。最后说句心里话做这类毕设题目真正拉开差距的不是模型精度那零点几个百分点而是整个流程能不能闭环数据从哪来、标注怎么做、训练参数怎么解释、推理结果怎么验证、误报怎么改进。这一套走下来哪怕模型效果不是顶尖你也能把这个课题讲得清清楚楚。我自己带过几个学生做类似题目发现凡是踏实走完这套流程的答辩基本不会被问倒凡是只想着把代码跑通截几张图交差的最后都在“这个检测是怎么实现的”这个问题上卡了壳。希望这篇笔记能帮你少走点弯路现在就去把你电脑上那个zip解压出来按顺序把环境装好、跑通推理、再录一段自己的视频吧。本文还有配套的精品资源点击获取
返回列表