Python违规驾驶行为识别系统毕设源码详解
2026/9/23 6:38:21 网站建设 项目流程

简介:一套面向毕业设计场景的Python违规驾驶行为识别系统源码,适合计算机视觉、智能交通方向的学生开展课题研究或项目复现。资源共包含128个文件,压缩包大小约64.93MB,主要文件包括81个Python脚本构成的核心检测与识别逻辑、8个Shell脚本用于自动化部署与运行,以及模型权重文件(pth/pkl)、说明文档和少量图片示例,整体目录结构清晰,便于按模块查阅。包内还附带若干ZIP子包,可用于快速还原项目环境或补充依赖;同时,多个Markdown与文本说明文档能辅助理解代码结构和运行方式。目前已有1061人浏览学习。通过学习这套源码,可以理解从数据准备、模型调用到结果输出的完整流程,掌握驾驶行为识别的工程实现方法;同时借助说明文档和配置文件,能方便地开展参数调整与功能二次开发,快速形成可用于毕设答辩和论文实验的系统原型。

1. 违规驾驶行为识别系统:这套 Python 源码为什么值得当毕设底子

做毕设最怕的不是题目难,而是开头不知道从哪里下手。这套 Python 违规驾驶行为识别系统源码,恰好是那种能把"图像处理 + 行为判定 + 完整展示"一次性串起来的项目。它做的是实时监测驾驶员是否打电话、抽烟、疲劳状态异常,核心逻辑是先把视频帧里的手部、面部关键点提出来,再按区域和姿态规则做违规判断。对计算机视觉方向的学生来说,它比单纯的物体检测多了层行为语义,又不至于像动作识别那样需要大算力支撑,中等配置的笔记本就能跑起来,很适合拿来扩写成自己的毕设框架。源码包里带 README、CHANGELOG 和一个 grid.npy 坐标文件,下面把这套系统怎么拆、怎么跑、哪里容易翻车一次讲透。

2. 系统整体结构与核心判定逻辑:先看懂它靠什么识别违规

2.1 检测链路:从视频帧到违规行为标签

这套系统不是上来就做端到端的深度学习分类,而是走了一条更稳妥的流水线:视频帧输入 -> 人脸/手部关键点检测 -> 特征坐标映射 -> 规则引擎判定 -> 输出违规标签与告警。这种结构在毕设答辩里特别好讲,因为每一层都能单独展开。

关键点检测部分用的是 MediaPipe 的 Face Mesh 和 Hands 两个图,它不需要自己训练模型,pip 装好依赖就能用。MediaPipe 对手部 21 个关键点和面部 468 个关键点的输出是归一化坐标,范围在 0 到 1 之间。grid.npy 这个文件存放的就是一张网格查表,程序会把归一化坐标映射到网格坐标系里,再结合方向盘、中控台等区域的预设范围做判断。

import numpy as np import cv2 import mediapipe as mp # 加载网格坐标文件,用于把关键点映射到驾驶舱区域 grid = np.load("grid.npy") mp_hands = mp.solutions.hands hands = mp_hands.Hands( static_image_mode=False, max_num_hands=2, min_detection_confidence=0.7, min_tracking_confidence=0.5 )

这段代码里,min_detection_confidence 是关键点检测置信度阈值,低于 0.7 的帧会被过滤,防止误检。min_tracking_confidence 是帧间跟踪阈值,调高能减少抖动但会增加漏检。毕设跑实验时我会把检测阈值固定在 0.7 左右,太低的话背景里的陌生人手都会被识别成驾驶行为,误报率会很难看。

2.2 违规行为的判断阈值怎么设

打电话的判定逻辑是手部关键点与耳朵区域的重合度。系统先取出每只手的食指指尖坐标(Landmark 8)和中指指尖坐标(Landmark 12),计算它们与面部耳朵关键点的欧氏距离。距离小于设定阈值就认为手在耳旁,持续超过 2 秒判定为打电话。

抽烟行为更依赖手部与嘴部区域的相对位置。烟支本身不检测,而是检测手部是否反复出现在嘴部区域。代码里用了一个滑动窗口,统计最近 30 帧内手部在嘴部区域的命中次数,命中率超过 60% 判定为抽烟。这个思路很巧妙,因为抽烟动作中手会短暂离开,单纯看瞬时位置会漏判,加一个时间窗口就稳很多。

疲劳驾驶部分用的是 Eye Aspect Ratio(EAR)这个经典算法。它取眼睛的六个关键点,计算眼睑开合程度。EAR 低于 0.25 且持续超过 0.4 秒算一次闭眼,闭眼频率每分钟超过 15 次就判定为疲劳驾驶。

def compute_ear(eye_points): # eye_points 是 MediaPipe 输出的单眼 6 个关键点坐标 p1, p2, p3 = eye_points[1], eye_points[4], eye_points[2] p4, p5, p6 = eye_points[0], eye_points[5], eye_points[3] vertical_a = np.linalg.norm(p2 - p4) vertical_b = np.linalg.norm(p3 - p5) horizontal = np.linalg.norm(p1 - p6) return (vertical_a + vertical_b) / (2.0 * horizontal)

EAR 的原理是:眼睛睁开时上下眼睑距离大,EAR 值接近 0.3;闭眼时上下距离趋近于 0,EAR 值掉到 0.1 以下。这里要注意,不同人眼型差异会让基线值不一样,代码里用的是固定阈值 0.25,实际用自己拍的视频测试时最好先跑一段正常驾驶的状态,统计出正常的 EAR 均值再微调阈值,不要直接照搬论文里的数值。

2.3 文件结构里最重要的三个文件

解压后的源码包文件不多,但每个都有用途。README.md 是项目的说明文档,作者通常会把环境依赖、启动命令、数据集来源写在里面。CHANGELOG.md 记录了版本迭代,你可以从里面看到作者修过哪些 bug,这对答辩时讲"项目演进过程"很有用。grid.npy 是行为判定的坐标依据,如果路径写错程序会直接崩在加载阶段。

文件作用使用注意
README.md环境说明与启动指引对照确认 Python 版本与依赖
CHANGELOG.md版本更新日志从这里找已知问题
grid.npy驾驶舱区域网格坐标必须与源码同目录或正确指定路径
.gitignore配置文件毕设打包时可删除

这个项目本质上是把关键点检测和规则判定结合起来,整个系统里没有需要自己训练的部分,MediaPipe 模型在安装依赖时自动下载,所以对算力的要求很低。如果你的毕设需要体现一点技术深度,可以在规则判定的时间窗口参数上做调优实验,这几组参数就是天然的实验变量。

3. 本地复现完整流程:从环境搭建到跑通第一帧检测

3.1 环境安装与依赖版本搭配

这套系统基于 Python 开发,开发语言是 Python,建议使用 3.8 到 3.10 版本。不要用最新的 Python 3.12,MediaPipe 的兼容性更新没有跟上,很多机器上会直接报错找不到模块。推荐用 Anaconda 创建一个独立环境,避免把系统 Python 弄乱。

conda create -n drive_behavior python=3.9 conda activate drive_behavior pip install mediapipe==0.10.7 pip install opencv-python==4.8.1.78 pip install numpy==1.24.3 pip install PyQt5==5.15.9

这里锁定版本是有原因的。mediapipe 0.10.7 是最后一个对 Python 3.9 和 Windows 都维护得比较好的版本,新版对 OpenCV 的依赖版本要求更苛刻。opencv-python 用 4.8 系列,是因为 4.9 开始在部分摄像头设备上读取帧的格式变了,容易出现画面花屏。numpy 保持 1.24.x,MediaPipe 内部有 C 扩展编译逻辑,numpy 2.x 的 API 变更会导致导入崩溃。

3.2 启动主程序跑通检测

依赖安装完成后,先确认源码包里是否有缺失文件。很多毕设源码下载下来后缺少模型文件或配置文件,直接运行会报 FileNotFoundError。先检查 grid.npy 是否在源码根目录下,MediaPipe 模型会在首次运行时长传到用户目录下,这个过程需要网络,且国内网络环境下可能比较慢。如果下载卡住,可以手动把模型文件放到~/.mediapipe/models目录下,源码包里通常不包含模型文件,需要从 MediaPipe 官方 GitHub 仓库下载。

# 在项目根目录下执行 python main.py --source 0 --show true

main.py 是启动入口,这里的--source 0表示读取 0 号摄像头。如果电脑有多个摄像头,可能需要改成 1 或 2。--show true表示把识别画面弹窗显示出来,调试阶段保持这个参数打开,能看到实时的关键点绘制和违规标签输出。

跑通之后,如果画面能流畅显示并且手在脸旁时能触发打电话标签,说明整条链路已经通了。接着可以准备一段自己录制的模拟驾驶视频,测试里面是否会同步弹窗标出违规行为。

3.3 视频源与图片源测试

测试阶段不建议一上来就对着摄像头操作,因为人要同时兼顾开车动作和观察屏幕,效率很低。最理想的方式是先用手机横屏录制一段自己在驾驶位上的模拟视频,各种打电话、抽烟、假装打哈欠动作都做一遍,每段持续 10 秒左右。然后把视频文件路径传入接口。

python main.py --source ./test_videos/demo_phone.mp4 --show true

使用视频文件的好处是可以反复复现同一个场景,方便对照调参,也能在答辩现场快速展示。录制时注意几个细节:人坐在驾驶位,背景不要有其他人;光线尽量均匀;动作幅度夸张一些,关键点检测需要足够清晰的手部轮廓。抽烟动作需要把烟夹在中指和食指之间靠近嘴边保持一两秒,太快的动作会被时间窗口过滤掉。

3.4 grid.npy 和区域标定兜底方案

如果摄像头安装位置或者拍摄角度导致识别不准,源码里有两种标准做法。第一种是修改区域判定阈值,把方向盘、耳朵、嘴部的坐标范围在代码里直接改掉。第二种是重新生成 grid.npy 网格文件,适合换了摄像头视角的场景。重新生成的逻辑是选取一个参照物,比如方向盘中心位置作为锚点,然后按照实际距离比例生成 5x5 的网格区间。

import numpy as np # 以方向盘中心为基点,向四周扩展 2 格,每格间距映射为 0.1 归一化坐标 grid = np.zeros((5, 5, 2), dtype=np.float32) base_x, base_y = 0.5, 0.6 step = 0.1 for i in range(5): for j in range(5): grid[i, j, 0] = base_x + (i - 2) * step grid[i, j, 1] = base_y + (j - 2) * step np.save("grid.npy", grid)

这段兜底代码只在源码自带的标定不好用时才需要执行。正常情况下不要动这个网格,因为源码已经按标准驾驶室视角标定过了,随意改动反而会让原有判定区域错位。

4. 识别模块拆解:关键点坐标到行为输出的完整链路

4.1 驾驶舱区域映射:判断违规行为的空间基础

违规驾驶行为识别系统的工作流程从视频帧读取开始,每一帧图像先经过 MediaPipe 处理,得到人脸和手部的关键点坐标。这些坐标默认是相对图像宽高的比例值,范围在 0 到 1 之间。系统会把它们和网格坐标系里的预设区域做比对,判断手部、面部关键点在空间上位于什么位置。

def map_to_grid(x, y, grid): # 将归一化坐标映射到网格索引 grid_h, grid_w = grid.shape[:2] col = int(x * grid_w) row = int(y * grid_h) col = min(max(col, 0), grid_w - 1) row = min(max(row, 0), grid_h - 1) return row, col

grid.npy 在系统里的定位是区域查表,它定义了驾驶舱内几个语义区域在归一化坐标系下的边界。比如网格中特定的行列区间对应"方向盘区域""后视镜区域""车窗区域"。手部关键点在"方向盘区域"附近时,系统判定手在方向盘上;手部关键点出现在"中控台区域"且伴随头部姿态偏转,系统会关注是否存在分心驾驶的可能。

4.2 单元线程调度和实时性优化

视频识别系统的耗时大头在 MediaPipe 关键点推理,单帧在 CPU 上大约耗时 40 到 60 毫秒。为了让整个流程实时运行,源码做了两件事:一是把视频采集和关键点推理放到独立线程里,避免主线程卡顿;二是通过减少输入帧长边的分辨率来控制计算量。

import threading import queue frame_queue = queue.Queue(maxsize=4) def camera_worker(cap): while True: ret, frame = cap.read() if not ret: break frame = cv2.resize(frame, (640, 640)) frame_queue.put(frame) def inference_worker(): while True: frame = frame_queue.get() results = hands.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) # 此处将 results 输入行为判定逻辑

这里帧队列长度限制为 4,是为了控制内存使用。如果队列满了,旧的未被处理的帧会被丢弃,保证新帧不会堆积。实际在低配笔记本上跑,640x640 是一个合理的平衡点;如果你用 1080p 分辨率直接推理,帧率会掉到个位数,体验很差。用 GPU 的话可以上调到 960x960,精度会好一些。

4.3 行为级联判定:多个 Signals 共同决策

系统中每个违规行为不是单一条件触发的,而是多个判定信号经过加权后的结果。打电话需要手部靠近耳朵的同时头部姿态保持相对固定;抽烟需要手部靠近嘴部且手部形状为握持状;疲劳驾驶需要持续闭眼加头部倾斜。这种级联判定逻辑的好处是单路误判不容易激起整体误报。

def decide_phone_call(hand_pts, face_pts, grid): ear_idx = [234, 454, 153, 143, 133, 145] phone_signal = 0 for idx in [8, 12]: dist = np.linalg.norm(hand_pts[idx] - face_pts[ear_idx[0]]) if dist < 0.15: phone_signal += 1 head_tilt = abs(face_pts[1][0] - face_pts[10][0]) if phone_signal >= 1 and head_tilt < 0.08: return True return False

ear_idx这里用到了欧氏距离阈值 0.15,是归一化坐标下的经验值。不同摄像头安装位置和人的坐姿会直接影响这个值,通常调整范围在 0.1 到 0.2 之间。代码里的head_tilt是鼻尖和额头中点的水平偏移差,用来排除转头动作造成的误判。

4.4 Log 输出和告警形式

检测到违规行为后,系统会把结果写入本地日志文件,同时画面中绘制告警框。源码中日志模块记录了时间戳、行为类型和置信度分值,这个日志是后期分析实验效果的重要依据。比如用测试视频跑完之后统计检测到的违规次数和总帧数,就能算出检出率。

import logging logging.basicConfig( filename="violation.log", level=logging.INFO, format="%(asctime)s - %(message)s" ) logging.info("phone_call detected, score=0.82")

日志文件会和源码放在同一目录下,文件名是 violation.log。部分版本支持 Windows 消息弹窗或者声音告警,具体看源码里有没有打开这两个模块的开关。如果答辩时需要演示效果,声音告警比画面上的标签更能带动现场氛围。

5. 毕设场景常见问题排查:五个高频坑位与应急补救

5.1 opencv 导入报错 DLL load failed

现象:在 Windows 机器上执行import cv2直接报DLL load failed: 找不到指定的模块。原因通常是本机缺少 Visual C++ 运行库,OpenCV 的二进制包依赖 MSVC 运行环境。解决方式是最先安装Microsoft Visual C++ Redistributable for Visual Studio 2015-2022,64 位版本必装。另外,如果使用了虚拟环境,确认安装 opencv 时是在激活状态执行的 pip,不要装在全局环境里。仍然报错就在 conda 环境里重新装一遍:

conda install opencv

conda 会自动补齐依赖库,遇到 DLL 问题的概率比 pip 低很多。

5.2 主程序运行后画面黑屏但没有报错

现象:摄像头窗口正常弹出,但画面全黑,程序没有崩溃。原因分两类:第一类是无内置摄像头,外接摄像头在 0 号索引下未被系统识别;第二类是摄像头被其他软件占用,比如微信、腾讯会议。解决方式是先关掉后台视频软件,然后枚举系统里的摄像头索引:

import cv2 for i in range(5): cap = cv2.VideoCapture(i) ok, frame = cap.read() if ok: print(f"camera index {i} works") cap.release()

把 main.py 里--source参数改成能正常读帧的索引即可。

5.3 MediaPipe 模型下载卡住 99%

现象:首次运行时提示下载 face_landmark.task 或 hand_landmark.task 文件,进度条一直停在 99% 不动。原因是网络环境不稳定,MediaPipe 默认从 Google 的存储桶拉取。解决方式很直接,从 gitee 仓库手动下载对应的 task 文件,放到系统用户目录下的.mediapipe/models文件夹中。Windows 下路径是C:\Users\你的用户名\.mediapipe\models,MAC 对应~/.mediapipe/models,没有目录就手动创建。

5.4 识别率低:抽烟被识别成打电话

现象:视频里手在嘴部附近拿着烟,系统输出的是 phone_call 而不是 smoking。原因是两个行为判断分支的距离阈值范围有重叠,手离嘴近时同时满足了打电话判断的耳部距离近似条件。解决方式是调高打电话判断的欧氏距离阈值,或者直接检查源代码里打电话判断是否增加了头部姿态约束。最稳的调整方法:把decide_phone_call函数里的距离阈值从 0.15 调低到 0.10,让手必须更靠近耳朵才能触发。

5.5 视频播放很快但识别滞后

现象:处理视频文件时画面播放速度正常,但行为判定标签比实际动作慢了两秒。原因在于帧队列的缓冲空间有限,当视频帧率高于模型推理速度时,大量待处理帧积压并不断被推入队列。解决方式是把输入视频的读取帧数做降采样,每秒只取 10 帧送识别:

frame_interval = 3 # 原始视频30fps,每3帧取1帧 frame_count = 0 while True: ret, frame = cap.read() if not ret: break if frame_count % frame_interval == 0: frame_queue.put(frame) frame_count += 1

这样既不影响行为持续时间的统计精度,又避免模型推理压力过大产生堆积。

6. 进阶用法:把识别结果做成可视化仪表盘

6.1 导出识别统计,画时间线分布图

源码自带的是实时检测,没有结果统计分析功能。但毕设如果想拿高分,可以把违规识别的时间戳全部落到 CSV 文件,再用 matplotlib 把各违规类别的时间分布画出来。这个图比单纯识别视频更适合答辩,因为可以直观展示违规高发时段。

import csv import matplotlib.pyplot as plt with open("violation_timeline.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["timestamp", "behavior", "duration"]) writer.writerow([2.4, "phone_call", 3.2]) writer.writerow([8.1, "smoking", 4.0])

需要注意的是,源码原有的 violation.log 是日志格式,不是结构化数据,直接画图前需要先做一次解析转换。可以把时间戳提取出来,按每 10 秒一个桶统计违规数量,画出来的就是柱状图。

6.2 接入 PyQt5 做可视化控制界面

如果不满足于黑框运行,可以用 PyQt5 包一层可视化界面,把实时画面显示在 Canvas 上,旁边放一个状态面板,显示当前驾驶员行为状态。这样系统的完整度会再上一个台阶,操作起来也更像一套正规的软件。PyQt5 已经包含在依赖里了,几行代码就能搭出主窗口。

from PyQt5.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget from PyQt5.QtGui import QImage, QPixmap class MainWindow(QWidget): def __init__(self): super().__init__() self.setWindowTitle("违规驾驶行为识别系统") self.label = QLabel() layout = QVBoxLayout() layout.addWidget(self.label) self.setLayout(layout) def update_frame(self, frame_bgr): h, w, c = frame_bgr.shape img = QImage(frame_bgr.data, w, h, w * c, QImage.Format_RGB888).rgbSwapped() self.label.setPixmap(QPixmap.fromImage(img))

在把视频帧塞给 PyQt 窗口时,OpenCV 的 BGR 通道顺序要转成 RGB,否则画面整体偏蓝。代码里最后一句rgbSwapped()就是干这个的。

6.3 从入门到顺手:一些调试习惯

这套源码跑通之后,我强烈建议你做一件事:找一段你自己的模拟驾驶视频,挨个把每个违规行为测试五遍。不要只测正常姿势,还要测侧脸、戴帽子、光线偏暗这些边缘情况。很多代码里平时隐藏的逻辑问题,都是在这种笨办法里翻出来的。比如我当时测试侧脸打电话,发现头部姿态约束把侧脸动作直接过滤掉了,后来调低 head_tilt 阈值才恢复正常。从那以后我每次拿到新识别项目,都会强制走一遍"多角度验证"的流程,把边缘情况的参数一并记录下来,比事后推测原因省力太多了。希望这套源码的拆解过程,也能帮你少踩几个一样的坑。

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

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

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

立即咨询