計(jì)數(shù)系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn))
YOLOv8PyQt5 密集人群人體檢測(cè)識(shí)別計(jì)數(shù)系統(tǒng)設(shè)計(jì)與實(shí)現(xiàn)這次我們來(lái)看一個(gè)非常典型的深度學(xué)習(xí)落地場(chǎng)景在商場(chǎng)、景區(qū)、地鐵站這類(lèi)人流密集區(qū)域如何用 YOLOv8 配合 PyQt5 搭建一套人體檢測(cè)與計(jì)數(shù)系統(tǒng)。這類(lèi)系統(tǒng)在智能安防、客流統(tǒng)計(jì)、區(qū)域擁擠預(yù)警里應(yīng)用很多難點(diǎn)主要集中在三塊——模型能不能在小目標(biāo)密集場(chǎng)景下保持精度、視頻流能不能實(shí)時(shí)處理、以及檢測(cè)結(jié)果能不能在桌面端應(yīng)用里直觀展示。下面我直接把這套系統(tǒng)的設(shè)計(jì)思路、訓(xùn)練流程、PyQt5 界面實(shí)現(xiàn)和性能優(yōu)化方案拆開(kāi)寫(xiě)清楚。如果你正準(zhǔn)備做畢業(yè)設(shè)計(jì)、課程項(xiàng)目或者想在公司內(nèi)部快速搭一個(gè)人體計(jì)數(shù) Demo這篇文章可以直接照著做。1. 核心能力速覽先看這套系統(tǒng)的關(guān)鍵能力能力項(xiàng)說(shuō)明檢測(cè)模型YOLOv8支持 nano/small/medium/large/x 多版本界面框架PyQt5支持實(shí)時(shí)視頻顯示、檢測(cè)結(jié)果疊加、計(jì)數(shù)統(tǒng)計(jì)核心功能人體檢測(cè)、目標(biāo)計(jì)數(shù)、視頻/圖片/攝像頭輸入、檢測(cè)結(jié)果導(dǎo)出硬件要求訓(xùn)練推薦 NVIDIA GPU純推理可 CPU有 GPU 速度更快顯存占用與模型大小、輸入分辨率直接相關(guān)需按實(shí)際配置測(cè)試支持平臺(tái)Windows / Linux啟動(dòng)方式Python 命令行啟動(dòng) PyQt5 應(yīng)用API 能力可封裝為檢測(cè)接口供其他程序調(diào)用批量任務(wù)支持批量圖片檢測(cè)和視頻逐幀檢測(cè)適合場(chǎng)景客流統(tǒng)計(jì)、擁擠預(yù)警、安防監(jiān)控、畢設(shè)/課設(shè)項(xiàng)目YOLOv8 是 Ultralytics 團(tuán)隊(duì)在 2023 年初發(fā)布的目標(biāo)檢測(cè)框架相比 YOLOv5 最大的變化是采用了 Anchor-Free 檢測(cè)頭并且把分類(lèi)、檢測(cè)、分割、姿態(tài)估計(jì)統(tǒng)一到了一個(gè)框架里。配合 PyQt5 做桌面界面不需要瀏覽器直接打包成 exe 就能在 Windows 上跑這對(duì)安防領(lǐng)域的實(shí)際部署來(lái)說(shuō)非常方便。2. 適用場(chǎng)景與使用邊界這套系統(tǒng)能解決的問(wèn)題總結(jié)下來(lái)是三類(lèi)靜態(tài)圖片中的人體檢測(cè)與計(jì)數(shù)。比如上傳一張商場(chǎng)入口的抓拍圖系統(tǒng)自動(dòng)標(biāo)出每個(gè)人并顯示總數(shù)。視頻文件或?qū)崟r(shí)攝像頭中的人體檢測(cè)與計(jì)數(shù)。比如接入監(jiān)控?cái)z像頭 RTSP 流實(shí)時(shí)統(tǒng)計(jì)畫(huà)面里的人數(shù)變化。批量圖片的處理。比如一次性處理一整天抓拍的幾百?gòu)垐D片輸出每張圖片的人數(shù)和檢測(cè)結(jié)果圖。適合的人群也很明確。做畢設(shè)和課設(shè)的學(xué)生、需要快速驗(yàn)證目標(biāo)檢測(cè)方案的開(kāi)發(fā)者、以及安防或零售行業(yè)想做客流統(tǒng)計(jì)的技術(shù)人員都可以直接用這套方案。使用邊界同樣需要說(shuō)清楚。這類(lèi)系統(tǒng)基于視覺(jué)模型對(duì)遮擋嚴(yán)重的密集場(chǎng)景檢測(cè)精度會(huì)下降光線(xiàn)暗、雨天、低分辨率攝像頭都會(huì)影響效果。另外在公共區(qū)域部署時(shí)務(wù)必獲得監(jiān)控設(shè)備和數(shù)據(jù)使用的合法授權(quán)不能私自采集人臉或行人的可識(shí)別信息用于其他用途涉及隱私數(shù)據(jù)要脫敏處理。模型本身只輸出人體位置和數(shù)量不識(shí)別身份但采集端合規(guī)問(wèn)題仍然需要自己把關(guān)。3. 環(huán)境準(zhǔn)備與前置條件先確認(rèn)環(huán)境。這套系統(tǒng)核心依賴(lài)是 PyTorch、Ultralytics YOLOv8、OpenCV 和 PyQt5。硬件方面訓(xùn)練推薦至少一塊 NVIDIA GPU最好是 6GB 以上顯存。純推理的話(huà)CPU 也能跑但視頻流實(shí)時(shí)性和高分辨率圖片的處理速度會(huì)差很多。如果你手里只有 GTX 1660 Ti、RTX 3060、RTX 4060 這類(lèi)顯卡只要顯存超過(guò) 6GB跑 YOLOv8s 或 YOLOv8m 沒(méi)有問(wèn)題。軟件環(huán)境建議如下我這里列的是推薦配置實(shí)際以你本機(jī)為基礎(chǔ)操作系統(tǒng)Windows 10/11 或 Ubuntu 20.04/22.04Python3.8 到 3.11 均可推薦 3.10CUDA11.8 或 12.1需匹配 PyTorch 版本主要依賴(lài)ultralytics、torch、torchvision、opencv-python、PyQt5、numpy安裝 PyTorch 前先確認(rèn)顯卡驅(qū)動(dòng)和 CUDA 版本。推薦直接用 pip 安裝命令如下# 先安裝 PyTorchCUDA 12.1 版本示例 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121 # 再安裝其余依賴(lài) pip install ultralytics opencv-python PyQt5 numpy如果在國(guó)內(nèi)網(wǎng)絡(luò)環(huán)境安裝較慢可以換用清華鏡像源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安裝完成后用下面這段代碼驗(yàn)證環(huán)境是否正常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說(shuō)明 PyTorch 的 CUDA 版本和驅(qū)動(dòng)不匹配需要重新安裝對(duì)應(yīng)版本的 PyTorch。CPU 環(huán)境也能繼續(xù)做推理測(cè)試只是速度會(huì)慢。4. 數(shù)據(jù)處理與模型訓(xùn)練這套系統(tǒng)的核心之一是訓(xùn)練一個(gè)人體檢測(cè)模型。如果你不想自己訓(xùn)練可以直接用 YOLOv8 自帶的預(yù)訓(xùn)練權(quán)重yolov8n.pt和yolov8s.pt模型里本身就包含 person 這個(gè)類(lèi)別。但你如果想要針對(duì)自己場(chǎng)景做更高精度的檢測(cè)用自己的數(shù)據(jù)集微調(diào)是必須的。4.1 數(shù)據(jù)集準(zhǔn)備人體檢測(cè)數(shù)據(jù)集最常見(jiàn)的公開(kāi)選項(xiàng)是 COCO 數(shù)據(jù)集中的 person 類(lèi)別或者 CrowdHuman 這類(lèi)密集人群數(shù)據(jù)集。自己采集數(shù)據(jù)時(shí)要注意覆蓋不同角度、不同光照、不同密度場(chǎng)景。數(shù)據(jù)集目錄結(jié)構(gòu)建議如下dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/標(biāo)注格式采用 YOLO 格式每個(gè)圖片對(duì)應(yīng)一個(gè)同名的 txt 文件每行代表一個(gè)目標(biāo)class_id x_center y_center width height坐標(biāo)值都是歸一化到 0~1 的浮點(diǎn)數(shù)。比如0 0.514648 0.479492 0.235352 0.772461標(biāo)注工具可以用 LabelImg 或者 LabelStudio導(dǎo)出成 YOLO 格式即可。4.2 模型配置文件在項(xiàng)目目錄下創(chuàng)建person-detection.yaml內(nèi)容如下path: ./dataset train: images/train val: images/val test: images/test names: 0: person這個(gè)文件告訴 YOLOv8 數(shù)據(jù)集的路徑和類(lèi)別名稱(chēng)。4.3 訓(xùn)練命令YOLOv8 訓(xùn)練入口非常簡(jiǎn)單一條命令就能啟動(dòng)yolo detect train dataperson-detection.yaml modelyolov8s.pt epochs100 imgsz640 batch16 device0參數(shù)含義data數(shù)據(jù)集配置文件的路徑。model預(yù)訓(xùn)練權(quán)重路徑也可以用yolov8s.yaml從頭訓(xùn)練但用預(yù)訓(xùn)練權(quán)重收斂更快。epochs訓(xùn)練輪數(shù)小數(shù)據(jù)集建議 100 輪起步。imgsz輸入圖像分辨率推薦 640 或 768。密集小目標(biāo)場(chǎng)景可以適當(dāng)提升到 960但顯存占用會(huì)增大。batch批大小根據(jù)顯存調(diào)整。8GB 顯存跑 YOLOv8s 建議 batch 不超過(guò) 32。device0表示第一張 GPUcpu表示 CPU 訓(xùn)練。訓(xùn)練過(guò)程中日志會(huì)打印每個(gè) epoch 的 mAP、precision、recall 等指標(biāo)。訓(xùn)練結(jié)束后最優(yōu)權(quán)重保存在runs/detect/train/weights/best.pt。如果你只是想快速驗(yàn)證整套系統(tǒng)流程先不要訓(xùn)練直接用官方預(yù)訓(xùn)練權(quán)重測(cè)試yolo predict modelyolov8s.pt sourcetest.jpg5. PyQt5 系統(tǒng)設(shè)計(jì)與界面實(shí)現(xiàn)現(xiàn)在進(jìn)入系統(tǒng)核心部分。這套人體檢測(cè)識(shí)別計(jì)數(shù)系統(tǒng)采用 PyQt5 作為桌面界面框架整體結(jié)構(gòu)分為三層層級(jí)組件職責(zé)界面層PyQt5 主窗口顯示視頻畫(huà)面、按鈕控制、計(jì)數(shù)結(jié)果展示邏輯層檢測(cè)線(xiàn)程、計(jì)數(shù)邏輯調(diào)用 YOLOv8 模型推理統(tǒng)計(jì)人數(shù)數(shù)據(jù)層輸入源管理支持圖片文件、視頻文件、攝像頭、RTSP 流界面布局參考如下左側(cè)視頻/圖片顯示區(qū)域。右側(cè)檢測(cè)結(jié)果信息區(qū)包括總?cè)藬?shù)、當(dāng)前幀人數(shù)、檢測(cè)耗時(shí)。底部操作按鈕包括打開(kāi)圖片、打開(kāi)視頻、打開(kāi)攝像頭、停止檢測(cè)、導(dǎo)出結(jié)果。頂部菜單模型選擇、置信度閾值設(shè)置、IOU 閾值設(shè)置。這里直接給出主窗口的核心代碼框架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): 檢測(cè)線(xiàn)程避免在 UI 線(xiàn)程中執(zhí)行推理導(dǎo)致界面卡頓 frame_signal pyqtSignal(object, int, float) # 處理后的幀、人數(shù)、耗時(shí) 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, confself.conf_thres, iouself.iou_thres, verboseFalse) 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檢測(cè)線(xiàn)程通過(guò)frame_signal把處理后的幀、人數(shù)和推理耗時(shí)發(fā)回主界面主界面再渲染到 QLabel 上。關(guān)鍵點(diǎn)在于推理絕對(duì)不能放在主界面線(xiàn)程里做否則視頻流一幀要卡幾百毫秒界面直接假死。主窗口類(lèi)核心代碼如下class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(YOLOv8 人體檢測(cè)識(shí)別計(jì)數(shù)系統(tǒng)) self.setMinimumSize(1280, 720) # 主布局 self.video_label QLabel(請(qǐng)打開(kāi)視頻或攝像頭) self.video_label.setAlignment(Qt.AlignCenter) self.video_label.setStyleSheet(background-color: #1e1e1e; color: white;) self.count_label QLabel(當(dāng)前人數(shù): 0) self.time_label QLabel(檢測(cè)耗時(shí): 0 ms) self.open_image_btn QPushButton(打開(kāi)圖片) self.open_video_btn QPushButton(打開(kāi)視頻) self.open_camera_btn QPushButton(打開(kāi)攝像頭) self.stop_btn QPushButton(停止檢測(cè)) self.export_btn QPushButton(導(dǎo)出結(jié)果) # 參數(shù)控制 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) # 檢測(cè)線(xiàn)程 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) # 左側(cè)視頻區(qū)域 left_layout QVBoxLayout() left_layout.addWidget(self.video_label) layout.addLayout(left_layout, stretch4) # 右側(cè)控制區(qū)域 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, stretch1) # 信號(hào)連接 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 幀轉(zhuǎn)換為 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當(dāng)前人數(shù): {count}) self.time_label.setText(f檢測(cè)耗時(shí): {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, confself.conf_spin.value(), iouself.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)圖中代碼是簡(jiǎn)化的主窗口。實(shí)際使用時(shí)建議把模型路徑、輸入源、線(xiàn)程狀態(tài)管理寫(xiě)得更嚴(yán)謹(jǐn)比如打開(kāi)攝像頭前先停止當(dāng)前檢測(cè)線(xiàn)程再重新創(chuàng)建。6. 功能測(cè)試與效果驗(yàn)證6.1 圖片檢測(cè)測(cè)試測(cè)試目的驗(yàn)證模型能否正確識(shí)別圖片中的行人并統(tǒng)計(jì)數(shù)量。操作步驟啟動(dòng)系統(tǒng)點(diǎn)擊打開(kāi)圖片。選擇一張人流較多的圖片。觀察右側(cè)人數(shù)統(tǒng)計(jì)和檢測(cè)耗時(shí)。預(yù)期結(jié)果畫(huà)面中出現(xiàn)的人體都被矩形框標(biāo)出右側(cè)顯示的人數(shù)和圖片中實(shí)際人數(shù)基本一致。判斷標(biāo)準(zhǔn)檢測(cè)出的人數(shù)誤差是否在可接受范圍內(nèi)。如果漏檢嚴(yán)重降低置信度閾值如果誤檢多提高置信度閾值。6.2 視頻文件檢測(cè)測(cè)試測(cè)試目的驗(yàn)證系統(tǒng)在連續(xù)幀上的穩(wěn)定性和計(jì)數(shù)變化。操作步驟點(diǎn)擊打開(kāi)視頻選擇一個(gè) mp4 文件。觀察視頻播放過(guò)程中人數(shù)統(tǒng)計(jì)是否實(shí)時(shí)更新。注意畫(huà)面是否卡頓。預(yù)期結(jié)果視頻流暢播放每幀畫(huà)面中的人數(shù)隨著行人進(jìn)出而變化。判斷標(biāo)準(zhǔn)視頻處理幀率能否達(dá)到 15 FPS 以上。如果幀率太低考慮換更小的模型yolov8n或降低輸入分辨率。6.3 攝像頭實(shí)時(shí)檢測(cè)測(cè)試測(cè)試目的驗(yàn)證攝像頭輸入源的實(shí)時(shí)性。操作步驟點(diǎn)擊打開(kāi)攝像頭。在攝像頭前走動(dòng)觀察檢測(cè)框是否跟隨人體移動(dòng)。記錄檢測(cè)耗時(shí)。預(yù)期結(jié)果系統(tǒng)能以準(zhǔn)實(shí)時(shí)的速度對(duì)攝像頭畫(huà)面進(jìn)行檢測(cè)。判斷標(biāo)準(zhǔn)從畫(huà)面變化到檢測(cè)框更新的延遲是否在可接受范圍內(nèi)。CPU 推理延遲會(huì)明顯高于 GPU。6.4 密集場(chǎng)景測(cè)試這是這套系統(tǒng)的核心功能驗(yàn)證。選擇一張人流非常密集的圖片比如地鐵通道、景區(qū)門(mén)口觀察小目標(biāo)漏檢情況。遠(yuǎn)處的人體很小模型能否識(shí)別出來(lái)。人群互相遮擋時(shí)能否區(qū)分不同個(gè)體。計(jì)數(shù)結(jié)果與人工計(jì)數(shù)的差距。如果密集場(chǎng)景效果差優(yōu)先在更高分辨率下推理imgsz960或imgsz1280或者使用 YOLOv8m/YOLOv8l 等更大的模型。7. 接口 API 與批量任務(wù)如果你想把檢測(cè)能力集成到其他系統(tǒng)里可以單獨(dú)封裝一個(gè)檢測(cè)服務(wù)。這里給兩個(gè)方案。7.1 Python 函數(shù)封裝最簡(jiǎn)單的 API 就是一個(gè)函數(shù)from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) def detect_persons(image_path, conf_thres0.25, iou_thres0.45): results model(image_path, confconf_thres, iouiou_thres, verboseFalse) 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}調(diào)用result detect_persons(crowd.jpg) print(總?cè)藬?shù):, result[total])7.2 HTTP 接口服務(wù)用 FastAPI 把檢測(cè)封裝成 HTTP 服務(wù)方便跨語(yǔ)言調(diào)用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, verboseFalse) 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}啟動(dòng)服務(wù)uvicorn api_server:app --host 0.0.0.0 --port 8000測(cè)試請(qǐng)求curl -X POST -F filetest.jpg http://127.0.0.1:8000/detect7.3 批量圖片檢測(cè)批量處理任務(wù)建議加上進(jìn)度記錄和失敗重試邏輯。核心思路遍歷目錄下所有圖片逐張推理結(jié)果保存到輸出目錄并按原文件名命名同時(shí)生成一個(gè) 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_okTrue) results_csv [] for img_path in input_dir.glob(*.jpg): try: results model(img_path, conf0.25, verboseFalse) 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)批量任務(wù)做得再完善一點(diǎn)可以加多線(xiàn)程并行推理或者將任務(wù)拆分成多個(gè)批次交給 GPU 排隊(duì)處理。8. 資源占用與性能觀察資源占用是實(shí)際部署時(shí)最需要關(guān)心的部分。雖然沒(méi)有統(tǒng)一的數(shù)字可以套用但可以給出觀察方法和調(diào)優(yōu)方向。8.1 顯存占用怎么看訓(xùn)練和推理時(shí)用 NVIDIA 官方工具查看nvidia-smiLinux 上還可以用實(shí)時(shí)監(jiān)控watch -n 1 nvidia-smiWindows 上 Task Manager 的 GPU 頁(yè)簽也能看到顯存占用。8.2 模型大小對(duì)性能的影響模型參數(shù)量推理速度精度適用環(huán)境YOLOv8n最小最快較低嵌入式設(shè)備、實(shí)時(shí)性要求高YOLOv8s小較快中上消費(fèi)級(jí) GPU、通用場(chǎng)景YOLOv8m中中等較高高精度需求YOLOv8l/x大較慢高服務(wù)器端離線(xiàn)處理選擇建議實(shí)時(shí)視頻流優(yōu)先 yolov8s 或 yolov8n密集小目標(biāo)圖片優(yōu)先 yolov8m 以上并結(jié)合 imgsz960 甚至 1280。8.3 推理性能關(guān)鍵參數(shù)輸入分辨率直接決定推理速度和顯存占用。640 和 1280 相比推理時(shí)間可能差 3~4 倍。batch size 對(duì)單張圖片推理沒(méi)有意義但對(duì)批量任務(wù)影響很大。GPU 在 batch 越大時(shí)效率越高。CPU 推理時(shí)輸入分辨率對(duì)速度的影響更大建議密集場(chǎng)景先用預(yù)處理裁切而不是整張大圖直接推理。8.4 PyQt5 界面性能優(yōu)化視頻流界面卡頓有兩個(gè)常見(jiàn)原因一是推理線(xiàn)程耗時(shí)太長(zhǎng)二是 QImage 轉(zhuǎn)換和 QPixmap 縮放消耗過(guò)多 CPU。優(yōu)化方向推理線(xiàn)程只負(fù)責(zé)推理和畫(huà)框不負(fù)責(zé)界面縮放。顯示幀進(jìn)行降采樣。比如推理分辨率是 1280顯示時(shí)縮放到 720p。使用QLabel.setPixmap前先判斷畫(huà)面尺寸是否有變化避免重復(fù)縮放。幀率控制不是每幀都要做檢測(cè)可以隔幀檢測(cè)界面顯示原幀和最近一次檢測(cè)結(jié)果。9. 常見(jiàn)問(wèn)題與排查方法實(shí)際部署中遇到最多的問(wèn)題集中在這幾類(lèi)問(wèn)題現(xiàn)象可能原因排查方式解決方案安裝 ultralytics 失敗Python 版本過(guò)高或依賴(lài)沖突查看 pip 報(bào)錯(cuò)日志使用 Python 3.9~3.11重新創(chuàng)建虛擬環(huán)境CUDA available 為 FalsePyTorch 版本和驅(qū)動(dòng)不匹配運(yùn)行nvidia-smi查看驅(qū)動(dòng)版本安裝匹配 CUDA 版本的 PyTorch訓(xùn)練時(shí)顯存不足batch 太大或 imgsz 太大查看 nvidia-smi 顯存占用降低 batch 或 imgsz開(kāi)啟梯度累積檢測(cè)漏檢嚴(yán)重置信度閾值過(guò)高、模型過(guò)小、輸入分辨率不足查看置信度分布降低 conf 到 0.15換大模型提高 imgsz誤檢多置信度閾值太低、場(chǎng)景復(fù)雜查看誤檢框置信度提高 conf增加負(fù)樣本訓(xùn)練視頻流卡頓推理耗時(shí)太長(zhǎng)、顯示刷新阻塞統(tǒng)計(jì)每幀推理耗時(shí)換小模型、降分辨率、隔幀檢測(cè)PyQt5 界面打不開(kāi)依賴(lài)缺失或 Python 環(huán)境問(wèn)題終端運(yùn)行看報(bào)錯(cuò)重裝 PyQt5檢查 QT_QPA_PLATFORM攝像頭打不開(kāi)攝像頭索引錯(cuò)誤、權(quán)限不足用 cv2.VideoCapture 單獨(dú)測(cè)試檢查設(shè)備索引Windows 可嘗試 0/1/2批量任務(wù)中途失敗單張圖片損壞、內(nèi)存溢出查看異常日志增加 try/except逐張保存結(jié)果模型文件缺失權(quán)重路徑錯(cuò)誤或未下載完成檢查路徑和文件大小重新下載權(quán)重確認(rèn)路徑正確重點(diǎn)說(shuō)兩個(gè)常見(jiàn)坑第一個(gè)是 PyTorch 和 CUDA 版本不匹配。很多用戶(hù)裝完 PyTorch 后發(fā)現(xiàn)torch.cuda.is_available()是 False。解決方法是先查驅(qū)動(dòng)支持的 CUDA 版本再安裝對(duì)應(yīng) PyTorch。最新的 NVIDIA 驅(qū)動(dòng)一般能兼容 CUDA 12.x 系列直接安裝 cu121 或 cu124 的 PyTorch 通常沒(méi)問(wèn)題。第二個(gè)是 PyQt5 界面閃退或空白。這個(gè)問(wèn)題在高 DPI 縮放和多顯示器場(chǎng)景下很常見(jiàn)。可以在主程序入口加上import os os.environ[QT_AUTO_SCREEN_SCALE_FACTOR] 1如果畫(huà)面閃爍或顯示異??梢試L試調(diào)整QImage.Format或檢查bytes_per_line是否計(jì)算正確。10. 最佳實(shí)踐與使用建議這套系統(tǒng)從原型到真實(shí)可用中間還有很多細(xì)節(jié)。結(jié)合我的經(jīng)驗(yàn)給幾條工程化建議。第一第一次跑通流程用最小配置。先拿一張圖片用官方預(yù)訓(xùn)練模型跑通 PyQt5 界面再逐步加視頻、攝像頭、自定義模型。一步到位容易出問(wèn)題排查起來(lái)也麻煩。第二模型、數(shù)據(jù)集、輸出結(jié)果分目錄管理。推薦目錄結(jié)構(gòu)project/ ├── models/ # 訓(xùn)練好的權(quán)重文件 ├── dataset/ # 訓(xùn)練數(shù)據(jù)集 ├── images/ # 測(cè)試圖片 ├── videos/ # 測(cè)試視頻 ├── runs/ # YOLOv8 訓(xùn)練和推理日志 ├── ui/ # PyQt5 界面代碼 └── main.py # 主程序入口第三批量任務(wù)一定要加日志。每一張圖片的處理狀態(tài)、結(jié)果、耗時(shí)都記錄到日志文件里。處理幾千張圖片時(shí)沒(méi)有日志根本沒(méi)法定位是哪些圖片出了問(wèn)題。第四接口服務(wù)要限制訪(fǎng)問(wèn)范圍。如果封裝成 HTTP API至少設(shè)置--host 127.0.0.1只允許本機(jī)訪(fǎng)問(wèn)或者加上簡(jiǎn)單的 Token 驗(yàn)證。直接暴露在公網(wǎng)非常危險(xiǎn)。第五涉及人臉、聲音、版權(quán)素材時(shí)必須確認(rèn)授權(quán)。這套系統(tǒng)檢測(cè)的是行人整體不涉及人臉識(shí)別但在公共區(qū)域部署仍然需要符合當(dāng)?shù)乇O(jiān)控和數(shù)據(jù)管理規(guī)定。不要在未經(jīng)授權(quán)的情況下采集和存儲(chǔ)可識(shí)別個(gè)人的數(shù)據(jù)。第六發(fā)布或商用前要做效果復(fù)核。訓(xùn)練集上的指標(biāo)再好也不代表現(xiàn)場(chǎng)效果沒(méi)問(wèn)題。拿一段真實(shí)場(chǎng)景的視頻跑一遍統(tǒng)計(jì)誤檢率、漏檢率再?zèng)Q定是否上線(xiàn)。11. 總結(jié)與下一步這套基于 YOLOv8 PyQt5 的人體檢測(cè)系統(tǒng)最值得嘗試的點(diǎn)是它把模型訓(xùn)練、桌面界面和實(shí)際業(yè)務(wù)場(chǎng)景串在了一條完整的鏈路上。從數(shù)據(jù)集準(zhǔn)備、模型微調(diào)到 PyQt5 界面開(kāi)發(fā)、視頻流檢測(cè)、批量任務(wù)處理每一步都是可落地的。最先要驗(yàn)證的功能是圖片檢測(cè)和視頻檢測(cè)的基礎(chǔ)流程。用官方預(yù)訓(xùn)練模型跑通后再換自己的數(shù)據(jù)集微調(diào)。最容易踩的坑是環(huán)境配置階段的 CUDA 版本不匹配以及 PyQt5 界面渲染的性能瓶頸。后續(xù)可以繼續(xù)擴(kuò)展的方向也很多接入更復(fù)雜的跟蹤算法如 ByteTrack 或 DeepSORT 實(shí)現(xiàn)跨幀人數(shù)統(tǒng)計(jì)和軌跡繪制增加 ROI 區(qū)域設(shè)定只統(tǒng)計(jì)指定區(qū)域的人群密度接入 RTSP 流做多路攝像頭并發(fā)處理或者把 PyQt5 界面替換成 Web 界面統(tǒng)一管理多臺(tái)檢測(cè)設(shè)備。這套系統(tǒng)的價(jià)值不只是演示目標(biāo)檢測(cè)而是提供了一個(gè)完整的多功能桌面應(yīng)用開(kāi)發(fā)模板值得你動(dòng)手試一試。