简介:这是一套面向计算机、人工智能与自动化专业学生及初学者的交通场景智能分析系统源码,聚焦车辆与行人检测、车牌识别、车型分类、车速估算及多目标跟踪等核心任务,适用于课程设计、毕业设计与算法实践。资源包共2000个文件,以764个Python脚本(含YOLOv5模型训练/推理、DeepSORT跟踪逻辑、LPR3车牌识别模块、车速计算与GUI主程序)、63个YAML配置文件(模型参数与数据路径定义)、1127个TXT日志与标注说明为主,辅以XML标注样本、Shell部署脚本及Markdown项目文档,整体体积达605.6MB,结构清晰、模块解耦度高。已有1112人学习下载,代码经完整调试并用于高分毕设答辩(95分),附带可直接运行的PyQt5图形界面,涵盖实时视频流处理、检测结果可视化、目标计数统计与速度动态标注等功能,为学习者提供从环境配置、模型调用到GUI集成的全链路参考范例。
1. 项目概述与核心价值
最近在整理过往的项目资料时,翻出了一个挺有意思的“老伙计”——一个基于YOLOv5、LPRNet(这里用LPR3代指)、DeepSORT和PyQt5的交通识别检测系统。这个项目当时是为了一个智慧园区出入口管理的POC(概念验证)而开发的,目标很明确:在一个集成的图形界面里,实时处理视频流,同时完成车辆/行人检测、车牌识别、车辆跟踪,并估算车速。虽然现在YOLOv8、YOLOv10乃至各种Transformer模型层出不穷,但这个“YOLOv5+LPR+DeepSORT”的组合拳,在轻量级、实时性和准确性上,依然是一个非常经典且实用的解决方案,特别适合边缘计算设备或对成本敏感的中小规模部署场景。
这个系统的核心价值在于“一体化”和“可落地”。它不是一个单纯的算法演示,而是一个带完整图形用户界面(GUI)的应用程序。你不需要在命令行里敲各种指令、看一堆终端输出;所有功能,从打开摄像头或视频文件、调整模型参数、查看识别结果到导出数据,都可以通过鼠标点击完成。这对于交付给最终用户、进行现场演示或者作为二次开发的基础框架,意义重大。它解决了从算法模型到实际应用“最后一公里”的问题,把复杂的深度学习模型封装成了一个普通操作人员也能使用的工具。
2. 技术栈深度解析与选型逻辑
为什么是这几个技术?这背后是我们在平衡精度、速度、开发效率和部署成本后做出的选择。
2.1 目标检测:为何坚守YOLOv5?
在项目开发时,YOLOv5正处在它的鼎盛时期。相比于更早的YOLOv3/v4,v5在易用性上是一个飞跃。其官方PyTorch实现提供了极其清晰的代码结构和丰富的预训练模型(从nano到xlarge),让我们可以轻松地在“轻量”和“精度”之间做权衡。
- 核心优势:
- 开箱即用的训练管道:
data.yaml定义数据集,model.yaml定义网络结构,一行命令python train.py即可开始训练。这对于快速迭代车牌、车辆等自定义数据集的模型至关重要。 - 灵活的模型尺寸:YOLOv5s(小)模型在COCO数据集上也能达到不错的mAP,而模型文件仅十几MB,非常适合在算力有限的设备(如Jetson Nano、RK3568等边缘计算盒子)上部署,满足交通场景的实时性要求(通常需要>25 FPS)。
- 丰富的增强与优化:Mosaic数据增强、自适应锚框计算、自动混合精度训练等技巧都被集成在内,减少了我们大量手动调参的工作。
- 开箱即用的训练管道:
注意:虽然YOLOv8现在更流行,且在某些指标上更优,但YOLOv5的生态依然庞大,社区资源(如针对特定硬件的优化教程、转换工具)非常丰富。对于很多已部署的项目,升级模型并非第一要务,稳定和可维护性更重要。本系统的设计是模块化的,理论上将
models/yolov5s.pt替换为YOLOv8的模型文件,并调整少量前后处理代码,即可完成升级。
2.2 车牌识别:LPRNet的精妙之处
车牌识别(License Plate Recognition, LPR)是本系统的关键一环。我们选择了LPRNet这类基于轻量级CNN+RNN+CTC(连接时序分类)的端到端识别方法,而不是传统的“字符分割+字符识别”两步走方案。
- 传统方法的痛点:受光照、倾斜、污损影响大,分割步骤容易失败,导致连锁错误。
- LPRNet的优势:
- 端到端训练:输入整张车牌图片,直接输出车牌字符串。模型自己学习如何对齐特征和序列,避免了脆弱的分割步骤。
- 轻量高效:网络结构小巧,推理速度快,非常适合在检测到车牌后实时进行识别。
- 抗干扰强:对车牌的轻微倾斜、光照变化有一定鲁棒性。
在源码中,LPR3可能指代一个包含LPRNet原理的、经过优化的第三版实现,通常会包含针对中文车牌(蓝牌、黄牌、绿牌等)字符集(0-9A-Z省简称)专门训练好的模型。
2.3 多目标跟踪:DeepSORT的稳定追踪
仅仅检测出每一帧中的车辆是不够的。我们需要知道“这辆车”在整个视频序列中的运动轨迹,这是进行车速估算、行为分析(如违章停车)的基础。这就是DeepSORT的用武之地。
DeepSORT在经典SORT算法的基础上,引入了深度学习的外观特征(Appearance Feature)提取器。其工作流程可以概括为:
- 检测:YOLOv5提供当前帧所有车辆的检测框。
- 预测:利用卡尔曼滤波(Kalman Filter)根据上一帧的轨迹,预测当前帧中这些轨迹的位置。
- 关联:这是核心。计算运动关联度(预测框与检测框的IoU)和外观关联度(检测框内车辆深度特征之间的余弦距离)。两者加权结合,通过匈牙利算法进行最优匹配。
- 更新:匹配成功的,用新检测框更新轨迹;未匹配的检测框,可能初始化为新轨迹;未匹配的轨迹,会被暂存,若干帧后删除。
通过DeepSORT,系统能为每一辆车辆分配一个唯一的、持续的ID,从而稳定地追踪其位置,为后续计算位移(用于测速)打下基础。
2.4 图形界面:PyQt5的工业级选择
为什么不用Tkinter或Web前端?PyQt5提供了近乎工业级桌面应用开发的能力。
- 功能强大:丰富的控件库(表格、树形图、图形视图等),能够轻松构建复杂的交互界面,例如显示多路视频、绘制跟踪框和轨迹、展示结构化数据表格。
- 界面美观:通过QSS(Qt样式表)可以做出非常现代化的界面,提升软件质感。
- 多线程支持:这是关键!视频处理是计算密集型任务,必须放在子线程中,否则界面会卡死。PyQt5的
QThread、信号(Signal)与槽(Slot)机制,能优雅地解决界面响应与后台运算的冲突。 - 打包部署方便:使用
PyInstaller或Nuitka可以轻松将Python脚本打包成独立的可执行文件(.exe),方便在没有Python环境的Windows电脑上运行。
3. 系统架构与模块协同工作流
理解了各个组件后,我们来看它们是如何协同工作的。整个系统的数据流是线性的,但通过多线程实现了并行化处理。
3.1 核心处理流水线
- 视频流获取线程:主线程或一个专用线程负责从摄像头、RTSP流或视频文件中读取帧。
- 目标检测线程:读取到的帧被送入YOLOv5模型。模型输出本帧中所有检测到的目标(车辆、行人)的边界框、置信度和类别。这里通常会对检测结果进行初步过滤,例如只保留置信度大于0.5的车辆框。
- 多目标跟踪线程:过滤后的检测框被送入DeepSORT跟踪器。跟踪器完成预测、关联、更新步骤,为每个检测框分配或更新一个Track ID。输出是带有ID的跟踪框。
- 车牌识别子流程:对于类别为“车辆”的跟踪框,系统会从原始帧中裁剪出对应的区域(ROI)。这个ROI被送入一个专门的车牌检测模型(可以是另一个更精细的YOLO,或直接使用原检测框的上半部分)。检测到车牌后,再裁剪出车牌区域,送入LPRNet模型进行字符识别。
- 车速估算模块:系统维护一个字典,以Track ID为键,存储该车辆的历史位置(通常是边界框底边中心点)和时间戳。当同一ID的车辆在连续帧中出现时,根据其像素位移和已知的相机参数(或一个预设的像素-距离比例尺),结合帧间时间差,估算出瞬时速度。更复杂的实现会考虑透视变换,将图像坐标映射到真实世界坐标。
- GUI渲染线程:所有结果(绘制了跟踪框、ID、车牌号、速度的帧)被发送到主GUI线程。PyQt5的
QLabel或QGraphicsView控件负责显示图像。同时,识别结果(时间、ID、车牌号、速度、类别)被插入到QTableWidget或数据库中,供查询和导出。
3.2 多线程通信的关键
这里面的技术难点在于线程间的数据同步和通信。通常采用“生产者-消费者”模式:
- 视频获取线程是生产者,将帧放入一个队列(
queue.Queue)。 - 处理线程(检测、跟踪)作为消费者,从队列取帧处理,然后将结果放入另一个结果队列。
- GUI主线程定时从结果队列中取数据更新界面。所有对PyQt5控件的操作(如更新图片、插入表格行)必须在主线程中执行,通过
pyqtSignal将结果从工作线程传递到主线程来安全调用。
4. 环境搭建与源码运行实操指南
拿到源码压缩包后,第一步就是搭建环境。这里会涉及Python环境、PyTorch、PyQt5以及一些依赖库。
4.1 创建并激活虚拟环境(强烈推荐)
为了避免包版本冲突,第一步永远是创建独立的Python虚拟环境。
# 假设使用 conda conda create -n traffic_sys python=3.8 conda activate traffic_sys # 或者使用 venv python -m venv traffic_sys_env # Windows traffic_sys_env\Scripts\activate # Linux/Mac source traffic_sys_env/bin/activate4.2 安装核心依赖
项目根目录下通常会有一个requirements.txt文件。直接安装是最快的方式。
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple如果requirements.txt文件缺失或不完整,你需要手动安装以下核心包:
# 深度学习框架与计算机视觉库 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu # CPU版本,根据CUDA版本调整 pip install opencv-python pip install Pillow pip install numpy pip install scipy # 跟踪与工具库 pip install filterpy # DeepSORT依赖的卡尔曼滤波库 pip install scikit-learn # 用于特征距离计算等 # 图形界面 pip install PyQt5 pip install pyqt5-tools # 可选,包含Qt Designer等工具 # 其他可能需要的 pip install pandas # 用于数据导出 pip install matplotlib # 用于可能的可视化实操心得:安装PyTorch时,务必去 官网 根据你的CUDA版本(如果有GPU)选择正确的安装命令。
torch和torchvision的版本需要匹配,否则可能导入失败。对于纯CPU运行,使用上面的--index-url指向CPU版本仓库即可。
4.3 模型文件准备
源码中通常不会包含训练好的模型文件(.pt, .pth),因为文件较大。你需要自行准备:
- YOLOv5模型:从YOLOv5官方GitHub仓库下载预训练权重,如
yolov5s.pt。如果你针对交通场景(只检测车和人)进行了微调,则使用你自己训练的权重。 - LPRNet模型:需要找到针对中文车牌训练好的LPRNet权重文件(.pth)。这部分资源可能需要从开源社区或论文作者处获取。
- DeepSORT权重:DeepSORT需要的行人重识别(ReID)模型权重,用于提取外观特征。常用的是在大型行人数据集上预训练的
ckpt.t7文件。
将这些模型文件放入项目指定的文件夹,通常是./weights/或./models/,并在代码的配置部分(如config.py或GUI的设置界面)指定正确的路径。
4.4 运行主程序
环境与模型就绪后,运行主GUI文件。
python main.py或者
python gui_main.py如果一切正常,PyQt5窗口将会弹出。接下来你就可以通过菜单或按钮:
- 加载视频文件或连接摄像头。
- 点击“开始”按钮,系统便会运行。
5. 关键代码模块剖析与定制化
让我们深入几个核心模块,看看如何根据需求进行定制。
5.1 YOLOv5检测器的集成
系统不会直接调用YOLOv5庞大的训练/验证脚本,而是集成其检测部分。通常,会有一个detector.py文件,其中核心类是YOLOv5Detector。
import torch import cv2 from models.experimental import attempt_load from utils.general import non_max_suppression, scale_coords class YOLOv5Detector: def __init__(self, weights_path, device='cpu', img_size=640): self.device = torch.device(device) self.model = attempt_load(weights_path, map_location=self.device) self.model.eval() # 设置为评估模式 self.img_size = img_size self.names = self.model.module.names if hasattr(self.model, 'module') else self.model.names def detect(self, img): # 1. 图像预处理:调整大小、归一化、转换通道顺序 (HWC to BCHW) img0 = img.copy() img = self.preprocess(img) img = torch.from_numpy(img).to(self.device) img = img.float() / 255.0 if img.ndimension() == 3: img = img.unsqueeze(0) # 2. 推理 with torch.no_grad(): pred = self.model(img)[0] # 3. 后处理:非极大值抑制 (NMS) pred = non_max_suppression(pred, conf_thres=0.25, iou_thres=0.45) detections = [] for det in pred: if det is not None and len(det): det[:, :4] = scale_coords(img.shape[2:], det[:, :4], img0.shape).round() for *xyxy, conf, cls in det: # 转换为 [x1, y1, x2, y2, conf, class_id] detections.append([int(xyxy[0]), int(xyxy[1]), int(xyxy[2]), int(xyxy[3]), conf.item(), int(cls)]) return detections def preprocess(self, img): # 实现resize和padding,保持长宽比 # ...定制点:
- 置信度与IOU阈值:
conf_thres和iou_thres直接影响检测的灵敏度和误报率。在交通场景中,可以适当提高conf_thres(如0.5)以减少远处模糊车辆的误报。 - 只检测特定类别:YOLOv5的COCO预训练模型有80类。在
detect方法后,可以过滤cls,只保留2(car),5(bus),7(truck),3(motorcycle)等车辆类,以及0(person)。 - 更换模型:只需修改
weights_path,指向yolov5m.pt或yolov5l.pt以获得更高精度(牺牲速度)。
5.2 DeepSORT跟踪器的封装
DeepSORT的集成通常在一个tracker.py文件中。
from deep_sort import DeepSort import numpy as np class Tracker: def __init__(self, deepsort_weights_path): # 初始化DeepSORT,配置参数 self.deepsort = DeepSort( model_path=deepsort_weights_path, max_dist=0.2, # 外观特征匹配的最大距离阈值 min_confidence=0.3, # 检测结果的最低置信度(供跟踪器使用) nms_max_overlap=1.0, max_iou_distance=0.7, # IoU匹配的最大距离 max_age=70, # 轨迹最大存活帧数(未匹配) n_init=3, # 需要连续匹配多少次才确认一条新轨迹 nn_budget=100, use_cuda=False ) def update(self, detections, frame): """ detections: list of [x1, y1, x2, y2, conf, cls] frame: 当前帧图像 (用于提取外观特征) return: list of [x1, y1, x2, y2, track_id] """ if len(detections) == 0: return self.deepsort.update([], [], frame) # 转换为DeepSORT需要的格式: [x, y, w, h, conf] bbox_xywh = [] confs = [] for det in detections: x1, y1, x2, y2, conf, cls = det w, h = x2 - x1, y2 - y1 bbox_xywh.append([x1 + w/2, y1 + h/2, w, h]) confs.append(conf) bbox_xywh = np.array(bbox_xywh) confs = np.array(confs) # 调用DeepSORT更新 outputs = self.deepsort.update(bbox_xywh, confs, frame) tracked_objects = [] for output in outputs: x1, y1, x2, y2, track_id = output tracked_objects.append([int(x1), int(y1), int(x2), int(y2), int(track_id)]) return tracked_objects定制点:
max_age和n_init:这是调优跟踪稳定性的关键。max_age设得大,轨迹不容易消失,但在目标被长期遮挡后重新出现时,可能会被误认为新目标。n_init设得大,新轨迹需要更多确认才被创建,能减少短暂误检产生的“闪烁”ID。在交通场景,车辆运动连续,可以适当增大max_age(如100),n_init保持3或5。max_dist和max_iou_distance:控制关联的严格程度。如果场景中车辆密集、相互遮挡严重,可以适当放宽max_iou_distance,但需警惕ID切换(ID Switch)。
5.3 车牌识别与车速估算的实现
车牌识别:在获得车辆跟踪框后,会调用一个LPR类。其recognize方法大致流程是:1) 在车辆ROI内再次检测车牌位置(或用启发式规则,如取ROI上半部分);2) 对车牌区域进行预处理(灰度化、二值化、尺寸归一化);3) 送入LPRNet模型,通过CTC解码得到字符串。
车速估算:这是一个简化但实用的方法。
class SpeedEstimator: def __init__(self, fps, pixels_per_meter): self.fps = fps # 视频帧率 self.ppm = pixels_per_meter # 像素/米比例尺,需要标定 self.track_history = {} # {track_id: [(x, y, frame_idx), ...]} def update(self, track_id, centroid): # centroid: (x, y) 车辆底部中心点 if track_id not in self.track_history: self.track_history[track_id] = [] self.track_history[track_id].append((*centroid, time.time())) # 使用时间戳更精确 # 保持最近N个点用于计算速度 if len(self.track_history[track_id]) > 10: self.track_history[track_id].pop(0) def estimate(self, track_id): history = self.track_history.get(track_id, []) if len(history) < 2: return 0.0 # 计算最近两个点之间的位移和时间差 (x1, y1, t1), (x2, y2, t2) = history[-2], history[-1] pixel_distance = ((x2 - x1)**2 + (y2 - y1)**2) ** 0.5 time_interval = t2 - t1 if time_interval <= 0: return 0.0 # 计算速度 (米/秒),并转换为公里/小时 speed_mps = (pixel_distance / self.ppm) / time_interval speed_kph = speed_mps * 3.6 return speed_kph关键点:
- 比例尺标定 (
ppm):这是测速准确性的基础。需要在视频画面中找到一个已知实际长度的参照物(如车道宽度3.75米),测量其在图像中的像素长度,计算得出pixels_per_meter。更准确的方法是进行相机标定,获取透视变换矩阵。 - 参考点选择:使用边界框底边中心点比使用框中心点更稳定,因为它更贴近地面,受车辆姿态(如刹车抬头)影响小。
- 滤波:估算出的瞬时速度可能抖动很大。可以对一个轨迹的连续多个速度值进行滑动平均滤波,得到更平滑的速度曲线。
5.4 PyQt5 GUI的构建与多线程
主窗口类MainWindow继承自QMainWindow。核心是启动一个工作线程WorkerThread来处理视频。
from PyQt5.QtCore import QThread, pyqtSignal, Qt from PyQt5.QtGui import QImage, QPixmap class WorkerThread(QThread): # 定义信号,用于将处理结果传回主线程 frame_processed = pyqtSignal(QImage, list) # 图像和结果数据 info_ready = pyqtSignal(str) # 状态信息 def __init__(self, video_source): super().__init__() self.video_source = video_source self.is_running = True # 初始化检测器、跟踪器、识别器等 self.detector = YOLOv5Detector(...) self.tracker = Tracker(...) self.lpr = LPR(...) self.speed_estimator = SpeedEstimator(...) def run(self): cap = cv2.VideoCapture(self.video_source) while self.is_running: ret, frame = cap.read() if not ret: break # 1. 检测 detections = self.detector.detect(frame) # 2. 跟踪 tracks = self.tracker.update(detections, frame) results = [] for track in tracks: x1, y1, x2, y2, tid = track # 3. 车牌识别 (针对车辆) license_plate = self.lpr.recognize(frame[y1:y2, x1:x2]) # 4. 车速估算 centroid = ((x1+x2)//2, y2) self.speed_estimator.update(tid, centroid) speed = self.speed_estimator.estimate(tid) # 5. 绘制 cv2.rectangle(frame, (x1, y1), (x2, y2), (0,255,0), 2) label = f"ID:{tid} {license_plate} {speed:.1f}km/h" cv2.putText(frame, label, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0,255,0), 2) results.append([tid, license_plate, speed]) # 转换图像格式供Qt显示 rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb_image.shape qt_image = QImage(rgb_image.data, w, h, ch * w, QImage.Format_RGB888) # 发射信号 self.frame_processed.emit(qt_image, results) cap.release() def stop(self): self.is_running = False在主窗口中,连接信号到槽函数来更新UI:
class MainWindow(QMainWindow): def __init__(self): # ... 初始化UI ... self.worker = WorkerThread(0) # 0 代表默认摄像头 self.worker.frame_processed.connect(self.update_frame) self.worker.info_ready.connect(self.status_bar.showMessage) def start_processing(self): self.worker.start() def update_frame(self, qt_image, results): pixmap = QPixmap.fromImage(qt_image) self.video_label.setPixmap(pixmap.scaled(self.video_label.size(), Qt.KeepAspectRatio)) # 更新结果表格 self.update_table(results)6. 常见问题与实战调试技巧
在实际运行和二次开发中,你肯定会遇到各种问题。这里记录了一些典型的坑和解决方法。
6.1 环境与依赖问题
问题:
ImportError: cannot import name 'xxx' from 'models.experimental'- 原因:YOLOv5的代码结构可能已更新,或者你的YOLOv5子模块没有正确克隆/放置。
- 解决:确保项目根目录下有完整的
models/、utils/文件夹,它们来自YOLOv5官方仓库。最稳妥的方式是,将你的业务代码放在YOLOv5官方代码的根目录下运行,或者将必要的模块(models/common.py,models/experimental.py,utils/general.py等)复制到你的项目目录中并调整导入路径。
问题:PyQt5相关错误,如无法找到
QThread或界面崩溃- 原因:PyQt5安装不完整,或者在非主线程操作了UI组件。
- 解决:确保安装
PyQt5和pyqt5-tools。黄金法则:所有与UI相关的操作(如更新QLabel的图片、向QTableWidget插入行)都必须在主线程中执行。通过pyqtSignal将数据从工作线程传递到主线程的槽函数,在槽函数里更新UI。
6.2 模型与性能问题
问题:检测/识别速度太慢,FPS很低
- 排查:
- 设备:首先确认是在CPU还是GPU上运行。检查代码中
torch.device是否设置为cuda。 - 模型:使用的是YOLOv5s还是更大的模型?尝试换成
yolov5n.pt(nano)看看速度提升。 - 输入尺寸:YOLOv5的
img_size参数默认640。增大它会提高精度但显著降低速度。对于交通监控,640通常足够。 - 推理优化:使用
torch.jit.trace或torch.jit.script将模型转换为TorchScript,或使用ONNX Runtime、TensorRT进行推理,能大幅提升速度。 - 视频分辨率:如果原始视频是1080p或更高,可以先将其缩放到一个较小的尺寸(如960x540)再进行检测,能极大提升速度,对精度影响有限。
- 设备:首先确认是在CPU还是GPU上运行。检查代码中
- 排查:
问题:车牌识别准确率低
- 排查:
- 车牌检测阶段:确保裁剪给LPRNet的是清晰、正面的车牌区域。如果YOLOv5的车辆检测框不准,可以单独训练一个专门的车牌检测模型(用YOLOv5在车牌数据集上微调),在车辆ROI内做二次检测。
- 图像预处理:LPRNet输入前,车牌区域可能需要做灰度化、二值化、尺寸归一化(如94x24)。检查预处理流程是否与模型训练时一致。
- 模型本身:确认LPRNet模型是在包含中文车牌的数据集上训练的。如果场景中有新能源车牌(绿牌)、使馆车牌等特殊样式,可能需要扩充训练数据。
- 排查:
6.3 跟踪与业务逻辑问题
问题:车辆ID频繁切换(ID Switch)
- 原因:车辆密集、相互遮挡;DeepSORT的关联参数设置不合理;检测框抖动。
- 解决:
- 调优DeepSORT的
max_iou_distance(降低)和max_dist(降低),让关联更严格。 - 增加
n_init,要求新轨迹有更多连续匹配才被确认。 - 对检测结果进行平滑滤波(如对同一目标的连续检测框做移动平均),减少抖动。
- 考虑使用更强大的ReID模型提取更具判别力的外观特征。
- 调优DeepSORT的
问题:车速估算不准
- 原因:
pixels_per_meter比例尺标定错误;参考点选择不当;透视畸变未校正;速度计算未滤波。 - 解决:
- 精确标定:在视频中选择一段平直的路面,测量已知距离(如两条车道线之间的虚线,长度6米),在图像中测量像素距离,反复测量取平均。
- 透视变换:如果摄像头是斜向下拍摄,需要进行透视变换将图像坐标映射到鸟瞰图坐标,然后再计算距离。OpenCV的
cv2.getPerspectiveTransform和cv2.warpPerspective可以实现。 - 速度滤波:不要使用瞬时速度,而是计算过去10-20帧的平均速度或中值速度。
- 原因:
6.4 打包与部署问题
- 问题:使用PyInstaller打包后,程序无法运行,提示缺少模块或文件
- 解决:创建
hook文件或修改.spec文件,确保PyInstaller能打包到非Python库文件。- 模型文件:在.spec文件的
datas列表中,将weights/文件夹添加进去。datas=[('weights/*.pt', 'weights'), ('models/*.pth', 'models'), ...] - PyQt5图标等资源:同样需要添加到
datas。 - 隐藏导入:有些模块是动态导入的,需要在.spec的
hiddenimports中添加,例如hiddenimports=['torch', 'torchvision', 'cv2', 'PyQt5.QtCore', 'PyQt5.QtGui', 'PyQt5.QtWidgets', 'sklearn.neighbors']。
- 模型文件:在.spec文件的
- 一个实用的调试方法:在打包后的程序崩溃时,查看生成的错误日志,找到缺失的模块名,将其添加到
hiddenimports中。
- 解决:创建
这个项目就像一个精密的机械钟表,每个齿轮(模块)都需要精确调校才能顺畅运转。从环境搭建、模型准备,到参数调优、问题排查,每一步都需要耐心和实践。但它带来的成就感也是巨大的——看着屏幕上实时框出的车辆、跳动的车牌号和速度,你会感觉那些复杂的算法终于变成了一个能解决实际问题的工具。希望这份详细的拆解,能帮你更好地理解、运行甚至改进这个系统。如果在实际操作中遇到新的问题,不妨回头看看各个模块的连接处,那里往往是问题的根源。
本文还有配套的精品资源,点击获取