YOLOv8+PyQt5人群检测计数系统设计与实现
2026/9/6 23:49:07 网站建设 项目流程

这次我们来看一个非常典型的计算机视觉综合项目:基于 YOLOv8 + PyQt5 的密集人群人体检测识别计数系统。这类系统在安防监控、客流统计、公共场所密度预警等场景里很常见,也是很多同学做毕业设计、课题练习或者企业内部工具时的首选方案。

项目的核心思路不复杂:用 YOLOv8 作为目标检测引擎,对视频流、图片或者本地摄像头画面中的人体进行实时识别,再用 PyQt5 搭建一个可视化桌面界面,把检测结果、人数统计、帧率等信息直接展示出来。相比纯命令行调用模型,PyQt5 界面的价值在于:你可以把模型能力封装成一个普通用户也能操作的工具,不需要对方懂 Python,也不需要对方去敲命令。这一点在实际落地场景里非常重要。

从技术门槛来看,这个项目覆盖了深度学习目标检测、模型训练与推理、OpenCV 图像处理、PyQt5 桌面应用开发、多线程与实时视频流处理等知识点。如果你想系统性地练习一遍 CV 工程化流程,这个项目是一个很完整的载体。本文会把整个系统的设计思路、环境配置、部署流程、功能测试和常见坑位都过一遍,并附上可复用的代码示例。

1. 核心能力速览

能力项说明
项目类型深度学习目标检测 + 桌面 GUI 应用
检测模型YOLOv8(支持 yolov8n / yolov8s / yolov8m / yolov8l 等版本)
界面框架PyQt5
主要功能图片检测、视频文件检测、摄像头实时检测、人数统计、检测结果可视化
支持平台Windows / Linux,需根据实际环境安装对应依赖
GPU 要求推荐 NVIDIA 显卡 + CUDA 环境;CPU 也可运行,但推理速度会明显下降
显存占用取决于模型版本、输入分辨率和 batch 大小,需以实际运行环境为准
启动方式Python 代码启动,可打包为 exe / 一键启动脚本
是否支持 API需自行封装,项目本身可以增加 Flask / FastAPI 服务
是否支持批量任务需结合代码扩展,视频文件与图片目录可批量处理
适合场景课堂设计、毕业设计、安防监控演示、客流统计原型、算法验证工具

从材料来看,YOLOv8 已经是目前 Ultralytics 团队维护的成熟框架,环境配置简单,模型文件在首次运行时自动下载,对新手比较友好。PyQt5 则负责把检测能力包装成图形界面,支持按钮点击、文件选择、实时画面刷新等功能。整个系统的复杂度主要不在算法本身,而在工程整合。

2. 适用场景与使用边界

2.1 适合谁用

这个系统设计适合以下几类人群:

  • 正在做毕业设计或课程设计的学生,需要一个完整的 CV 项目来展示目标检测、GUI 开发和实时视频处理能力。
  • 需要快速搭建安防监控界面原型的开发者,先验证 YOLOv8 在具体场景下的检测效果。
  • 想学习 PyQt5 和 YOLOv8 如何配合使用的工程初学者。
  • 企业内部想做客流统计、区域人数超限提醒等功能的测试人员。

2.2 能解决什么问题

系统可以把“输入一张图片 / 一段视频 / 一路摄像头画面”变成“输出打了检测框的实时画面 + 人数统计结果”。在演示场景中,它能验证模型是否准确定位密集人群中的每一个人,并给出计数。

2.3 不适合什么场景

  • 高并发、多路摄像头同时接入的生产级系统,需要做服务化改造和负载均衡,桌面 GUI 不是最优解。
  • 对检测精度要求极高的场景(比如精确区分行人和非行人),需要针对特定场景采集数据并重新训练模型。
  • 需要在手机端或嵌入式设备(如 RK3588、Jetson)上运行的场景,需要换用轻量化部署方案,比如 YOLOv8n 导出 ONNX 或 TensorRT。

2.4 合规与安全边界

人体检测系统会涉及人脸、行人等敏感信息。如果你把系统用在真实监控环境中,务必注意以下边界:

  • 使用公开数据集(如 COCO、CrowdHuman)训练或测试时,确认数据集的使用许可。
  • 在真实场景中采集视频或图片,需要获得相关人员的知情同意,或确保使用范围符合当地法律法规和平台规定。
  • 不要将检测结果用于未经授权的身份识别、行为分析或任何可能侵犯个人隐私的用途。
  • 如果涉及人脸信息,强烈建议做人脸匿名化处理,比如在输出画面中模糊人脸区域,仅保留人体框。

3. 环境准备与前置条件

3.1 硬件环境

YOLOv8 支持 CPU 和 GPU 推理。对于本项目,建议按以下标准准备环境:

硬件项推荐配置说明
CPU4 核以上CPU 也能跑,但 fps 较低
GPUNVIDIA 显卡,显存 4G 以上可选,但对实时视频检测提升明显
内存8G 以上视频解码和多线程处理会占用内存
硬盘10G 以上可用空间模型文件、Python 环境、依赖库都需要空间

如果你使用 GTX 1660 Ti 这类显卡,跑 YOLOv8n 或 YOLOv8s 是可以接受的,显存占用通常在 2G 到 4G 之间,具体取决于输入分辨率。RTX 系列显卡体验更好,尤其是开启了 TensorRT 加速之后。

3.2 软件环境

需要注意:这里的版本号是通用推荐,实际安装时以项目兼容性为准,建议先测试再固定版本。

建议使用 Python 3.8 到 3.11 之间的版本。PyQt5 对 Python 3.11 的支持已经比较稳定,YOLOv8 的 Ultralytics 包在 Python 3.8 以上都可以正常使用。

必装依赖:

pip install ultralytics pip install PyQt5 pip install opencv-python pip install torch pip install torchvision pip install numpy pip install pillow pip install pandas

如果你使用 NVIDIA GPU,还需要确认 CUDA 和 cuDNN 是否已安装,并且确保 PyTorch 版本与 CUDA 版本匹配。如果 PyTorch 安装成了 CPU 版本,即使显卡正常也无法使用 GPU 加速。

安装 PyTorch 的参考命令:

# 先到 PyTorch 官网确认 CUDA 版本对应的安装命令 # 下面只是一个模板示例,具体版本需根据本机 CUDA 版本调整 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118

3.3 检查环境是否就绪

安装完成后,可以用下面的代码检查 PyTorch 是否能正常调用 GPU:

import torch print("PyTorch 版本:", torch.__version__) print("CUDA 是否可用:", torch.cuda.is_available()) if torch.cuda.is_available(): print("显卡名称:", torch.cuda.get_device_name(0)) else: print("当前使用 CPU 模式,推理速度会相对较慢")

如果torch.cuda.is_available()返回False,说明 PyTorch 的 CUDA 版本不匹配,或者当前环境没有可用的 NVIDIA 驱动。优先考虑重装对应版本的 PyTorch。

4. 安装部署与启动流程

4.1 下载依赖与模型权重

YOLOv8 的模型权重不需要手动下载。Ultralytics 包会在第一次调用时自动下载 yolov8n.pt、yolov8s.pt 等预训练权重文件,默认保存到当前工作目录。为了让项目结构更清晰,建议手动放置模型文件:

mkdir weights

然后从 Ultralytics 官方 GitHub Release 页面下载对应版本的.pt文件,放到weights目录下。如果你只想快速跑通,直接让代码自动下载也是可以的。

4.2 模型加载与基础推理测试

先做一个最基础的模型加载测试,确认 YOLOv8 可以正常工作:

# test_yolo.py from ultralytics import YOLO # 加载预训练模型 model = YOLO("./weights/yolov8n.pt") # 对一张图片进行推理 results = model.predict( source="./test.jpg", conf=0.4, save=True, imgsz=640 ) print("检测完成,结果已保存")

执行后,项目目录下会生成runs/detect/predict文件夹,里面包含标注了检测框的结果图。如果能正常生成,说明 YOLO 环境已经就绪。

4.3 PyQt5 主界面框架

PyQt5 界面部分是这个项目的关键。下面是一个最小可运行的主窗口示例,包含了按钮选择图片、显示检测结果和计数信息的基础结构:

import sys import cv2 from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QFileDialog, QVBoxLayout, QWidget from PyQt5.QtGui import QImage, QPixmap from PyQt5.QtCore import Qt class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("YOLOv8 + PyQt5 人体检测计数系统") self.resize(900, 600) self.image_label = QLabel("请选择图片") self.image_label.setAlignment(Qt.AlignCenter) self.open_btn = QPushButton("选择图片") self.open_btn.clicked.connect(self.open_image) layout = QVBoxLayout() layout.addWidget(self.image_label) layout.addWidget(self.open_btn) container = QWidget() container.setLayout(layout) self.setCentralWidget(container) def open_image(self): file_path, _ = QFileDialog.getOpenFileName( self, "选择图片", "./", "图片文件 (*.jpg *.jpeg *.png)" ) if file_path: self.show_image(file_path) def show_image(self, file_path): img = cv2.imread(file_path) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) h, w, ch = img.shape bytes_per_line = ch * w q_img = QImage(img.data, w, h, bytes_per_line, QImage.Format_RGB888) pixmap = QPixmap.fromImage(q_img).scaled( self.image_label.width(), self.image_label.height(), Qt.KeepAspectRatio ) self.image_label.setPixmap(pixmap) if __name__ == "__main__": app = QApplication(sys.argv) window = MainWindow() window.show() sys.exit(app.exec_())

运行后,你会看到一个非常简单但可用的 PyQt5 窗口。下一步就是把 YOLOv8 检测结果绘制到这个窗口里。

4.4 封装基于模型推理的业务逻辑

为了避免界面卡顿,建议把模型推理放到单独的线程中,而不是直接在主线程里跑。这样做的好处是:视频播放时界面不会失去响应,切换图片或视频时体验更流畅。

下面是一个简单的推理线程示例:

import threading import cv2 from ultralytics import YOLO class DetectThread(threading.Thread): def __init__(self, model_path, source_path, callback): super().__init__() self.model = YOLO(model_path) self.source_path = source_path self.callback = callback self.running = True def run(self): cap = cv2.VideoCapture(self.source_path) while self.running: ret, frame = cap.read() if not ret: break results = self.model.predict(frame, conf=0.4, imgsz=640) annotated_frame = results[0].plot() self.callback(annotated_frame) cap.release() def stop(self): self.running = False

在 PyQt5 主窗口中,通过信号槽机制把识别后的帧刷新到 QLabel 即可。这里要注意plot()返回的是带标注的 BGR 图像,显示前要转换为 RGB 格式。

5. 功能测试与效果验证

5.1 图片检测测试

测试目的:验证模型能否在单张图片中定位并识别所有人。

操作步骤:

  1. 准备一张密集人群图片,比如街拍、广场或车站候车厅图片。
  2. 调用 YOLOv8 进行推理。
  3. 观察检测框是否准确覆盖人体,计数结果是否接近真实人数。

预期结果:

  • 检测框覆盖大部分可见人体。
  • 检测框类别为person且置信度分数合理。
  • 计数结果与实际人数偏差不大。

常见失败原因:

  • 图片中人体尺寸太小,使用imgsz=640无法检出小目标。
  • 人体相互遮挡严重,需要提高conf阈值减少重复框,或者使用更大模型。

5.2 视频文件检测测试

测试目的:验证模型在连续视频帧中的稳定性。

输入素材:一段人员行走的 mp4 视频。

操作步骤:

  1. 使用 OpenCV 逐帧读取视频。
  2. 对每一帧调用 YOLOv8 推理。
  3. 统计平均检测帧率和计数波动。

预期结果:

  • 视频画面流畅输出检测框。
  • 计数结果不会出现频繁跳变。

如果检测速度太慢,优先降低输入分辨率到 480,或者换用yolov8n.pt这种轻量模型。

5.3 摄像头实时检测测试

测试目的:验证实时视频流场景下的可用性。

操作步骤:

  • 运行 PyQt5 程序。
  • 点击“打开摄像头”按钮。
  • 程序调用cv2.VideoCapture(0)读取本机摄像头画面。
  • 将每一帧送入检测线程。

预期结果:

  • 摄像头画面实时显示在界面上。
  • 人体检测框跟随人员移动。
  • 界面不卡死,帧率可接受。

如果画面延迟明显,检查是否有多个模型实例被重复创建,推理线程是否在每次循环中都进行了不必要的模型初始化。

5.4 计数功能验证

计数是这类系统的核心功能之一。实现思路有两种:

  • 统计当前画面中检测到的 person 类别数量。
  • 统计视频或监控场景中累计出现的人数。

第一种相对简单,直接在每次推理结果里累加person类别数量即可。第二种需要引入目标跟踪逻辑,比如 ByteTrack 或 DeepSORT,否则同一人会被多次计数。

本项目如果只做基础版,建议先完成第一种功能,并明确标注是“当前画面人数”。如果要实现“累计进入人数”,需要在 ROI 区域设置一条计数线,结合跟踪算法判断人员是否跨越该线。

5.5 模型大小与精度的权衡测试

模型版本体重推理速度精度适用场景
yolov8n.pt约 6 MB实时预览、低配环境
yolov8s.pt约 22 MB常规检测需求
yolov8m.pt约 52 MB较慢较高对精度有更高要求
yolov8l.pt约 87 MB离线分析

对于密集人群场景,小目标比较多,单纯换大模型不一定能解决所有问题。更有效的做法是使用更大的输入分辨率,比如imgsz=960imgsz=1280,但显存占用也会成倍增加。实际部署时,需要在自己的显卡上测试一组分辨率,找到速度与精度的平衡点。

6. 接口 API 与批量任务

6.1 为什么要提供 API

桌面 GUI 是给人用的,API 是给程序用的。如果你希望把检测能力开放给其他系统,比如网页后端、移动端小程序或者自动化脚本,就需要封装一个 HTTP 接口。YOLOv8 + Flask / FastAPI 的组合非常成熟,半小时内就能搭好。

6.2 FastAPI 检测服务示例

下面的代码展示了一个最简检测接口,支持上传图片并返回检测结果:

# api_server.py from fastapi import FastAPI, UploadFile, File from ultralytics import YOLO import cv2 import numpy as np app = FastAPI() # 全局加载模型,避免每次请求重复加载 model = YOLO("./weights/yolov8n.pt") @app.post("/detect") async def detect(file: UploadFile = File(...)): # 读取上传图片 image_bytes = await file.read() nparr = np.frombuffer(image_bytes, np.uint8) img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # 推理 results = model.predict(img, conf=0.4, imgsz=640) # 提取检测框信息 boxes = results[0].boxes detections = [] if boxes is not None: for box in boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() conf = float(box.conf[0]) cls = int(box.cls[0]) name = model.names[cls] detections.append({ "class": name, "confidence": round(conf, 4), "bbox": [round(x1, 2), round(y1, 2), round(x2, 2), round(y2, 2)] }) return { "count": len(detections), "detections": detections }

启动服务:

uvicorn api_server:app --host 0.0.0.0 --port 8000

调用测试:

curl -X POST "http://127.0.0.1:8000/detect" \ -F "file=@test.jpg"

接口返回示例:

{ "count": 3, "detections": [ { "class": "person", "confidence": 0.86, "bbox": [120.5, 80.2, 260.1, 400.3] } ] }

6.3 Python 调用 API 的通用模板

import requests url = "http://127.0.0.1:8000/detect" files = {"file": open("test.jpg", "rb")} response = requests.post(url, files=files, timeout=30) result = response.json() print("检测人数:", result["count"]) for detection in result["detections"]: print(detection)

如果你想把 API 服务集成到 PyQt5 界面中,只需要在按钮点击事件里用requests发送请求,再把返回结果渲染到界面上即可。

6.4 批量任务设计

批量任务的核心是“遍历目录 + 逐文件处理 + 输出结构化结果”。下面是一种简单的批量处理方式:

import os from ultralytics import YOLO import csv model = YOLO("./weights/yolov8n.pt") input_dir = "./inputs" output_dir = "./outputs" os.makedirs(output_dir, exist_ok=True) results_rows = [] for img_name in os.listdir(input_dir): img_path = os.path.join(input_dir, img_name) results = model.predict(img_path, conf=0.4, imgsz=640, save=True) person_count = sum(1 for box in results[0].boxes if model.names[int(box.cls[0])] == "person") results_rows.append([img_name, person_count]) print(f"{img_name}: {person_count} 人") # 保存统计结果 with open(os.path.join(output_dir, "count_result.csv"), "w", newline="", encoding="utf-8") as f: writer = csv.writer(f) writer.writerow(["图片名", "人数"]) writer.writerows(results_rows) print("批量处理完成")

在实际工程中,建议把处理失败的文件单独记到一个error_log.txt中,避免某个异常图片导致整个任务中断。

7. 资源占用与性能观察

7.1 显存占用怎么看

YOLOv8 训练或推理时的显存占用可以通过以下命令实时观察:

nvidia-smi

如果是 GPU 推理,注意观察Memory-Usage列,以及python进程占用的显存大小。

从常规经验看:

  • yolov8n.pt+imgsz=640:显存占用较低,4G 显存可以流畅运行。
  • yolov8s.pt+imgsz=640:显存占用中等,建议 4G 以上。
  • yolov8m/l.pt+imgsz=1280:显存占用会明显上升,建议 8G 以上。

但这些数字不是绝对的,实际占用会随视频分辨率、batch 大小和模型输入尺寸变化。关键是通过nvidia-smi观察自己环境下的真实占用。

7.2 CPU 推理和 GPU 推理的差异

同一台机器,GPU 推理速度通常比 CPU 快数倍到十数倍。CPU 模式下,轻量模型处理单张图片可能在几百毫秒到一秒左右,视频实时检测基本不现实。GPU 模式下,yolov8n可以达到几十 FPS 甚至上百 FPS。

所以,如果你的机器没有 NVIDIA 显卡,建议把系统定位为“离线图片检测工具”,而不是实时视频检测系统。

7.3 影响性能的关键参数

  • imgsz:值越大,检测越精细,但耗时和显存占用越高。
  • conf:置信度阈值越低,检测框越多,耗时略有增加。
  • 视频源分辨率:1080p 视频输入时,可以先resize到 640 或 960 宽,再送入模型。
  • 批量推理:处理视频时不要一帧一帧单独调用predict,可以尝试将多帧拼接成 batch,但实现难度会提高。

7.4 降低显存占用的思路

  • 使用yolov8n而不是yolov8x
  • 降低输入分辨率,比如从 1280 降到 640。
  • 减少视频解码缓存,cv2.VideoCapture的缓冲可以调低。
  • 推理一次后主动清理解析结果,避免结果对象堆积。
  • 程序中只保留一个 YOLO 模型实例,不要每次调用都重新加载。

8. 常见问题与排查方法

问题现象可能原因排查方式解决方案
PyTorch 显示 CUDA 不可用PyTorch 为 CPU 版本,或 CUDA 驱动不匹配执行torch.cuda.is_available()检查重装匹配 CUDA 版本的 PyTorch
首次运行自动下载模型失败网络问题导致下载超时观察控制台日志手动下载.pt文件放到weights目录
启动后页面显示出来了,但没有检测结果推理线程没有正确启动,或图片路径为空在界面中添加日志输出,检查file_path是否传入将推理代码封装到独立线程,通过信号回调传递结果
视频播放不流畅,界面卡死视频检测与 GUI 刷新在同一个线程观察 CPU/GPU 占用和界面响应速度使用QThreadthreading.Thread分离推理
同一人在不同帧被重复计数简单的逐帧计数无法区分目标查看连续帧计数波动引入 ByteTrack / 跟踪器,或只在指定区域统计
小目标人群检测不到输入分辨率过低观察检测结果与图片中目标尺寸的关系提高imgsz到 960 / 1280,或使用更大模型
PyQt5 安装失败Python 版本过新或过旧查看 pip 错误日志使用 Python 3.9–3.11,或尝试安装 PyQt5-Qt5
摄像头打不开摄像头索引错误或权限问题执行cv2.VideoCapture(0)测试更换索引为1或检查系统摄像头权限

8.1 常见依赖版本冲突

PyQt5 和 OpenCV 都依赖一些底层库,如果同时安装多个版本的 numpy,可能出现崩溃。稳妥的做法是固定版本:

pip install numpy==1.24.3 pip install opencv-python==4.8.0.74 pip install PyQt5==5.15.9 pip install ultralytics==8.0.0

注意:这些版本只是参考,具体以你项目的兼容性为准。如果项目运行正常,不建议随便升级依赖。

8.2 模型文件缺失问题

模型加载时报错File not found,最常见的原因是路径写错。建议在代码中打印当前工作目录:

import os print(os.getcwd())

然后把模型路径写为绝对路径或基于当前目录的相对路径,避免启动目录不一致导致找不到模型。

9. 最佳实践与使用建议

9.1 先小参数测试,再上完整流程

第一次运行系统时,不要直接加载大模型和处理长视频。先用yolov8n.pt+ 一张单图,跑通整个链路。确认模型推理、界面刷新都正常之后,再逐步切换到更大模型和实时视频流。

9.2 项目目录结构建议

project/ ├── main.py # PyQt5 入口 ├── api_server.py # FastAPI 服务入口 ├── detect_thread.py # 推理线程封装 ├── weights/ │ └── yolov8s.pt # 模型权重 ├── inputs/ # 测试图片/视频 ├── outputs/ # 检测结果输出 ├── runs/ # Ultralytics 自动生成的运行结果 ├── requirements.txt # 依赖清单 └── README.md # 项目说明

9.3 模型和素材分目录管理

模型文件、输入素材、输出结果、日志文件要分目录存放。批量任务处理时,按日期生成子目录,避免结果被覆盖:

from datetime import datetime output_dir = f"./outputs/{datetime.now().strftime('%Y%m%d_%H%M%S')}"

9.4 批量任务要加日志和失败重试

批量处理大量图片或视频时,单张图片损坏、编码格式不支持都可能导致程序中断。在 try-except 中捕获异常并记录日志,是工程化的基本要求。

import traceback for file in file_list: try: process_file(file) except Exception: with open("error_log.txt", "a", encoding="utf-8") as f: f.write(file + "\n") f.write(traceback.format_exc())

9.5 接口服务要限制访问范围

FastAPI 服务默认监听0.0.0.0,在公网环境下会被任意来源调用。不要把检测服务直接暴露到公网,除非你加了认证或网络访问控制。开发时使用127.0.0.1,内网使用时用防火墙限制来源 IP。

9.6 涉及人脸、声音、版权素材时确认授权

本项目主要检测人体,但监控场景下不可避免地会拍到人脸。如果你要做效果演示,建议使用 COCO 官方图片、CrowdHuman 公开数据集或自己拍摄的素材,不要直接处理陌生人的实时监控画面,更不能把检测结果公开发布并带有可识别身份的信息。

10. 总结与下一步

这个项目的核心价值是把 YOLOv8 的检测能力和 PyQt5 的界面能力组合起来,形成一个可以演示、可以测试、可以二次开发的完整系统。相比纯算法脚本,它多了交互和可视化的维度;相比生产级安防平台,它保留了轻量和灵活的优势。

最开始上手时,先验证三件事:环境里能否跑通 YOLOv8 推理、PyQt5 窗口能否正常显示图片、推理线程和界面信号槽是否配合正常。这三个点通了,项目就已经完成了一半。最需要花时间的部分通常是视频流实时检测的逻辑,尤其是视频帧率高时如何保证界面不卡顿、计数不跳变。

下一步可以考虑的方向:

  • 引入 ByteTrack 或 DeepSORT 跟踪算法,实现稳定的“累计进入人数”统计。
  • 增加 ROI 区域人数超限报警功能,当区域内人数超过阈值时自动截图并弹窗提醒。
  • 用 PyInstaller 将项目打包成 exe,方便在没有 Python 环境的电脑上运行。
  • 把 YOLOv8 模型导出为 ONNX 或 TensorRT 格式,提高推理速度。
  • 增加多摄像头切换和轮询检测的界面功能。

不管你是为了课题演示还是自研工具,这套 YOLOv8 + PyQt5 的组合都是值得掌握的。把部署流程和常见问题整理清楚,后面扩展新功能时就能把精力集中在业务逻辑上。建议收藏备用,按上面的步骤跑一遍,有问题按排查表逐项对照。

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

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

立即咨询