ARTICLE DETAIL

资讯详情

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

PyQt5+CenterNet行人检测计数系统:工程结构、推理原理与避坑实践

PyQt5+CenterNet行人检测计数系统:工程结构、推理原理与避坑实践 简介面向计算机相关专业毕业设计与项目实战的行人识别检测计数系统基于深度学习与PyQt5构建提供完整可运行的源码和训练好的模型。适合正在准备毕设、课程设计或期末大作业的学生也适合想练习目标检测与界面开发的学习者。包内涵盖19个Python脚本、5个编译后的pyc文件以及预训练模型.h5、字体、配置文件、示例图片等共34个文件压缩包约683.77MB。源码基于CenterNet架构包含hourglass与resnet骨干网络、训练脚本、数据集处理工具以及PyQt5交互界面主窗口、计数窗口、实时视频检测等模块附带的说明文档和配置文件有助于快速理解和复现。项目代码结构清晰关键位置附有注释能帮助理解CenterNet的检测流程。该项目曾在毕业设计评审中获得99分经导师认可从数据准备到模型部署流程完整适合直接作为课程设计或毕业设计参考。已有110人学习下载兼具工程完整性与二次开发价值。1. 为什么 PyQt5 CenterNet 是行人检测计数毕设里最稳的组合PyQt5 和深度学习这两个词放在一起很多人第一反应是“又是把界面和模型强行缝合的毕设”。但这个行人识别检测计数系统不一样它把检测核心放在 CenterNet 上自带训练好的centernet_hourglass_coco.h5界面侧有predictUI.py做单张预测、videoDetection.py做视频检测、CountWindow.py做实时计数展示不是给你一个空壳 UI而是解压后能立刻跑通的完整 demo。对于正在做毕业设计、课程设计或期末大作业的人来说最怕的不是算法看不懂是“代码缺一半、模型没权重、环境装到崩溃”。这套资源把这三件事一次性覆盖了你需要做的只是先把 demo 跑起来再按自己的数据微调类别和界面文案。2. 拆解工程文件从数据划分脚本到五个入口程序拿到压缩包先别急着双击MainWindow.py花十分钟把目录结构摸清楚后面能少踩很多坑。这个包的工程组织方式很典型训练相关代码放在nets和centernet_training.py推理和界面控制在根目录模型权重统一放在model_data。整个包的文件数量和种类都不算多但每个文件都存在得很有目的性。2.1 目录结构训练框架在 nets 下推理逻辑在根目录先看根目录的 Python 文件按职责可以分成四组界面入口组MainWindow.py主窗口、predictUI.py单张图片预测、videoDetection.py视频检测、CountWindow.py计数窗口。数据准备组random_split.py划分数据集、get_dr_txt.py生成训练标注文件、get_gt_txt.py生成真值文件给评估用、fackData.py生成模拟数据。后端逻辑组DataServer.py数据服务循环、centernet.py推理封装、get_map.pymAP 评估。辅助工具组img_to_video.py图片拼视频、video2audio.py视频抽音频。nets目录里是网络结构定义hourglass.py、resnet.py、centernet.py和centernet_training.py加了__pycache__说明作者在开发时已经运行过这个细节很重要——一个生成过__pycache__的工程通常意味着代码在交付前是被执行过的不是网上随便拼凑的残缺代码。model_data里的核心是centernet_hourglass_coco.h5这个文件名透露了两个信息骨干网络是 Hourglass训练数据集是 COCO。配套的coco_classes.txt有 80 类voc_classes.txt有 20 类如果你只想检测行人后面处理数据时只留person这一类就够。simhei.ttf是黑体字体文件PyQt5 界面显示中文时防止乱码用的timg.jpg、street.jpg、img.jpg是给predictUI.py测试用的样例图。dayLogs/2021-12-31.txt这类的日志文件记录的是开发当日跑数据的结果输出形式上像是一个开发日志存档。提示如果你只打算跑演示真正需要关心的文件只有四个MainWindow.py、DataServer.py、model_data下的 h5 权重、nets目录。其他脚本都在为“重新训练”和“答辩演示”服务。2.2 数据链路random_split.py → get_dr_txt.py → get_gt_txt.py毕业后如果要往自己数据集上迁移这三兄弟是绕不开的。它们的协作关系是这样的random_split.py把图片和标注按比例随机分成训练集和验证集避免同一段连续帧的画面全落进训练集导致验证结果虚高。get_dr_txt.py读训练集图片路径和标注框生成检测训练用的 txt 文件每一行是一条样本。get_gt_txt.py读验证集标注生成评估用的 ground truth 文件最后交get_map.py计算 mAP。我用过的同类 CenterNet 训练管线里标注格式一般是下面这种# get_dr_txt.py 输出的格式 图片路径 x_min y_min x_max y_max 类别编号 /home/user/data/person_0001.jpg 42 116 186 342 0 /home/user/data/person_0002.jpg 12 88 150 300 0关键参数不在脚本里而在你的数据整理习惯上类别编号必须和coco_classes.txt或voc_classes.txt里的索引位置一致。比如voc_classes.txt第一行是person编号就是 0。坐标是像素坐标不需要归一化CenterNet 训练时内部会做/width、/height的转换。同一个目标如果被两个框框了txt 里会出现重复行轻则训练震荡重则 loss 变成 NaN。我在自己的项目里会用脚本对同一图片名的所有框做一次 IoU 去重这个习惯一直保留到现在。random_split.py里的划分比例如果没写作者大概率是9:1。这个比例在行人检测场景里够用如果你的数据量小于 2000 张建议改成8:2因为验证集太小get_map.py算出来的 mAP 方差会非常大看不出模型真实水平。2.3 处理脚本img_to_video.py、video2audio.py、fackData.py 扮演的角色这三个脚本属于“毕设演示数字化”工具第一眼看觉得凑数实际答辩时全用得上。img_to_video.py把一帧帧检测结果图拼成视频文件。很多人毕设答辩要求提交视频 demo但录制屏幕时画面不稳定这个脚本能让你把异步图片序列压成固定帧率的 mp4格式规整且不会丢帧。video2audio.py则是从视频里抽音频我在给演示视频配字幕时经常用到它——先把原视频音轨抽出来再用剪辑软件对轨比直接往里塞音乐文件省事得多。fackData.py配合根目录的fack.csv使用作用是根据 CSV 里的模拟轨迹数据生成检测结果用来在没有摄像头和测试视频的情况下联调 UI。这个思路值得学先把输入替身准备好再调界面逻辑而不是每次调试都依赖真实传感器数据。如果你要演示“人流量计数”功能现场没人入镜会很尴尬fackData.py就是那个后悔药。3. CenterNet 的检测与计数闭环热图、backbone 与推理参数这个包的检测核心选的是 CenterNet不是 Faster R-CNN 也不是 YOLO。从毕设角度讲这个选择很聪明CenterNet 的模型结构更简单没有 anchor 匹配的复杂逻辑代码量少能讲的原理却不少无论是写论文还是做 PPT素材都够。3.1 为什么不选 YOLOanchor-free 关键点检测与行人重叠边界行人检测里最常见的场景是三个人叠在一起走、一个人被另一个人挡了一半。YOLO 系模型在 anchor 正负样本分配上对这种密集遮挡很不友好同一个格子可能对应多个目标anchor 和 ground truth 做 IoU 匹配时来回拉扯。CenterNet 把这个问题换了个角度处理——不预测框而是预测目标中心点的高斯热图。每个目标在热图上是一个峰值点网络只要找到这个峰就能定位目标再用回归分支预测宽高和偏移量。这个包里的模型输出就是一个batch × 128 × 128 × num_classes的热图输入 512×512 时下采样 4 倍外加batch × 128 × 128 × 2的目标宽高回归和batch × 128 × 128 × 2的中心点偏移修正。推理时从热图上取局部峰值再做一次简单的阈值过滤就把检测结果全部捞出来了。相比 YOLO 的“先框后分类”CenterNet 天然省去了一部分 NMS 的麻烦密集行人场景漏检率更低。注意说“省去 NMS”不等于完全不做后处理。输出检测框之间仍可能因为热图上的两个相邻峰值产生小重叠centernet.py里通常会保留一个轻量去重步骤算是一个简化版的 NMS。3.2 hourglass 与 resnet 两种骨干的选择nets下同时存在hourglass.py和resnet.py对应的权重文件是centernet_hourglass_coco.h5。这告诉我们这个包至少支持两种骨干网络切换训练好的版本选的是 Hourglass。Hourglass 的结构特点是“先下采样再上采样”中间用 skip connection 把不同尺度的特征拼起来。它对姿态估计这个任务几乎是标配因为人体关键点识别需要同时看全局哪个人和局部哪个部位。用在行人检测上表现在小目标不敏感但关键点定位特别准。代价是推理速度慢CPU 上跑 512×512 输入一帧通常要 300ms 以上。ResNet 骨干的优势是快和稳。如果你的毕设侧重点在“实时性”而不是“精度”可以在centernet.py里把骨干切到 resnet然后用同一个训练流程重新训练一版权重。两者的数据流接口是保持一致的训练代码里改一个参数就行。3.3 centernet_training.py 的训练入口与 h5 权重关系这个包没有把完整训练流程做成一个一键脚本训练逻辑集中在centernet_training.py里。我从这个文件的名字和配套的数据准备脚本推测它的训练流程大概是# 1. 先把数据和标注准备好 python random_split.py python get_dr_txt.py # 2. 开始训练训练入口示例具体参数以文件内为准 python centernet_training.py --classes voc_classes.txt --backbone hourglass训练过程里最影响结果的是四个超参数参数常见取值说明输入尺寸384×384 / 512×512越大对小目标越友好但显存占用成倍上涨batch size8 / 16取决于显存小于 8 时建议调低学习率初始学习率1e-4 左右迁移 COCO 权重可以用 1e-4从头训练要更低关键点置信度0.3 ~ 0.4预测时过滤低置信度峰值真正训练过你就会发现centernet_training.py里训练循环写得并不复杂前向计算、loss 反传、定期保存 h5。困难的反而是数据处理那一步图片要按长边等比缩放补边到输入尺寸标注框坐标要做同样的变换热图要以每个目标中心点为圆心按高斯核函数生成峰值区域。这个预处理在centernet_training.py里大概率是封装好的如果你要换自己的行人数据集改动重点就在get_dr_txt.py生成的标注格式是否正确而不是训练代码本身。3.4 推理解码conf_threshold 与 max_objects 的参数语义在你确定训练能跑通之前直接使用训练好的 h5 进行推理更现实。推理入口在predictUI.py或videoDetection.py里加载模型、预处理图片、网络前向、解码四个步骤。解码阶段是调参重灾区我在自己的工程里会把它拆出来单独验证可维护性高很多import numpy as np # 假设 model 已加载, image 是 1×512×512×3 的输入 outputs model.predict(image) heatmap, wh, offset outputs[0], outputs[1], outputs[2] h, w heatmap.shape[1], heatmap.shape[2] # 128×128 stride 512 // h # 4 conf_threshold 0.3 # 太低会出大量假框, 太高漏检; 0.3 是常见默认值 max_objects 100 # 单帧最多保留目标数, 拥挤场景可调到 200 ys, xs np.where(heatmap[0, :, :, 0] conf_threshold) for y, x in zip(ys, xs): # 中心点坐标要乘 stride 再减去偏移, 得到原图坐标 cx (x offset[0, y, x, 0]) * stride cy (y offset[0, y, x, 1]) * stride # 宽高来自 wh 分支, 注意 CenterNet 的宽高是全局语义的 bw, bh wh[0, y, x, 0], wh[0, y, x, 1] x1, y1 cx - bw / 2, cy - bh / 2 # 这里再按置信度排序, 截断到 max_objects 个参数语义要理解透conf_threshold控制的是热图峰值的置信度不是分类概率所以它的取值和 YOLO 的conf_thres没有直接可比性。中心点的偏移和宽高是网络回归出来的如果你的数据集里行人有大量裁切人走在画面边缘网络对宽高的回归会偏保守实际表现就是边缘行人框比实际小一圈——这是 CenterNet 这个结构在行人检测上的固有短板调conf_threshold救不回来。我在改这些参数时有个习惯先用predictUI.py跑通单张图把conf_threshold从 0.5 往下降每降一档就看一次的漏检和误检数量找到一个既不出现“框住空气”也不丢人的平衡点。最终停在 0.3 还是 0.25取决于你要展示的画面里行人密度有多高。4. 避坑记录环境、中文路径与 OpenCV/PyQt5 混装的五个坎这个包总体来说交付完整度很高但不代表解压后就能一键跑通。以下五个问题是我在实际复现同类工程时反复遇到的按“现象→原因→解决”写清楚你提前避开能省大半天时间。4.1 cv2 DLL load failedopencv-python 全家桶混装的连锁反应现象第一次运行python MainWindow.pyimport cv2 时直接报DLL load failed: 找不到指定的模块或者导入成功但cv2.VideoCapture(0)打开摄像头返回空帧、程序闪退。原因最常见的是环境里同时存在opencv-python和opencv-contrib-python两个包都在写cv2命名空间Python 加载时撞了 DLL。另一个常见诱因是 PyQt5 依赖的pyqt5-sip版本和PyQt5不匹配在不干净的环境里容易引发连锁错误。解决# 把 opencv 卸载干净, 只保留一个 pip uninstall -y opencv-python opencv-contrib-python opencv-python-headless pip install opencv-python4.5.3.56 # 顺手固定 PyQt5 相关版本, 避免后续升级踩雷 pip install PyQt55.15.4 pyqt5-sip12.8.1我踩过最狠的一次是 conda 环境里conda install opencv和 pip 的版本混合在一起卸载都卸不干净最后把整个环境删掉重建才算完。所以现在每拿到一个新工程我都会先运行pip list | findstr opencv看是否有多个 opencv 共存。4.2 cv2.imread 读中文路径返回 None用 imdecode 兜底现象predictUI.py选择一张位于C:\Users\王同学\Desktop\毕业设计\测试图片.jpg的图片时模型加载正常但检测界面一直没有框输出控制台显示“无法读取图片”。把图片复制到纯英文路径后一切正常。原因cv2.imread底层走的是 C 的文件读取接口对系统中文编码支持很差路径里一旦出现中文就返回None。国内学生的 Windows 用户名大多是中文拼音或汉字压缩包默认放桌面几乎必踩这个坑。解决不改变代码结构的情况下把读取图片的公共函数替换成下面的写法import cv2 import numpy as np def imread_unicode(path: str): 替代 cv2.imread, 支持中文路径 data np.fromfile(path, dtypenp.uint8) return cv2.imdecode(data, cv2.IMREAD_COLOR)这个方法把图片当字节流读进来再用imdecode解码完全绕过了路径编码问题。我建议直接把predictUI.py和videoDetection.py里所有cv2.imread替换成这个函数一劳永逸。如果不想改代码至少把整个工程路径改成纯英文再运行。4.3 TensorFlow/Keras 版本对不上h5 模型加载直接翻车现象load_model(model_data/centernet_hourglass_coco.h5)时报错信息里包含AttributeError: str object has no attribute decode或者/Logits相关函数名不存在。有的还会在预测阶段报tf.function相关的图执行错误。原因h5 权重文件是用特定版本的 Keras/TensorFlow 保存的不同版本的 Keras 保存格式存在细微差别高层 API 的兼容性并不稳定。这里最典型的原因是本地安装的 Keras 是独立包与tensorflow内置的tf.keras版本冲突。解决按这套组合安装并固定版本pip install tensorflow2.5.0 keras2.4.3安装完确认一下确实是这个组合再运行python -c import tensorflow as tf; print(tf.__version__)另外如果包里的加载代码用的是keras.models.load_model而你环境里只有tf.keras也会出现找不到模型结构定义的问题。我一般会在自己的工程里统一成tf.keras.models.load_model再在nets/centernet.py里注册对应的自定义层这样加载 h5 的成功率最高。4.4 GPU 显存爆掉与 CPU 卡顿抽帧策略和输入尺度现象显卡只有 4GB 显存训练时batch_size16一跑就直接 OOM或者没有 N 卡用 CPU 跑videoDetection.py视频画面一卡一卡的像幻灯片。原因CenterNet 训练时输入 512×512千兆级显存都不够造何况是学生机的 4GB 卡。而 CPU 推理本身慢如果再逐帧处理 1080p 视频每一帧都全分辨率过模型CPU 根本扛不住。解决训练阶段把batch_size降到 4输入尺寸改到 384×384OOM 基本就消失了。对推理阶段我通常加一个“隔帧推理 显示同步”的开关# 在 videoDetection.py 的循环中, 每隔 N 帧做一次检测 frame_count 0 process_every_n_frames 2 # 每 2 帧检测一次, 显示帧不中断 while True: ok, frame cap.read() if not ok: break frame_count 1 if frame_count % process_every_n_frames 0: dets detector.predict(frame) # 无论是否执行推理, 当前帧都继续显示 draw_and_show(frame, dets)检测是耗时的但如果检测线程和显示线程分开显示帧率会高很多。这个策略在 CPU 机器上立竿见影你可以先从process_every_n_frames 3开始试如果画面撕裂感太强就降到 2。4.5 换上自己的行人数据集后 mAP 上不去现象用公开的行人数据集训练了几十个 epoch验证集 mAP 只有 30% 左右远低于压缩包自带权重在 COCO 上的表现。原因这个问题九成不在代码而在数据准备。最常见的几个坑类别文件里没清理保留了 COCO 的 80 类训练时把行人以外的目标也当正样本标注框边界不贴合框大于实际身体范围导致中心点偏移和宽高回归学习到的分布混乱数据集太小且场景单一模型泛化能力差。解决改voc_classes.txt或新建一个person_classes.txt只保留一行person然后重新跑get_dr_txt.py。对比模型输出的热图峰值和标注的中心点位置用可视化脚本把热图叠在图片上看一眼能直接发现问题。通常训练效果差的样本热图上要么没有峰值要么峰值位置和行人的真实中心相差很大。数据是自己标的这里没有捷径只能回头把标注框调准或者多补一些不同光线、不同姿态的样本。我自己的血泪经验是**行人检测的训练好坏90%以上由数据质量决定调参只占一小半。**先别折腾学习率和正则项把标注质量拉满再说。5. UI 渲染与实时计数DataServer 循环、CountWindow 曲线与线程边界检测模型只是引擎这套毕设能拿 99 分靠的是 PyQt5 界面把检测结果实时呈现给导师看。这一章重点讲界面层怎么组织、帧同步怎么做、实时计数曲线怎么画得顺滑。5.1 MainWindow.py 与 predictUI.py / videoDetection.py 的职责边界MainWindow.py是主入口负责搭建整体框架顶部工具栏、中间显示区、底部状态栏。它不直接写检测逻辑而是把任务分派给predictUI.py单张图片预测、videoDetection.py视频流检测、CountWindow.py人群计数弹窗。这种“主窗口 功能子窗口”的架构在毕设里很讨喜因为代码结构清晰答辩时能一条线讲下来主界面 → 选择功能 → 调用对应脚本 → 显示结果。DataServer.py在这里扮演数据服务角色负责在后台做视频帧的读取、检测结果的缓存和分发。你在MainWindow.py里点“开始检测”实际是在通知DataServer启动一个循环而不是在主窗口里写死 while 循环。我拿到这个包后第一件事就是看DataServer.py里的循环是否独立线程运行这一眼就能判断作者有没有处理界面卡顿问题。5.2 视频循环里最容易被忽视的“帧同步”问题新手写视频检测最喜欢在while True里先cap.read()再detector.predict(frame)最后setPixmap显示然后发现界面点关闭按钮没反应窗口直接变成“未响应”。原因很简单time.sleep()和模型推理占用了 Qt 的事件循环消息队列转不动。我一般会把耗时推理放进 QThread 里让 UI 线程只负责显示。下面是DataServer.py里可以复用的线程骨架from PyQt5.QtCore import QThread, pyqtSignal class VideoThread(QThread): frame_signal pyqtSignal(object) # 把帧和检测结果一起发给 UI def __init__(self, detector, process_every_n_frames2): super().__init__() self.detector detector self.process_every_n_frames process_every_n_frames self.running True def run(self): frame_count 0 while self.running: ok, frame cap.read() if not ok: break frame_count 1 if frame_count % self.process_every_n_frames 0: dets self.detector.predict(frame) self.frame_signal.emit((frame, dets)) self.msleep(20) # 不要用 time.sleep, 这里 msleep 不会阻塞 Qt 事件循环 def stop(self): self.running False self.wait()逻辑说明frame_signal是 Qt 的信号跨线程传递帧和检测结果主线程槽函数里只做 QImage 转换和setPixmap不做任何模型操作。self.msleep(20)控制帧率上限约 50fpsCPU 机器上如果实际达不到它只是一个让步操作真正的帧率瓶颈在predict的耗时。提示process_every_n_frames这个参数我建议不要做成固定值可以放到 UI 的 spinbox 上让用户自己调。演示时导师可能会说“你调快一点看看”有这个控件就不用回代码改数字了。5.3 CountWindow 实时计数曲线的刷新策略CountWindow.py大概率是在检测框输出的同时统计当前画面里的行人数。实时计数不能只看数字最好配一个滑动曲线图直观展示人数随时间变化。这里最容易踩的坑是每来一帧就把整条曲线重画一遍点多了界面越来越卡。更好的做法是用一个固定长度的队列每次只在末尾追加一个点并且只重绘最后一段from collections import deque history deque(maxlen60) # 只保留最近 60 帧的计数结果 def update_count(current_count): history.append(current_count) x len(history) - 1 y current_count # 只画新点不需要清空整个 graph 重新绘制 draw_line_segment(x - 1, history[-2], x, y)这样做的效果是曲线始终显示最近 1 秒左右的数据而且绘制负载恒定不会因为跑久了越画越慢。如果你想要更平滑的视觉效果对history里的值做一个简单移动平均即可把上一帧和当前帧的计数各取 50% 权重。5.4 用 fackData.py 脱离摄像头联调 UI 交互摄像头不是每次演示都靠谱尤其答辩现场环境复杂USB 摄像头驱动可能翻车。fackData.py和fack.csv在这里就是保底方案从 CSV 里读预置的行人轨迹和数量变化模拟出一段人流进入、停留、离开的过程。我调 UI 时通常先把DataServer的数据源切换成 fack界面逻辑调通后再换回摄像头。这样做的好处是每一次运行的结果完全相同不会因为有人从摄像头前走过导致界面表现时好时坏。项目里单独放一个fack.csv文件说明作者也是这么想的——这不是偷懒是把 UI 调试和检测调试解耦的正确方式。6. 开箱验证用训练好的 h5 空跑 demo再改三处让视频渲染更顺滑这一章直接落地到“如何验证这套资源真的能用”以及让演示效果更专业的三个小改动。6.1 CPU 空跑先验证环境再谈效果先不要碰摄像头和视频跑predictUI.py打开timg.jpg或street.jpg。这一步能一次性验证环境变量、模型加载、推理链路是否正常。在 CPU 机器上等待 3 到 5 秒是正常的模型加载和首次推理有预热时间如果超过 10 秒还在转圈看控制台有没有报错。python predictUI.py看到画面里出现行人检测框基本可以判定这套资源在本地环境是可用的。再跑一遍python MainWindow.py确认主界面能正常弹出、切换功能不崩溃。6.2 三处渲染参数调整把翻车率降下来第一处cv2.imread全部换成imread_unicode你永远不知道演示机桌面路径里有没有中文。第二处视频检测默认开process_every_n_frames2优先保证界面流畅框可以稍晚一帧出现但画面不能卡死。第三处显示 QImage 时不要每次setPixmap强制缩放先让QLabel设为setScaledContents(True)再把原始分辨率的 QPixmap 丢进去由控件负责缩放。6.3 get_map.py 评估一遍确认检测器的“底”最后运行get_map.py让它跑一遍验证集并输出各别类的 AP 值。这一步不是必须但能让你对模型能力有量化的底答辩时导师问“你模型精度怎么样”你能直接说出 mAP 数值比“挺好用的”有说服力得多。用训练好的 COCO 权重跑行人单类mAP 会很不错整条评估流程跑通本身也验证了get_gt_txt.py生成的数据链路正确。从那以后我每次拿到这种带训练好模型的毕设包都强制先做三件事路径全部改成英文、pip freeze拍一份环境快照、用 CPU 把示例图跑通一遍再动任何 UI 逻辑。这三步看着土但能挡掉八成的环境玄学翻车。希望帮到你让它从“下载资源”变成你答辩现场的底气。本文还有配套的精品资源点击获取
返回列表