YOLOv8+PyQt5 密集人群人体检测识别计数系统设计与实现
这次我们来看一个非常典型的深度学习落地场景:在商场、景区、地铁站这类人流密集区域,如何用 YOLOv8 配合 PyQt5 搭建一套人体检测与计数系统。这类系统在智能安防、客流统计、区域拥挤预警里应用很多,难点主要集中在三块——模型能不能在小目标密集场景下保持精度、视频流能不能实时处理、以及检测结果能不能在桌面端应用里直观展示。
下面我直接把这套系统的设计思路、训练流程、PyQt5 界面实现和性能优化方案拆开写清楚。如果你正准备做毕业设计、课程项目,或者想在公司内部快速搭一个人体计数 Demo,这篇文章可以直接照着做。
1. 核心能力速览
先看这套系统的关键能力:
| 能力项 | 说明 |
|---|---|
| 检测模型 | YOLOv8,支持 nano/small/medium/large/x 多版本 |
| 界面框架 | PyQt5,支持实时视频显示、检测结果叠加、计数统计 |
| 核心功能 | 人体检测、目标计数、视频/图片/摄像头输入、检测结果导出 |
| 硬件要求 | 训练推荐 NVIDIA GPU,纯推理可 CPU,有 GPU 速度更快 |
| 显存占用 | 与模型大小、输入分辨率直接相关,需按实际配置测试 |
| 支持平台 | Windows / Linux |
| 启动方式 | Python 命令行启动 PyQt5 应用 |
| API 能力 | 可封装为检测接口,供其他程序调用 |
| 批量任务 | 支持批量图片检测和视频逐帧检测 |
| 适合场景 | 客流统计、拥挤预警、安防监控、毕设/课设项目 |
YOLOv8 是 Ultralytics 团队在 2023 年初发布的目标检测框架,相比 YOLOv5 最大的变化是采用了 Anchor-Free 检测头,并且把分类、检测、分割、姿态估计统一到了一个框架里。配合 PyQt5 做桌面界面,不需要浏览器,直接打包成 exe 就能在 Windows 上跑,这对安防领域的实际部署来说非常方便。
2. 适用场景与使用边界
这套系统能解决的问题,总结下来是三类:
- 静态图片中的人体检测与计数。比如上传一张商场入口的抓拍图,系统自动标出每个人并显示总数。
- 视频文件或实时摄像头中的人体检测与计数。比如接入监控摄像头 RTSP 流,实时统计画面里的人数变化。
- 批量图片的处理。比如一次性处理一整天抓拍的几百张图片,输出每张图片的人数和检测结果图。
适合的人群也很明确。做毕设和课设的学生、需要快速验证目标检测方案的开发者、以及安防或零售行业想做客流统计的技术人员都可以直接用这套方案。
使用边界同样需要说清楚。这类系统基于视觉模型,对遮挡严重的密集场景检测精度会下降;光线暗、雨天、低分辨率摄像头都会影响效果。另外,在公共区域部署时,务必获得监控设备和数据使用的合法授权,不能私自采集人脸或行人的可识别信息用于其他用途,涉及隐私数据要脱敏处理。模型本身只输出人体位置和数量,不识别身份,但采集端合规问题仍然需要自己把关。
3. 环境准备与前置条件
先确认环境。这套系统核心依赖是 PyTorch、Ultralytics YOLOv8、OpenCV 和 PyQt5。
硬件方面,训练推荐至少一块 NVIDIA GPU,最好是 6GB 以上显存。纯推理的话,CPU 也能跑,但视频流实时性和高分辨率图片的处理速度会差很多。如果你手里只有 GTX 1660 Ti、RTX 3060、RTX 4060 这类显卡,只要显存超过 6GB,跑 YOLOv8s 或 YOLOv8m 没有问题。
软件环境建议如下(我这里列的是推荐配置,实际以你本机为基础):
- 操作系统:Windows 10/11 或 Ubuntu 20.04/22.04
- Python:3.8 到 3.11 均可,推荐 3.10
- CUDA:11.8 或 12.1,需匹配 PyTorch 版本
- 主要依赖:ultralytics、torch、torchvision、opencv-python、PyQt5、numpy
安装 PyTorch 前先确认显卡驱动和 CUDA 版本。推荐直接用 pip 安装,命令如下:
# 先安装 PyTorch,CUDA 12.1 版本示例 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 # 再安装其余依赖 pip install ultralytics opencv-python PyQt5 numpy如果在国内网络环境安装较慢,可以换用清华镜像源:
pip install torch torchvision torchaudio -i https://pypi.tuna.tsinghua.edu.cn/simple pip install ultralytics opencv-python PyQt5 numpy -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后,用下面这段代码验证环境是否正常:
import torch import ultralytics import cv2 import PyQt5 print("PyTorch:", torch.__version__) print("CUDA available:", torch.cuda.is_available()) print("Ultralytics:", ultralytics.__version__) print("OpenCV:", cv2.__version__) print("PyQt5:", PyQt5.QtCore.PYQT_VERSION_STR)如果torch.cuda.is_available()返回 False,说明 PyTorch 的 CUDA 版本和驱动不匹配,需要重新安装对应版本的 PyTorch。CPU 环境也能继续做推理测试,只是速度会慢。
4. 数据处理与模型训练
这套系统的核心之一,是训练一个人体检测模型。如果你不想自己训练,可以直接用 YOLOv8 自带的预训练权重yolov8n.pt和yolov8s.pt,模型里本身就包含 person 这个类别。但你如果想要针对自己场景做更高精度的检测,用自己的数据集微调是必须的。
4.1 数据集准备
人体检测数据集最常见的公开选项是 COCO 数据集中的 person 类别,或者 CrowdHuman 这类密集人群数据集。自己采集数据时,要注意覆盖不同角度、不同光照、不同密度场景。
数据集目录结构建议如下:
dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/标注格式采用 YOLO 格式,每个图片对应一个同名的 txt 文件,每行代表一个目标:
class_id x_center y_center width height坐标值都是归一化到 0~1 的浮点数。比如:
0 0.514648 0.479492 0.235352 0.772461标注工具可以用 LabelImg 或者 LabelStudio,导出成 YOLO 格式即可。
4.2 模型配置文件
在项目目录下创建person-detection.yaml,内容如下:
path: ./dataset train: images/train val: images/val test: images/test names: 0: person这个文件告诉 YOLOv8 数据集的路径和类别名称。
4.3 训练命令
YOLOv8 训练入口非常简单,一条命令就能启动:
yolo detect train data=person-detection.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=16 device=0参数含义:
data:数据集配置文件的路径。model:预训练权重路径,也可以用yolov8s.yaml从头训练,但用预训练权重收敛更快。epochs:训练轮数,小数据集建议 100 轮起步。imgsz:输入图像分辨率,推荐 640 或 768。密集小目标场景可以适当提升到 960,但显存占用会增大。batch:批大小,根据显存调整。8GB 显存跑 YOLOv8s 建议 batch 不超过 32。device:0表示第一张 GPU,cpu表示 CPU 训练。
训练过程中日志会打印每个 epoch 的 mAP、precision、recall 等指标。训练结束后,最优权重保存在runs/detect/train/weights/best.pt。
如果你只是想快速验证整套系统流程,先不要训练,直接用官方预训练权重测试:
yolo predict model=yolov8s.pt source=test.jpg5. PyQt5 系统设计与界面实现
现在进入系统核心部分。这套人体检测识别计数系统采用 PyQt5 作为桌面界面框架,整体结构分为三层:
| 层级 | 组件 | 职责 |
|---|---|---|
| 界面层 | PyQt5 主窗口 | 显示视频画面、按钮控制、计数结果展示 |
| 逻辑层 | 检测线程、计数逻辑 | 调用 YOLOv8 模型推理,统计人数 |
| 数据层 | 输入源管理 | 支持图片文件、视频文件、摄像头、RTSP 流 |
界面布局参考如下:
- 左侧:视频/图片显示区域。
- 右侧:检测结果信息区,包括总人数、当前帧人数、检测耗时。
- 底部:操作按钮,包括打开图片、打开视频、打开摄像头、停止检测、导出结果。
- 顶部菜单:模型选择、置信度阈值设置、IOU 阈值设置。
这里直接给出主窗口的核心代码框架:
import sys import cv2 import numpy as np from PyQt5.QtCore import QThread, pyqtSignal, Qt from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtWidgets import ( QApplication, QMainWindow, QLabel, QPushButton, QVBoxLayout, QHBoxLayout, QWidget, QFileDialog, QSpinBox, QDoubleSpinBox, QMessageBox ) from ultralytics import YOLO class DetectThread(QThread): """检测线程,避免在 UI 线程中执行推理导致界面卡顿""" frame_signal = pyqtSignal(object, int, float) # 处理后的帧、人数、耗时 def __init__(self): super().__init__() self.model = None self.cap = None self.running = False self.conf_thres = 0.25 self.iou_thres = 0.45 def load_model(self, model_path): self.model = YOLO(model_path) def set_video_source(self, source): """source 可以是图片路径、视频路径、摄像头索引或 RTSP 地址""" if isinstance(source, int): self.cap = cv2.VideoCapture(source) else: self.cap = cv2.VideoCapture(source) def run(self): self.running = True while self.running: ret, frame = self.cap.read() if not ret: break results = self.model(frame, conf=self.conf_thres, iou=self.iou_thres, verbose=False) annotated_frame = results[0].plot() person_count = 0 for box in results[0].boxes: cls = int(box.cls[0]) if cls == 0: # person person_count += 1 self.frame_signal.emit(annotated_frame, person_count, results[0].speed) def stop(self): self.running = False检测线程通过frame_signal把处理后的帧、人数和推理耗时发回主界面,主界面再渲染到 QLabel 上。关键点在于:推理绝对不能放在主界面线程里做,否则视频流一帧要卡几百毫秒,界面直接假死。
主窗口类核心代码如下:
class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("YOLOv8 人体检测识别计数系统") self.setMinimumSize(1280, 720) # 主布局 self.video_label = QLabel("请打开视频或摄像头") self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setStyleSheet("background-color: #1e1e1e; color: white;") self.count_label = QLabel("当前人数: 0") self.time_label = QLabel("检测耗时: 0 ms") self.open_image_btn = QPushButton("打开图片") self.open_video_btn = QPushButton("打开视频") self.open_camera_btn = QPushButton("打开摄像头") self.stop_btn = QPushButton("停止检测") self.export_btn = QPushButton("导出结果") # 参数控制 self.conf_spin = QDoubleSpinBox() self.conf_spin.setRange(0.05, 0.95) self.conf_spin.setValue(0.25) self.conf_spin.setSingleStep(0.05) self.iou_spin = QDoubleSpinBox() self.iou_spin.setRange(0.05, 0.95) self.iou_spin.setValue(0.45) self.iou_spin.setSingleStep(0.05) # 检测线程 self.detect_thread = DetectThread() self.detect_thread.frame_signal.connect(self.update_frame) self._init_ui() def _init_ui(self): central_widget = QWidget() self.setCentralWidget(central_widget) layout = QHBoxLayout(central_widget) # 左侧视频区域 left_layout = QVBoxLayout() left_layout.addWidget(self.video_label) layout.addLayout(left_layout, stretch=4) # 右侧控制区域 right_layout = QVBoxLayout() right_layout.addWidget(self.count_label) right_layout.addWidget(self.time_label) right_layout.addWidget(self.open_image_btn) right_layout.addWidget(self.open_video_btn) right_layout.addWidget(self.open_camera_btn) right_layout.addWidget(self.stop_btn) right_layout.addWidget(self.export_btn) right_layout.addWidget(QLabel("置信度阈值:")) right_layout.addWidget(self.conf_spin) right_layout.addWidget(QLabel("IOU 阈值:")) right_layout.addWidget(self.iou_spin) right_layout.addStretch() layout.addLayout(right_layout, stretch=1) # 信号连接 self.open_image_btn.clicked.connect(self.open_image) self.open_video_btn.clicked.connect(self.open_video) self.open_camera_btn.clicked.connect(self.open_camera) self.stop_btn.clicked.connect(self.stop_detection) self.export_btn.clicked.connect(self.export_results) def update_frame(self, frame, count, speed): """将 OpenCV BGR 帧转换为 QImage 并显示""" rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch = rgb_frame.shape bytes_per_line = ch * w q_img = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap = QPixmap.fromImage(q_img) pixmap = pixmap.scaled( self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.video_label.setPixmap(pixmap) self.count_label.setText(f"当前人数: {count}") self.time_label.setText(f"检测耗时: {speed['inference']:.1f} ms") def open_image(self): path, _ = QFileDialog.getOpenFileName( self, "选择图片", "", "图片文件 (*.jpg *.png *.bmp)" ) if path: self.detect_thread.requestInterruption() frame = cv2.imread(path) results = self.detect_thread.model(frame, conf=self.conf_spin.value(), iou=self.iou_spin.value()) annotated = results[0].plot() person_count = sum(1 for box in results[0].boxes if int(box.cls[0]) == 0) self.update_frame(annotated, person_count, results[0].speed)图中代码是简化的主窗口。实际使用时,建议把模型路径、输入源、线程状态管理写得更严谨,比如打开摄像头前先停止当前检测线程,再重新创建。
6. 功能测试与效果验证
6.1 图片检测测试
测试目的:验证模型能否正确识别图片中的行人并统计数量。
操作步骤:
- 启动系统,点击"打开图片"。
- 选择一张人流较多的图片。
- 观察右侧人数统计和检测耗时。
预期结果:画面中出现的人体都被矩形框标出,右侧显示的人数和图片中实际人数基本一致。
判断标准:检测出的人数误差是否在可接受范围内。如果漏检严重,降低置信度阈值;如果误检多,提高置信度阈值。
6.2 视频文件检测测试
测试目的:验证系统在连续帧上的稳定性和计数变化。
操作步骤:
- 点击"打开视频",选择一个 mp4 文件。
- 观察视频播放过程中人数统计是否实时更新。
- 注意画面是否卡顿。
预期结果:视频流畅播放,每帧画面中的人数随着行人进出而变化。
判断标准:视频处理帧率能否达到 15 FPS 以上。如果帧率太低,考虑换更小的模型(yolov8n)或降低输入分辨率。
6.3 摄像头实时检测测试
测试目的:验证摄像头输入源的实时性。
操作步骤:
- 点击"打开摄像头"。
- 在摄像头前走动,观察检测框是否跟随人体移动。
- 记录检测耗时。
预期结果:系统能以准实时的速度对摄像头画面进行检测。
判断标准:从画面变化到检测框更新的延迟是否在可接受范围内。CPU 推理延迟会明显高于 GPU。
6.4 密集场景测试
这是这套系统的核心功能验证。选择一张人流非常密集的图片(比如地铁通道、景区门口),观察:
- 小目标漏检情况。远处的人体很小,模型能否识别出来。
- 人群互相遮挡时,能否区分不同个体。
- 计数结果与人工计数的差距。
如果密集场景效果差,优先在更高分辨率下推理(imgsz=960或imgsz=1280),或者使用 YOLOv8m/YOLOv8l 等更大的模型。
7. 接口 API 与批量任务
如果你想把检测能力集成到其他系统里,可以单独封装一个检测服务。这里给两个方案。
7.1 Python 函数封装
最简单的 API 就是一个函数:
from ultralytics import YOLO model = YOLO("runs/detect/train/weights/best.pt") def detect_persons(image_path, conf_thres=0.25, iou_thres=0.45): results = model(image_path, conf=conf_thres, iou=iou_thres, verbose=False) boxes = results[0].boxes persons = [] for box in boxes: cls_id = int(box.cls[0]) if cls_id == 0: x1, y1, x2, y2 = box.xyxy[0].tolist() conf = float(box.conf[0]) persons.append({ "bbox": [x1, y1, x2, y2], "confidence": conf }) return {"total": len(persons), "persons": persons}调用:
result = detect_persons("crowd.jpg") print("总人数:", result["total"])7.2 HTTP 接口服务
用 FastAPI 把检测封装成 HTTP 服务,方便跨语言调用:
from fastapi import FastAPI, UploadFile, File import cv2 import numpy as np from ultralytics import YOLO app = FastAPI() model = YOLO("runs/detect/train/weights/best.pt") @app.post("/detect") async def detect(file: UploadFile = File(...)): contents = await file.read() nparr = np.frombuffer(contents, np.uint8) img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) results = model(img, verbose=False) persons = [] for box in results[0].boxes: if int(box.cls[0]) == 0: persons.append({ "bbox": [float(v) for v in box.xyxy[0]], "confidence": float(box.conf[0]) }) return {"total": len(persons), "persons": persons}启动服务:
uvicorn api_server:app --host 0.0.0.0 --port 8000测试请求:
curl -X POST -F "file=@test.jpg" http://127.0.0.1:8000/detect7.3 批量图片检测
批量处理任务建议加上进度记录和失败重试逻辑。核心思路:遍历目录下所有图片,逐张推理,结果保存到输出目录并按原文件名命名,同时生成一个 CSV 汇总表:
import csv import os from pathlib import Path from ultralytics import YOLO model = YOLO("yolov8s.pt") input_dir = Path("./test_images") output_dir = Path("./output_images") output_dir.mkdir(exist_ok=True) results_csv = [] for img_path in input_dir.glob("*.jpg"): try: results = model(img_path, conf=0.25, verbose=False) annotated = results[0].plot() output_path = output_dir / img_path.name cv2.imwrite(str(output_path), annotated) person_count = sum(1 for box in results[0].boxes if int(box.cls[0]) == 0) results_csv.append([img_path.name, person_count]) print(f"{img_path.name}: {person_count} people") except Exception as e: print(f"{img_path.name}: FAILED - {e}") with open("batch_results.csv", "w", newline="") as f: writer = csv.writer(f) writer.writerow(["image", "person_count"]) writer.writerows(results_csv)批量任务做得再完善一点,可以加多线程并行推理,或者将任务拆分成多个批次交给 GPU 排队处理。
8. 资源占用与性能观察
资源占用是实际部署时最需要关心的部分。虽然没有统一的数字可以套用,但可以给出观察方法和调优方向。
8.1 显存占用怎么看
训练和推理时,用 NVIDIA 官方工具查看:
nvidia-smiLinux 上还可以用实时监控:
watch -n 1 nvidia-smiWindows 上 Task Manager 的 GPU 页签也能看到显存占用。
8.2 模型大小对性能的影响
| 模型 | 参数量 | 推理速度 | 精度 | 适用环境 |
|---|---|---|---|---|
| YOLOv8n | 最小 | 最快 | 较低 | 嵌入式设备、实时性要求高 |
| YOLOv8s | 小 | 较快 | 中上 | 消费级 GPU、通用场景 |
| YOLOv8m | 中 | 中等 | 较高 | 高精度需求 |
| YOLOv8l/x | 大 | 较慢 | 高 | 服务器端离线处理 |
选择建议:实时视频流优先 yolov8s 或 yolov8n;密集小目标图片优先 yolov8m 以上并结合 imgsz=960 甚至 1280。
8.3 推理性能关键参数
- 输入分辨率直接决定推理速度和显存占用。640 和 1280 相比,推理时间可能差 3~4 倍。
- batch size 对单张图片推理没有意义,但对批量任务影响很大。GPU 在 batch 越大时效率越高。
- CPU 推理时,输入分辨率对速度的影响更大,建议密集场景先用预处理裁切,而不是整张大图直接推理。
8.4 PyQt5 界面性能优化
视频流界面卡顿有两个常见原因:一是推理线程耗时太长,二是 QImage 转换和 QPixmap 缩放消耗过多 CPU。优化方向:
- 推理线程只负责推理和画框,不负责界面缩放。
- 显示帧进行降采样。比如推理分辨率是 1280,显示时缩放到 720p。
- 使用
QLabel.setPixmap前先判断画面尺寸是否有变化,避免重复缩放。 - 帧率控制:不是每帧都要做检测,可以隔帧检测,界面显示原帧和最近一次检测结果。
9. 常见问题与排查方法
实际部署中遇到最多的问题集中在这几类:
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 安装 ultralytics 失败 | Python 版本过高或依赖冲突 | 查看 pip 报错日志 | 使用 Python 3.9~3.11,重新创建虚拟环境 |
| CUDA available 为 False | PyTorch 版本和驱动不匹配 | 运行nvidia-smi查看驱动版本 | 安装匹配 CUDA 版本的 PyTorch |
| 训练时显存不足 | batch 太大或 imgsz 太大 | 查看 nvidia-smi 显存占用 | 降低 batch 或 imgsz,开启梯度累积 |
| 检测漏检严重 | 置信度阈值过高、模型过小、输入分辨率不足 | 查看置信度分布 | 降低 conf 到 0.15,换大模型,提高 imgsz |
| 误检多 | 置信度阈值太低、场景复杂 | 查看误检框置信度 | 提高 conf,增加负样本训练 |
| 视频流卡顿 | 推理耗时太长、显示刷新阻塞 | 统计每帧推理耗时 | 换小模型、降分辨率、隔帧检测 |
| PyQt5 界面打不开 | 依赖缺失或 Python 环境问题 | 终端运行看报错 | 重装 PyQt5,检查 QT_QPA_PLATFORM |
| 摄像头打不开 | 摄像头索引错误、权限不足 | 用 cv2.VideoCapture 单独测试 | 检查设备索引,Windows 可尝试 0/1/2 |
| 批量任务中途失败 | 单张图片损坏、内存溢出 | 查看异常日志 | 增加 try/except,逐张保存结果 |
| 模型文件缺失 | 权重路径错误或未下载完成 | 检查路径和文件大小 | 重新下载权重,确认路径正确 |
重点说两个常见坑:
第一个是 PyTorch 和 CUDA 版本不匹配。很多用户装完 PyTorch 后发现torch.cuda.is_available()是 False。解决方法是先查驱动支持的 CUDA 版本,再安装对应 PyTorch。最新的 NVIDIA 驱动一般能兼容 CUDA 12.x 系列,直接安装 cu121 或 cu124 的 PyTorch 通常没问题。
第二个是 PyQt5 界面闪退或空白。这个问题在高 DPI 缩放和多显示器场景下很常见。可以在主程序入口加上:
import os os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"如果画面闪烁或显示异常,可以尝试调整QImage.Format或检查bytes_per_line是否计算正确。
10. 最佳实践与使用建议
这套系统从原型到真实可用,中间还有很多细节。结合我的经验,给几条工程化建议。
第一,第一次跑通流程,用最小配置。先拿一张图片,用官方预训练模型跑通 PyQt5 界面,再逐步加视频、摄像头、自定义模型。一步到位容易出问题,排查起来也麻烦。
第二,模型、数据集、输出结果分目录管理。推荐目录结构:
project/ ├── models/ # 训练好的权重文件 ├── dataset/ # 训练数据集 ├── images/ # 测试图片 ├── videos/ # 测试视频 ├── runs/ # YOLOv8 训练和推理日志 ├── ui/ # PyQt5 界面代码 └── main.py # 主程序入口第三,批量任务一定要加日志。每一张图片的处理状态、结果、耗时都记录到日志文件里。处理几千张图片时,没有日志根本没法定位是哪些图片出了问题。
第四,接口服务要限制访问范围。如果封装成 HTTP API,至少设置--host 127.0.0.1只允许本机访问,或者加上简单的 Token 验证。直接暴露在公网非常危险。
第五,涉及人脸、声音、版权素材时,必须确认授权。这套系统检测的是行人整体,不涉及人脸识别,但在公共区域部署仍然需要符合当地监控和数据管理规定。不要在未经授权的情况下采集和存储可识别个人的数据。
第六,发布或商用前要做效果复核。训练集上的指标再好,也不代表现场效果没问题。拿一段真实场景的视频跑一遍,统计误检率、漏检率,再决定是否上线。
11. 总结与下一步
这套基于 YOLOv8 + PyQt5 的人体检测系统,最值得尝试的点是它把模型训练、桌面界面和实际业务场景串在了一条完整的链路上。从数据集准备、模型微调,到 PyQt5 界面开发、视频流检测、批量任务处理,每一步都是可落地的。
最先要验证的功能是图片检测和视频检测的基础流程。用官方预训练模型跑通后,再换自己的数据集微调。最容易踩的坑是环境配置阶段的 CUDA 版本不匹配,以及 PyQt5 界面渲染的性能瓶颈。
后续可以继续扩展的方向也很多:接入更复杂的跟踪算法如 ByteTrack 或 DeepSORT 实现跨帧人数统计和轨迹绘制;增加 ROI 区域设定,只统计指定区域的人群密度;接入 RTSP 流做多路摄像头并发处理;或者把 PyQt5 界面替换成 Web 界面,统一管理多台检测设备。这套系统的价值不只是演示目标检测,而是提供了一个完整的多功能桌面应用开发模板,值得你动手试一试。