
簡介計算機視覺中的目標檢測技術旨在讓機器從圖像或視頻中定位并識別特定物體。以YOLO系列為代表的深度學習模型憑借出色的精度與速度平衡成為視頻監控場景下行人檢測的主流方案。通過遷移學習、非極大值抑制以及跨幀IOU關聯等核心機制可將連續幀中的檢測結果轉換為穩定的人流計數實現瞬時人數與累計流量的實時統計。結合PyTorch、OpenCV等工具鏈開發者能夠搭建完整的可視化系統并針對誤檢、漏檢和推理速度等問題進行工程優化。該技術廣泛應用于商場、景區、交通樞紐等公共區域的人流監測與安全預警。本文以一套基于深度學習的人流量檢測系統為例系統拆解YOLO目標檢測、計數邏輯、界面開發及部署優化要點幫助讀者快速掌握從模型原理到工程落地的完整路徑。 寫這篇東西之前我先說個背景。每年畢業季人流量檢測系統都是畢設題目的常客因為它的覆蓋面足夠廣深度學習、Python、目標檢測、圖像處理、界面開發該有的技術棧全都有而且展示效果直觀答辯時屏幕上實時跳出檢測框和計數數字老師一看就知道你做的是什么東西。但我也看過太多人卡在同一個地方——代碼能跑但不知道每一步在干什么模型能出框但計數邏輯漏洞百出界面能打開但換個視頻就崩。這套“基于深度學習的人流量檢測系統設計與實現”的Python源碼加項目說明整套東西我看下來本質上是一個標準的“目標檢測 跨幀計數 可視化展示”三段式架構。它解決的痛點是在一段監控視頻或實時攝像頭畫面里自動識別出“人”這個目標并統計出當前人數、累計人流量最后通過界面呈現給用戶。適合的人群很明確正在做人流量檢測相關畢設的學生以及想用Python快速搭一個目標檢測計數原型來做技術驗證的開發者。我需要把里面一些值得展開的技術細節和實際踩坑經驗說清楚幫你看懂這套系統是怎么設計的以及哪些地方可以做到更好。1. 項目整體設計與技術選型拆解1.1 畢設需求拆解不只是“檢測出人”這么簡單很多同學一上來就奔著“把人的框畫出來”去做完才發現工作量不夠答辯的時候沒有什么可講的。這套畢設的聰明之處在于它把“人流量檢測”拆成了三個遞進的需求層級。第一層是“有沒有人”這就是純目標檢測要做的事用YOLO或同類模型在每一幀畫面中找出人的位置輸出邊界框和置信度。第二層是“有多少人”這個分兩種口徑當前畫面的人數瞬時人數和一段時間內累計經過的人數流量。瞬時人數很好算直接統計當前幀的檢測框數量就行但累計流量就得靠跨幀關聯來做否則同一個人在畫面里走了10秒你把他算了10次這個數字就沒有意義了。第三層是“給你看什么”輸出不能只是終端里的一串坐標得有一個可視化界面實時顯示檢測結果、計數曲線最好還能處理視頻文件和攝像頭信號。我建議你在做任何同類項目前也先把這三層目標寫清楚。因為每一層對應的技術方案是完全不同的檢測用YOLO跟蹤用IOU匹配或DeepSORT界面用Flask或PyQt混在一起做容易做成一鍋粥拆開之后才能逐個擊破。1.2 技術選型對比為什么是YOLO系列為什么是PyTorch這套系統源碼里用的模型是YOLO系列的某個版本配套PyTorch框架Python版本要求在3.8以上。這個選擇在2024、2025年的環境下依然是非常理性的。先看目標檢測模型怎么選。對比過三套方案的同學應該有體感Faster R-CNN精度上限確實高尤其是小目標場景但速度太慢一幀需要幾十甚至上百毫秒實時視頻流基本撐不住。畢設現場演示的時候畫面一卡頓老師的第一印象就打折扣了。SSD速度不錯但小目標檢測能力偏弱人流量場景經常出現遠處的人很小的情況SSD容易漏檢。YOLO系列v5/v8/v9等精度和速度的平衡點在所有主流模型里做的是最好的訓練生態成熟預訓練權重好找部署簡單Python直接能調對畢設來說是最穩的選項。再看深度學習框架。這套源碼用的是PyTorch不是TensorFlow。原因很簡單PyTorch的調試體驗對畢設選手來說友好太多模型結構print出來一目了然動態圖機制讓中間層的輸出隨時可見。而TensorFlow的靜態圖機制遇到報錯時排查成本比較高。另外PyTorch的模型權重zoo比如Ultralytics YOLO的各種預訓練模型下載方便社區活躍度也高遇到問題一搜就能找到解決方案。選PyTorch還有一個現實原因如果你后續想用TensorRT做推理加速后面我會講PyTorch模型轉ONNX再轉TensorRT的鏈路已經非常成熟資料多坑少。這一點在做性能優化時非常重要。1.3 系統整體架構五層分流各司其職有了需求拆解整體架構自然就出來了。這套系統基本是按經典的五層結構來組織的數據輸入層讀取視頻文件或調用攝像頭OpenCV的VideoCapture推流格式統一轉成BGR幀。預處理層把每一幀縮放、歸一化、轉Tensor喂給模型前還需要確認通道順序、數值范圍是否符合模型訓練的分布。推理層加載訓練好的模型權重執行前向計算輸出檢測框坐標、置信度、類別ID。后處理與業務邏輯層把模型的原始輸出解析成人類可讀的框NMS去重、維護跟蹤ID、累積流量計數。展示層用PyQt或Web前端把畫了框的畫面、實時人數曲線、歷史統計報表展示出來。這套分層的好處是模塊之間解耦得很干凈。你不想用PyQt可以把展示層整個換成Flask寫Web界面不影響其他代碼。你想替換模型推理層內部換一下加載邏輯上層完全不用動。我見過太多畢設代碼把模型推理、畫框、計數全寫在同一個函數里200行一個函數帶著一堆全局變量看起來“寫得快”但后期改一個參數都要提心吊膽。2. 核心算法原理模型在做什么你心里要有數2.1 從卷積到池化網絡怎么“看見”一個人聊人流量檢測繞不開深度學習視覺基礎。這套源碼用的YOLO模型Backbone部分是卷積分層提取特征的網絡。卷積的作用是讓網絡在圖像的不同位置尋找局部模式比如邊緣、紋理、顏色組合淺層網絡找的是線和角深層網絡才能把這些局部模式組合成“人的頭肩形狀”“人的整體輪廓”這種語義信息。這里面有一個每個做畢設的人都應該能回答上來的概念池化。我們常說的深度學習的池化Pooling本質上就是下采樣。類比來說一張1080p的圖片如果用MaxPooling做2x2降采樣等于把每2x2的小塊里最大的那個值留下其他三個丟掉圖片變成540p。網絡對特征的敏感度不會因為這種“抽稀”而丟失太多反而獲得了兩大好處一是計算量大幅下降二是網絡對目標在畫面中的小幅偏移不再那么敏感這也就是我們說的平移不變性。在人群中做檢測人的位置總是千變萬化的我們希望網絡不管人在畫面左邊還是右邊都能穩定識別出“這是人”池化在這方面功不可沒。YOLO的Neck部分會用特征金字塔結構把淺層的細粒度位置信息和深層的強語義信息融合在一起。這就是為什么YOLO能同時檢測畫面里的大人和遠處的小人。你喂進去的圖片分辨率越高小目標檢測能力越強但推理速度成反比。這套系統里我建議用YOLO官方推薦的默認輸入尺寸通常在640x640左右這個尺寸對“中等密度的人群”場景足夠用。2.2 預訓練權重與遷移學習為什么你的模型收斂得這么快這套系統的訓練過程完全不是從零開始“煉丹”而是用COCO數據集上的預訓練權重做遷移學習。這是整套項目里最聰明的“省力點”。很多人第一次訓練深度學習模型習慣性地從隨機初始化的權重開始訓然后發現loss怎么也降不下來或者訓練了50個epoch還在震蕩。問題出在哪隨機初始化的網絡對圖像完全沒有任何先驗知識一切都需要從零學而任務本身又復雜數據量又沒那么大很容易過擬合或欠擬合。遷移學習的邏輯很樸素一個已經在COCO這種百萬級數據集上見過海量圖像的模型已經把“邊緣怎么提取”“紋理怎么組合成物體”這些東西學得差不多了。你把它加載進來凍結前幾層Backbone只需要訓練后面幾層和檢測頭讓它適應“人”類別的細分特征就行了。這套人流量檢測系統里默認就使用了從COCO遷移來的YOLO預訓練權重所以即使你自己的數據集只有幾百上千張圖訓練一二十個epoch也能收斂到不錯的精度。實操上有一個調參細節遷移學習時學習率要調低。隨機初始化的模型可以用1e-3甚至1e-2的學習率因為梯度方向變動大需要大步幅探索遷移學習狀態下權重已經在一個相對較優的局部區域小幅更新即可建議從1e-4起步用余弦退火逐步降低效果會比恒定的較大學習率好很多。2.3 NMS去重同一個人為什么會被框好幾次用過YOLO的同學都知道模型對同一個目標通常會輸出多個重疊的檢測框尤其目標密集的時候一個行人可能同時被三四個框命中置信度還都很高。如果不處理畫面里一個人頭上頂三四個框計數直接翻倍。YOLO的后處理用的標準方案是NMS非極大值抑制思路其實很簡單把置信度最高的框保留把其它和這個框重疊度太高IOU超過閾值的框剔除然后對剩下的框重復這個過程直到所有框都遍歷完。IOU就是兩個框的交集面積除以并集面積數值范圍0到1。NMS的閾值選擇有講究默認0.4到0.5之間比較穩妥。閾值設低了兩個挨得近的人可能被合并成一個框導致漏檢閾值設高了同一個人身上的重復框又清不干凈。在人流量這種密集人群場景我建議從0.45起步多拿幾幀實際畫面測一下看哪個人群的“粘連”問題最嚴重再去微調。2.4 從檢測到計數跨幀關聯的邏輯真正的“人流量”不是看某一幀有多少人而是要統計在一段時間內有多少人從畫面中經過。這套系統實現的是比較基礎的方案基于位置IOU的幀間關聯。核心邏輯是這樣的對上一幀的每個檢測框在當前幀的檢測框中找IOU最大的那個作為自己的“下一幀位置”如果最大IOU超過閾值比如0.3則認為這是同一個目標保留同一個TrackID如果沒有找到匹配則可能是個新人進入畫面分配一個新的TrackID如果某個TrackID連續多幀沒有匹配成功就認為這個人離開了畫面從追蹤池里刪除。這種純IOU匹配的方法在固定攝像頭、人流量密度不是特別高、人群移動速度平緩的場景下實測效果是夠用的。但如果畫面里的人來回走動、互相遮擋頻繁純IOU會頻繁丟ID或者誤配。想要在實測中增加ID穩定性可以考慮兩步優化第一步在匹配時加上“位置預測”環節用卡爾曼濾波根據前幾幀的速度外推出當前幀該位置在哪再去做IOU匹配第二步在匹配特征上不只看框的位置從檢測框內提取一個簡單的表觀特征顏色直方圖位置相近且顏色也接近的框才認為是同一人。這兩步加到代碼里TrackID的穩定性會有質的提升。這里有一個“計數口徑”的細節需要特別注意。你要在代碼里明確區分“瞬時人數”和“累計流量”兩個統計量。瞬時人數看當前幀跟蹤池里有幾個活著的TrackID累計流量看的是系統啟動至今創建過的TrackID總數。如果代碼里把這兩個概念混了你會發現“累計數量”反復跳來跳去因為你把當前幀的瞬時數量累加進去了。這套系統的說明文檔里專門對這兩個量做了區分我建議你也把系統輸出的字段名設計成current_count和total_count一眼就能分清。3. 實操落地從源碼到跑通系統的關鍵環節3.1 環境搭建版本對應關系是最大的坑拿到這套源碼第一步不是跑代碼而是把Python環境搭好。這里我總結一份經過驗證的環境對應表你照著配基本都是穩的組件推薦版本備注Python3.8 ~ 3.11建議3.9或3.10兼容性最好PyTorch1.13 ~ 2.2CPU版可以直接跑但速度慢推薦CUDA版CUDA11.8 或 12.1必須和PyTorch版本匹配cuDNN與CUDA配套8.x以上OpenCV4.5以上視頻讀寫、圖像預處理Ultralytics對應模型版本如果用YOLOv8直接用pip install ultralytics我拆這套系統時最大的坑就是CUDA版本和PyTorch版本的匹配問題。很多同學在Windows上裝了最新CUDA 12.4然后pip install torch默認裝了一個需要CUDA 12.1的包兩者不匹配torch.cuda.is_available()直接返回False程序只能跑CPU視頻流推理一幀要好幾百毫秒。查這個問題最簡單的辦法就是進入Python環境跑一句print(torch.cuda.is_available())如果輸出False優先去PyTorch官網找到對應CUDA版本的安裝命令用pip重裝而不是自己去折騰系統CUDA。再說說Linux環境。Ubuntu 22.04、24.04這些系統上配置深度學習環境時最容易出的問題就是顯卡驅動裝了沒反應。這個現象的常見原因是NVIDIA驅動下載了但沒進入命令行模式安裝或者nouveau開源驅動沒禁用干凈。你直接跑nvidia-smi看看有沒有輸出如果沒有任何信息大概率驅動沒裝上。網上那些Ubuntu配置教程里第一步基本都會要求禁用nouveau這個步驟別跳過否則后面裝CUDA大概率裝出個半殘狀態。裝完驅動重啟后如果nvidia-smi正常顯示顯卡信息和驅動版本再繼續裝CUDA和PyTorch順序反了會非常痛苦。3.2 數據集準備與標注不想標注就用這幾套公開數據這套源碼里沒有內置訓練數據集因為它默認了你的場景是“通用人流量檢測”這類場景完全可以不自己標注直接用公開數據集。我按使用優先級排個序COCO數據集的相關子集包含人這個類別person的標注數量充足直接取person類別訓練效果實測最好。CrowdHuman專門為密集人群檢測設計的數據集每個人頭都有標注適合人群密度大的場景。但它的標注風格偏頭肩框和常規人體框不完全一致需要做一點格式轉換。MOT17 / MOT20這個主要是做多目標跟蹤的數據集也可以用它的檢測標簽來訓練檢測器優點是一段視頻內同一個人有多個連續ID能順便為跟蹤環節提供測試數據。如果你確實需要自建數據集標注工具用LabelImg或者Labelme都行用LabelImg標注檢測框更順手。標注時有一條經驗只標完整可見的人被擋超過一半的人不要硬標。部分遮擋在密集人群中是常態但標注數據里如果混入了大量半截人模型學到的東西會很混亂。3.3 模型訓練看懂訓練配置比自己瞎調強這套系統的訓練腳本里各種超參數默認是寫好的。調參的方向可以按照重要程度來排序最核心的是batch size和輸入分辨率。batch size受顯存限制一般8到16之間比較合理顯存不夠就調小但別小于4否則訓練不穩定。輸入分辨率從640提升到960小目標檢測精度會明顯提升代價是訓練和推理速度都會下降取舍要看你的場景。其次是epoch數。用預訓練權重遷移學習我實測10到15個epoch基本就能收斂日志里看val/box_loss不再下降就可以了。不用硬湊50個epoch純屬浪費時間。學習率建議從0.001開始配合余弦退火優化器選SGD或AdamW都行但用SGD做目標檢測是經典路線收斂比較穩AdamW適合訓練中有大量不規則樣本的情況。數據增強方面如果你的場景是室內固定攝像頭建議關閉過強的旋轉增強因為固定攝像頭畫面里人很少旋轉90度增強過于激進反而會讓模型學到扭曲的人形。我在實測中遇到過類似問題開了強Mosaic增強后模型在真實視頻上誤檢率變高把桌腿當成人。后來把Mosaic關閉、只保留尺度抖動和輕微平移誤檢少了大半。3.4 實時檢測與計數模塊核心代碼不長但邏輯要清晰這套源碼的核心推理部分把預加載模型、逐幀推理、后處理、計數邏輯、畫框、統計展示串在一起。我把精煉后的核心骨架整理如下你可以對著源碼看逐行對照理解import cv2 import torch from ultralytics import YOLO # 加載訓練好的模型權重文件放models目錄 model YOLO(models/yolov8n_custom.pt) # 當前追蹤幀的檢測目標池 tracked_objects {} next_id 0 total_count 0 cap cv2.VideoCapture(test_video.mp4) while cap.isOpened(): ret, frame cap.read() if not ret: break results model.predict(frame, conf0.45, iou0.45, classes[0], verboseFalse) boxes results[0].boxes.xyxy.cpu().numpy() scores results[0].boxes.conf.cpu().numpy() # 用IOU做幀間匹配給同一目標分配同一個track_id current_ids [] for box, score in zip(boxes, scores): x1, y1, x2, y2 box.astype(int) best_iou 0.0 best_id None for tid, tbox in tracked_objects.items(): iou compute_iou([x1, y1, x2, y2], tbox) if iou best_iou: best_iou iou best_id tid if best_id is not None and best_iou 0.3: tracked_objects[best_id] [x1, y1, x2, y2] current_ids.append(best_id) else: tracked_objects[next_id] [x1, y1, x2, y2] current_ids.append(next_id) next_id 1 total_count 1 # 清理超過一定幀數沒有匹配的舊目標 # 這一步在源碼里會單獨維護hit_count和miss_count current_count len(set(current_ids)) # 繪制檢測框和統計信息 # 畫框、寫current_count和total_count到畫面上 cap.release()代碼里每個關鍵部分的意圖我展開說一下。model.predict這一步conf和iou分別是置信度閾值和NMS閾值classes[0]表示只檢測類別0在COCO里person就是0如果你自己做的人流量系統需要檢測多類需要去掉這個限制。compute_iou是兩個框重疊度的計算函數它決定同一目標能不能被關聯上閾值0.3到0.5都有人用密集人群建議0.3否則同一個人位置稍微挪一下匹配就斷了。total_count每新生有效track_id加1這就是“流量”的真實口徑。3.5 界面層Flask和PyQt怎么選這套源碼提供的是基于PyQt5的桌面端界面。做畢設有兩套主流方案都值得考慮PyQt5桌面端的優勢是調度簡單直接把攝像頭或視頻畫面顯示在窗口里按鈕點擊事件綁定到“開始檢測”“停止檢測”這些回調函數不需要起服務、不需要管端口現場演示不容易出岔子。劣勢是UI樣式比較陳舊做不出特別炫酷的儀表盤效果。Flask Web端的優勢是展示層級豐富可以把實時畫面推到網頁上同時用ECharts畫人流曲線、用熱力圖展示人多的區域答辯視覺效果拉滿。劣勢是多了一層WebSocket或AJAX通信代碼量上去了調試復雜度也高了。我給你的建議是圖省心用PyQt圖效果用Flask。兩者共用一套核心檢測計數邏輯只需要在展示層做適配。如果你想在答辯時讓老師眼前一亮Flask ECharts的實時人流曲線圖可比單純畫框直觀太多了。4. 常見問題與排查技巧實錄4.1 環境類問題速查表這里是我實測過程中整理的一份排錯對照表按“癥狀 - 病因 - 處理”三列展開癥狀病因處理torch.cuda.is_available()返回FalsePyTorch和CUDA版本不匹配去PyTorch官網找對應命令重裝推理時提示顯存不足CUDA out of memorybatch size或分辨率過大調低輸入分辨率或改推理時用半精度float16視頻打不開報VideoCapture錯誤OpenCV沒有對應視頻編解碼器安裝opencv-python或ffmpeg完整版換視頻格式訓練時loss為NaN學習率過大或數據里有異常值降低學習率檢查標注框是否有坐標越界模型預測一直輸出空結果置信度閾值設得過高把conf降到0.25甚至0.1看輸出Ubuntu裝好驅動后nvidia-smi無輸出驅動沒裝成功或nouveau未禁用重新安裝NVIDIA驅動確認禁用nouveau后重啟4.2 誤檢漏檢人群場景里最常見的兩類問題人流量檢測的誤檢在公開場合下最典型的目標是“廣告牌上的人像”模型會把海報里的明星當成人。這不是模型壞了是訓練數據里真實行人樣本和圖片里的行人樣本沒有被區分。一個可行的處理方法是針對你的部署場景收集一些背景幀加入訓練集并標注為空讓模型學習“這個位置的這個人不是目標”。這個方法在固定攝像頭場景下非常有效。漏檢則主要發生在小目標上。畫面遠處的人可能只有十幾個像素高網絡下采樣之后特征已經消失了。應對方案有三個方向一是把輸入分辨率提高到960或1280代價是速度二是調整模型結構中的錨框尺寸讓網絡輸出更多小尺度預測框三是在后處理上把置信度閾值降下來接受更多低置信度框再靠NMS去重。三者結合小目標漏檢率通常能降一半以上。4.3 推理速度優化從12FPS到30FPS做了什么性能問題在畢設現場最容易翻車。原始代碼用CPU推理時YOLOv8n的640分辨率在普通筆記本上大約只有3-6FPS畫面像幻燈片。做三步優化速度就能到可接受的范圍第一步換GPU推理。即使是一張GTX 1660或RTX 3050也能把幀率拉到20FPS以上。如果用的是NVIDIA顯卡記得在代碼里顯式指定device為cuda或0讓模型在GPU上跑。第二步轉ONNX后用TensorRT推理。這一步比較復雜但能把推理速度再提升2-3倍RTX 3060上用TensorRT跑YOLOv8s可以做到30FPS以上。第三步降分辨率。把輸入從640降到416檢測精度會有輕微下降但速度提升明顯。如果你做的是室內近距離場景416足夠用。4.4 畢設答辯高頻提問提前準備這5個問題這套系統做完之后答辯環節老師大概率會問這幾個方向的問題提前準備好就能從容應對第一個問題“你用的模型和其他模型比為什么選它”這個問題要用數據說話列出YOLO的mAP和推理速度對比Faster R-CNN和SSD的差異結合作答。第二個問題“人流統計的準確率怎么評估”這是一個關鍵點。建議準備一個測試集人工數出視頻里的真實人流量和系統輸出的total_count做對比算一個誤差率。有個實際數字比空口說“準確率挺高”有說服力得多。第三個問題“如果兩個人并排走系統會不會把他們數成一個人”這個問題考察的是后處理邏輯需要解釋清楚NMS只合并同一個目標的重復框而IOU跟蹤匹配則是按位置關聯不同幀的目標并排走的兩個人位置相鄰但IOU通常不會超過匹配閾值所以不會被合并。第四個問題“這個系統能安裝在移動端或嵌入式設備上嗎”這個考察工程化能力可以回答“可以但需要做模型輕量化和TensorRT/ONNX部署優化”然后把模型剪枝、量化這些名詞拋出來老師就知道你思考過部署問題。第五個問題“數據集的構建過程是怎樣的”把你的數據集來源、標注數量、類別分布說清楚再提一句“對固定場景做了背景幀補充”就能證明你不是直接拿預訓練模型跑了個demo而是做了實際的工程訓練。5. 如果項目要再往前走一步進階方向這套畢設的框架完整度已經足夠但如果你是抱著“不止為了交差”的心態來做還有幾個擴展方向很值得做人流密度估算是比目標檢測更適合密集場景的技術路線。檢測法在人群嚴重遮擋時天然吃虧而基于密度圖的計數回歸方法比如CSRNet直接把圖像回歸到人群密度圖再把密度圖積分得到人數它在密集場景下的魯棒性明顯更好。缺點是邊界框信息沒了你只能知道有多少人不知道每個人在哪。檢測和密度估計結合做一幀里先用密度圖判斷擁擠程度再用檢測框做個體識別是現在工業級產品的主流玩法。區域熱度分析也很有價值。把畫面網格化統計每個格子累積出現目標的時長生成一張熱力圖可以直觀看出哪片區域是高頻通行區。這個功能在商場、景區人流引導場景里是剛需而且在答辯PPT上展示效果遠超一段普通視頻。部署層面如果想讓作品有“落地感”可以把推理端放到邊緣設備上比如Jetson Nano或樹莓派加神經網絡加速棒。PyTorch模型導出成ONNX再轉TensorRT在Jetson上跑YOLOv8s能達到實時整套系統從“實驗室代碼”變成“能裝在商場門口的玩意兒”這個提升對畢設評分的加分效果很明顯。我在實際拆解這套源碼的過程中最深的一個體會是人流量檢測系統的難點從來不在“跑通YOLO”這一步而在于“檢測完之后怎么辦”。跟蹤的穩定性、計數的口徑、環境適配的魯棒性這些才是真正拉開工程質量差距的地方。希望這篇拆解能幫你把源碼里的每一行都吃透做出一個真正能說清楚原理、禁得起追問的畢設項目。本文還有配套的精品資源點擊獲取