別源碼解析:Haar級(jí)聯(lián)+LBPH模型實(shí)戰(zhàn))
簡(jiǎn)介面向計(jì)算機(jī)視覺(jué)開(kāi)發(fā)者的Python人臉識(shí)別系統(tǒng)源碼包內(nèi)置主程序、配置文件、說(shuō)明文檔以及多組訓(xùn)練好的識(shí)別器模型。項(xiàng)目基于OpenCV庫(kù)實(shí)現(xiàn)配套官方人臉檢測(cè)器可直接運(yùn)行體驗(yàn)人臉檢測(cè)、訓(xùn)練與識(shí)別流程。壓縮包共14個(gè)文件核心為10個(gè)yml識(shí)別器模型另含Python腳本、xml人臉檢測(cè)器、txt配置與md說(shuō)明整體僅148KB輕量簡(jiǎn)潔適合畢設(shè)、課設(shè)或入門(mén)學(xué)習(xí)。已有1083人學(xué)習(xí)下載具有一定參考熱度。通過(guò)對(duì)比不同編號(hào)的yml模型可以觀察訓(xùn)練參數(shù)對(duì)識(shí)別效果的影響結(jié)合主程序與說(shuō)明文檔能夠快速理解人臉特征提取、比對(duì)識(shí)別的工程實(shí)現(xiàn)便于在此基礎(chǔ)上二次開(kāi)發(fā)。資源還附帶了清晰的目錄結(jié)構(gòu)和運(yùn)行說(shuō)明有助于快速定位主程序入口、模型文件與配置項(xiàng)省去環(huán)境搭建和調(diào)試時(shí)間。1. 基于 OpenCV 的人臉識(shí)別系統(tǒng)這份源碼包里到底有什么說(shuō)實(shí)話(huà)很多人一聽(tīng)到“人臉識(shí)別系統(tǒng)”就以為要上深度學(xué)習(xí)、要訓(xùn)練神經(jīng)網(wǎng)絡(luò)、要裝 CUDA其實(shí) OpenCV 這套傳統(tǒng)方案完全夠用在很多實(shí)際場(chǎng)景里。這份源碼包很典型main.py 主程序、config.txt 配置文件、haarcascade_frontalface_default.xml 檢測(cè)模型再加上 10 個(gè) yml 識(shí)別器文件1.yml 到 10.yml。一看這個(gè)結(jié)構(gòu)就知道它是基于 Haar 級(jí)聯(lián)檢測(cè) LBPH局部二值模式直方圖識(shí)別器的經(jīng)典組合對(duì)應(yīng)了 10 個(gè)不同人的訓(xùn)練結(jié)果。它解決的是“從攝像頭讀到人臉 → 識(shí)別出是誰(shuí)”的完整閉環(huán)特別適合課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)、考勤門(mén)禁原型以及想快速理解 OpenCV 人臉識(shí)別全流程的從業(yè)者。整體邏輯不復(fù)雜跑通一遍你就把人臉檢測(cè)、數(shù)據(jù)集訓(xùn)練、模型持久化、實(shí)時(shí)識(shí)別這幾塊全摸透了。2. 先看懂源碼結(jié)構(gòu)config.txt 與 yml 文件的角色分配2.1 文件清單里每個(gè)文件是干什么的解開(kāi)壓縮包里面文件不多但每個(gè)都有明確職責(zé)。haarcascade_frontalface_default.xml 是 OpenCV 自帶的 Haar 級(jí)聯(lián)分類(lèi)器負(fù)責(zé)在畫(huà)面里把人臉位置框出來(lái)這是“檢測(cè)”環(huán)節(jié)。main.py 是主程序負(fù)責(zé)把檢測(cè)和識(shí)別串起來(lái)。config.txt 是配置文件我一般會(huì)在這里放識(shí)別閾值、檢測(cè)參數(shù)、模型路徑這些運(yùn)行時(shí)參數(shù)這樣換場(chǎng)景不用改代碼。1.yml 到 10.yml 是訓(xùn)練好的識(shí)別器模型文件每個(gè) yml 對(duì)應(yīng)一個(gè) ID 的人臉樣本訓(xùn)練結(jié)果也就是說(shuō)源碼包里已經(jīng)預(yù)置了 10 個(gè)人的模型數(shù)據(jù)。拿到源碼的第一件事我建議先打開(kāi) README.md 看作者寫(xiě)的環(huán)境依賴(lài)再打開(kāi) config.txt 看參數(shù)。這套組合的典型運(yùn)行邏輯是main.py 啟動(dòng)后讀攝像頭幀 → Haar 檢測(cè)人臉 → 把檢測(cè)到的人臉區(qū)域預(yù)處理后送入識(shí)別器 → 識(shí)別器返回 ID 和置信度 → 程序根據(jù) ID 映射姓名根據(jù)置信度決定是否顯示“陌生人”警告。yml 文件是核心資產(chǎn)沒(méi)有它們 main.py 跑不起來(lái)或者只能檢測(cè)不能識(shí)別。2.2 config.txt 典型內(nèi)容與參數(shù)語(yǔ)義很多初學(xué)者拿到代碼會(huì)忽略 config.txt覺(jué)得它不重要。實(shí)際上在這種結(jié)構(gòu)里config.txt 承擔(dān)了“參數(shù)與代碼分離”的作用。常見(jiàn)的寫(xiě)法類(lèi)似下面這樣# config.txt 典型內(nèi)容 camera_index 0 model_path . confidence_threshold 80 face_size (200, 200) scale_factor 1.1 min_neighbors 5 # 人物 ID 與姓名映射 1: ZhangSan 2: LiSi 3: WangWu 4: ZhaoLiu 5: QianQi 6: SunBa 7: ZhouJiu 8: WuShi 9: ZhengYi 10: WangEr我來(lái)解釋一下這些參數(shù)的實(shí)際意義。camera_index 是攝像頭編號(hào)0 一般是筆記本內(nèi)置攝像頭如果外接攝像頭可能變成 1 或 2這個(gè)值不對(duì)會(huì)出現(xiàn)“攝像頭打開(kāi)失敗”或者黑屏報(bào)錯(cuò)。model_path 是 yml 文件所在目錄程序里通常會(huì)把路徑拼接成model_path / str(id) .yml去加載。confidence_threshold 是置信度閾值LBPH 的 predict 返回的距離值越小表示越匹配所以閾值 80 表示“距離小于 80 才認(rèn)可這個(gè) ID”大于 80 就當(dāng)陌生人處理。face_size 是送入識(shí)別器前的人臉圖像縮放尺寸統(tǒng)一尺寸是訓(xùn)練和識(shí)別一致性的關(guān)鍵太小丟特征太大浪費(fèi)計(jì)算。這段配置最重要的一句話(huà)是程序加載模型時(shí)不是一次性加載全部 yml而是按需加載或者啟動(dòng)時(shí)遍歷目錄加載。如果某個(gè)人臉 ID 缺失比如 4.yml 丟了但 config 里又映射了 ZhaoLiu程序會(huì)嘗試讀取不存在的文件。我一般會(huì)建議在 main.py 里做一個(gè)模型文件存在性檢查缺失時(shí)跳過(guò)而不是直接崩潰。2.3 主程序 main.py 的執(zhí)行骨架如果作者把 main.py 寫(xiě)得規(guī)整代碼骨架大致如下import cv2 import os import configparser # 讀取配置文件 config configparser.ConfigParser() config.read(config.txt) camera_index int(config[DEFAULT][camera_index]) threshold int(config[DEFAULT][confidence_threshold]) face_size eval(config[DEFAULT][face_size]) # 加載人臉檢測(cè)器 face_cascade cv2.CascadeClassifier( cv2.data.haarcascades haarcascade_frontalface_default.xml ) # 初始化 LBPH 識(shí)別器 recognizer cv2.face.LBPHFaceRecognizer_create() # 加載已訓(xùn)練好的模型文件 model_dir config[DEFAULT][model_path] id_map {} for name in os.listdir(model_dir): if name.endswith(.yml): model_id int(name.split(.)[0]) recognizer.read(os.path.join(model_dir, name)) id_map[model_id] name這段代碼有幾處值得注意。cv2.face.LBPHFaceRecognizer_create()來(lái)自 opencv-contrib-python 包如果你裝的是普通的 opencv-python會(huì)報(bào)module cv2 has no attribute face。這是這個(gè)源碼包里最容易踩的坑之一。cv2.data.haarcascades是 OpenCV 自帶的級(jí)聯(lián)模型路徑這樣寫(xiě)的好處是不用自己復(fù)制 xml 文件路徑但前提是 OpenCV 版本不要過(guò)舊3.x 早期版本沒(méi)有這個(gè)屬性。遍歷模型目錄加載 yml 而不是硬編碼 10 個(gè) read 調(diào)用這也是更穩(wěn)的寫(xiě)法別人在你的代碼上增刪模型不用改主程序的邏輯。3. Haar 級(jí)聯(lián)檢測(cè)環(huán)節(jié)從視頻幀里把人臉框出來(lái)3.1 Haar 特征與級(jí)聯(lián)分類(lèi)器的工作方式Haar 級(jí)聯(lián)檢測(cè)器是老牌的人臉檢測(cè)方案核心是用 Haar 特征描述人臉區(qū)域的明暗分布規(guī)律。比如眼睛區(qū)域比臉頰暗鼻梁比兩側(cè)亮這些特征通過(guò)積分圖快速計(jì)算。級(jí)聯(lián)的意思是一串越來(lái)越嚴(yán)格的分類(lèi)器串聯(lián)前幾層用少量特征快速過(guò)濾掉絕大部分非人臉區(qū)域后幾層用更多特征對(duì)候選區(qū)域做精細(xì)判斷。這個(gè)設(shè)計(jì)讓檢測(cè)速度非??煸跇?shù)莓派這類(lèi)低算力設(shè)備上也能跑實(shí)時(shí)。在這份源碼里haarcascade_frontalface_default.xml 就是訓(xùn)練好的級(jí)聯(lián)模型文件。detectMultiScale 是調(diào)用入口它有四個(gè)關(guān)鍵參數(shù)。scaleFactor 控制每次縮放圖像的比例1.1 表示每次縮小 10%越小檢測(cè)越慢但越細(xì)致。minNeighbors 控制候選矩形最少被多少個(gè)鄰近矩形“投票”認(rèn)可值越大漏檢越多但誤檢越少。minSize 和 maxSize 限制檢測(cè)人臉的最小和最大像素尺寸設(shè)置合理能過(guò)濾掉遠(yuǎn)處的路人臉和近景誤檢。3.2 detectMultiScale 參數(shù)怎么調(diào)才合理看一段實(shí)際調(diào)用代碼# 常見(jiàn)調(diào)用方式 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale( gray, scaleFactor1.1, minNeighbors5, minSize(64, 64), maxSize(512, 512) ) for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (xw, yh), (0, 255, 0), 2) face_roi gray[y:yh, x:xw] face_roi cv2.resize(face_roi, face_size)每個(gè)參數(shù)的調(diào)整方向我都踩過(guò)。scaleFactor 設(shè)成 1.1 時(shí)對(duì)斜側(cè)臉和小尺寸臉的檢測(cè)比較友好但如果畫(huà)面里人臉很遠(yuǎn)很小可以適當(dāng)降低到 1.05代價(jià)是每幀耗時(shí)增加。minNeighbors 設(shè)成 3 會(huì)明顯增加誤檢背景里的圓形物體可能被當(dāng)成臉設(shè)成 8 以上又可能漏掉側(cè)面臉。我一般從 5 開(kāi)始調(diào)出錯(cuò)時(shí)看是誤檢多還是漏檢多再往對(duì)應(yīng)方向調(diào)。minSize 建議和訓(xùn)練時(shí)的 face_size 一致或接近設(shè)太小會(huì)導(dǎo)致大量背景小矩形參與計(jì)算浪費(fèi)時(shí)間。檢測(cè)環(huán)節(jié)有兩個(gè)常見(jiàn)翻車(chē)場(chǎng)景。一是 Haar 對(duì)側(cè)臉和低頭臉效果明顯變差如果你做的是門(mén)禁場(chǎng)景攝像頭裝得偏高人臉往往呈仰角這時(shí)候 Haar 的漏檢率會(huì)上去可以考慮換成 OpenCV 的 YuNet 或 MediaPipe但這超出了當(dāng)前源碼包的范疇。二是光照變化半張臉在陰影里時(shí) Haar 檢測(cè)框會(huì)漂移到亮的那半張臉上識(shí)別自然跟著錯(cuò)后面避坑章節(jié)我會(huì)專(zhuān)門(mén)展開(kāi)。3.3 檢測(cè)框坐標(biāo)與模型輸入的一致性detectMultiScale 返回的每個(gè)元素是 (x, y, w, h)分別是矩形左上角橫縱坐標(biāo)和寬高。后面的處理一定是gray[y:yh, x:xw]而不是gray[x:xw, y:yh]這個(gè)順序?qū)懛词切率肿畛R?jiàn)的錯(cuò)誤會(huì)直接導(dǎo)致切出來(lái)的人臉區(qū)域是歪的識(shí)別器輸出的置信度永遠(yuǎn)在閾值之外。裁剪出來(lái)的人臉還必須縮放到和訓(xùn)練時(shí)一致的尺寸比如 config 里的 (200, 200)否則 LBPH 直方圖特征的空間對(duì)齊就被破壞識(shí)別率大跌。這里還有一個(gè)容易被忽略的細(xì)節(jié)送入識(shí)別器之前要不要做直方圖均衡化。光照不均勻時(shí)cv2.equalizeHist(face_roi)能顯著提升識(shí)別穩(wěn)定性。很多源碼包作者不會(huì)寫(xiě)這一步但在實(shí)際場(chǎng)景里我會(huì)建議加上尤其是在現(xiàn)場(chǎng)燈光條件不穩(wěn)定的情況下這一步比換識(shí)別器算法更立竿見(jiàn)影。代價(jià)是每幀多一次直方圖均衡計(jì)算對(duì)現(xiàn)代 CPU 來(lái)說(shuō)幾乎可以忽略。4. LBPH 識(shí)別器與 yml 模型文件10 個(gè)人是怎么被區(qū)分開(kāi)的4.1 LBPH 為什么適合這種小樣本場(chǎng)景源碼包里預(yù)置了 10 個(gè) yml對(duì)應(yīng)的就是 10 個(gè)訓(xùn)練人物的模型。LBPH 是 OpenCV 里免訓(xùn)練深度網(wǎng)絡(luò)也能用的人臉識(shí)別方案原理不復(fù)雜把圖像劃分成若干小塊每個(gè)像素和它周?chē)?8 個(gè)像素比較大小得到一串二進(jìn)制編碼統(tǒng)計(jì)每個(gè)小塊的直方圖把所有小塊直方圖拼接起來(lái)作為這張臉的“指紋”。識(shí)別時(shí)計(jì)算兩幅圖直方圖的距離距離越小越像同一個(gè)人。這個(gè)方案的優(yōu)勢(shì)是訓(xùn)練樣本需求量小每個(gè)人給 10 到 20 張不同角度的臉照就能得到可用的模型而且訓(xùn)練速度極快筆記本上幾千張圖也就是秒級(jí)訓(xùn)練。缺點(diǎn)是對(duì)光照和姿態(tài)的魯棒性不如深度學(xué)習(xí)方案同一場(chǎng)景拍出來(lái)的效果很好換個(gè)燈光位置識(shí)別率就可能明顯下降。課件或者畢設(shè)場(chǎng)景完全夠用商業(yè)級(jí)考勤門(mén)禁就要謹(jǐn)慎。4.2 從數(shù)據(jù)集到 yml 的訓(xùn)練流程雖然源碼包只給了訓(xùn)練好的 yml 文件但你要真正用起來(lái)、要加新人就必須自己訓(xùn)練模型。完整流程分四步import cv2 import os import numpy as np # 1. 準(zhǔn)備數(shù)據(jù)集目錄 # dataset/1/001.jpg, dataset/1/002.jpg ... # dataset/2/001.jpg, dataset/2/002.jpg ... faces [] labels [] for person_id in os.listdir(dataset): person_dir os.path.join(dataset, person_id) if not os.path.isdir(person_dir): continue for img_name in os.listdir(person_dir): img_path os.path.join(person_dir, img_name) gray cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) gray cv2.resize(gray, (200, 200)) faces.append(gray) labels.append(int(person_id)) # 2. 創(chuàng)建 LBPH 識(shí)別器并訓(xùn)練 recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.train(faces, np.array(labels)) # 3. 保存模型 recognizer.save(1.yml) # 4. 驗(yàn)證模型 test_img cv2.imread(test.jpg, cv2.IMREAD_GRAYSCALE) test_img cv2.resize(test_img, (200, 200)) label, confidence recognizer.predict(test_img) print(f識(shí)別結(jié)果: label{label}, confidence{confidence})數(shù)據(jù)集的組織我建議一個(gè)子目錄一個(gè)人目錄名就是 ID。這里參數(shù)上有個(gè)關(guān)鍵點(diǎn)recognizer.train要求 faces 是列表、labels 是 numpy 數(shù)組而且每個(gè) face 的尺寸必須完全一致。這個(gè)一致性的約束比你想的更嚴(yán)格不是寬高比一樣就行是所有像素尺寸精確相同。我見(jiàn)過(guò)有人用cv2.resize(gray, (200, 200))時(shí)把參數(shù)寫(xiě)反成(200, 200)以為是寬高其實(shí) OpenCV 的 resize 第一個(gè)參數(shù)是目標(biāo)寬度、第二個(gè)是高度寫(xiě)反了就會(huì)出現(xiàn)訓(xùn)練時(shí)正常、識(shí)別時(shí)置信度異常高的聲音。4.3 project 出來(lái)的是什么recognizer.predict(test_img)返回的 confidence 是 LBPH 直方圖距離。很多人第一次拿到這個(gè)值會(huì)很困惑因?yàn)樗菐资揭粌砂俚臄?shù)字不像深度學(xué)習(xí)里輸出一個(gè) 0 到 1 的概率。這個(gè)距離的含義是兩張人臉圖特征向量的相似程度越小越像。config 里的 confidence_threshold 80 就是拿來(lái)做判斷的距離小于 80 認(rèn)為匹配大于 80 認(rèn)為陌生人。但這里要特別提醒一個(gè)反直覺(jué)的現(xiàn)象同一個(gè)人的不同照片置信度可能差很大。訓(xùn)練集中某個(gè)人只用了 10 張照片其中 8 張是正臉、2 張是側(cè)臉那你拿一張側(cè)臉去測(cè)置信度可能飆到 90 多直接被判定為陌生人。這是 LBPH 的天然邊界不是源碼包的問(wèn)題。實(shí)際應(yīng)用時(shí)我一般會(huì)把訓(xùn)練集覆蓋“正臉、左右側(cè)臉、抬頭、低頭、戴眼鏡、不戴眼鏡”這些變化而且每類(lèi)至少 3 張這樣模型才能泛化。ID 從 1 到 10 的映射關(guān)系也要和 config.txt 中的姓名映射保持一致否則會(huì)出現(xiàn)“識(shí)別出 ZhangSan 但框里顯示 WangEr”的錯(cuò)位。5. 避坑與排錯(cuò)從 ModuleNotFoundError 到識(shí)別不準(zhǔn)的五個(gè)高頻問(wèn)題5.1 ModuleNotFoundError: No module named cv2現(xiàn)象剛下載完源碼按照 README 里的命令運(yùn)行python main.py報(bào)錯(cuò)找不到 cv2 模塊。原因沒(méi)安裝 OpenCV或者裝錯(cuò)了包。這一個(gè)源碼包最常見(jiàn)的安裝命令pip install opencv-python裝出來(lái)的 OpenCV 不包含cv2.face模塊因?yàn)槿四樧R(shí)別模塊在 opencv-contrib-python 里。解決先卸載現(xiàn)有版本再安裝 contrib 包。一定要先卸載直接裝 opencv-contrib-python 會(huì)和已有的 opencv-python 沖突可能出現(xiàn)安裝成功但 import 還是失敗的玄學(xué)情況。pip uninstall opencv-python opencv-contrib-python -y pip install opencv-contrib-python numpy裝完之后檢查python -c import cv2; print(cv2.__version__); print(hasattr(cv2, face))。如果輸出里 face 是 True說(shuō)明人臉識(shí)別模塊可用了。5.2 程序能跑但框出來(lái)的人臉全被識(shí)別成陌生人現(xiàn)象攝像頭畫(huà)面正常人臉檢測(cè)框也有但屏幕上一直顯示 Stranger陌生人誰(shuí)過(guò)來(lái)都不認(rèn)識(shí)。原因最常見(jiàn)的兩個(gè)。第一個(gè)是攝像頭拍攝畫(huà)面和你訓(xùn)練模型的場(chǎng)景差異太大比如訓(xùn)練時(shí)用的 200x200 正臉照現(xiàn)場(chǎng)是斜上方監(jiān)控角度LBPH 特征對(duì)角度特別敏感。第二個(gè)是confidence_threshold設(shè)得太嚴(yán)比如設(shè)成了 50真實(shí)匹配距離 60 到 80 的情況被你一刀切了。解決先在 config.txt 里把閾值放寬到 100觀察實(shí)時(shí)顯示的置信度值大概在哪個(gè)范圍再根據(jù)分布反推合理閾值。同時(shí)檢查攝像頭角度盡量讓人的臉正對(duì)鏡頭傾斜角度超過(guò) 30 度時(shí) LBPH 識(shí)別率會(huì)斷崖式下降。5.3 攝像頭打不開(kāi)代碼報(bào) VIDIOC_QUERYMENU 錯(cuò)誤現(xiàn)象Linux 環(huán)境下運(yùn)行 main.py攝像頭初始化失敗提示VIDIOC_QUERYMENU或其他 V4L2 相關(guān)錯(cuò)誤。原因camera_index 是 0但你的攝像頭被系統(tǒng)識(shí)別成了別的索引或者 OpenCV 是用不支持 V4L2 的方式編譯的。解決先用系統(tǒng)命令確認(rèn)攝像頭索引ls /dev/video*一般有 /dev/video0 和 /dev/video1筆記本內(nèi)置攝像頭常是 0USB 外接攝像頭在某些驅(qū)動(dòng)組合下會(huì)占用 video0 導(dǎo)致內(nèi)置攝像頭變成 video1。然后改 config.txt 里的 camera_index 試試。如果還是不行可以臨時(shí)在代碼里加cv2.CAP_PROP_FRAME_WIDTH和cv2.CAP_PROP_FRAME_HEIGHT的設(shè)置把分辨率降到 640x480有時(shí)候高分辨率攝像頭在部分 Linux 驅(qū)動(dòng)下就是打不開(kāi)。5.4 10 個(gè) yml 加載到一半報(bào)錯(cuò)現(xiàn)象程序啟動(dòng)后加載 3.yml 時(shí)報(bào)錯(cuò)提示文件不存在或者模型格式錯(cuò)誤。原因模型文件路徑拼接錯(cuò)誤或者壓縮包解壓時(shí)有個(gè)別文件損壞。也有可能是os.listdir(model_dir)遍歷到了隱藏文件或臨時(shí)文件比如 .DS_Store 或者 1.yml.tmp按擴(kuò)展名.yml判斷時(shí)不會(huì)加載這些文件但如果某個(gè) yml 文件內(nèi)容被截?cái)嗔藃ecognizer.read()就會(huì)拋異常。解決在讀取之前加一個(gè) try-except跳過(guò)損壞的模型并打印日志方便排查。同時(shí)檢查 model_path 路徑是否包含中文字符OpenCV 的read函數(shù)對(duì)中文路徑支持很差這是老版本 OpenCV 的通病遇到中文路徑必須復(fù)制到純英文目錄下運(yùn)行。model_files [] for f in os.listdir(model_dir): if f.endswith(.yml) and f.split(.)[0].isdigit(): model_files.append(f) for mf in model_files: try: model_id int(mf.split(.)[0]) recognizer.read(os.path.join(model_dir, mf)) id_map[model_id] mf print(floaded model: {mf}) except Exception as e: print(fskip {mf}: {e})5.5 識(shí)別結(jié)果穩(wěn)定但速度很卡幀率掉到不到 10現(xiàn)象畫(huà)面明顯一卡一卡的識(shí)別延遲嚴(yán)重FPS 目測(cè)不到 10。原因檢測(cè)區(qū)域太大、圖像尺寸太大、或者 main.py 的 while 循環(huán)里做了太多高耗時(shí)操作比如把每一幀都存盤(pán)。Haar 檢測(cè)在 1080p 全幀圖上跑本身就慢再加上多人臉場(chǎng)景每個(gè)人都走一遍識(shí)別CPU 直接拉滿(mǎn)。解決先裁剪檢測(cè)區(qū)域。固定一個(gè) ROI感興趣區(qū)域只在畫(huà)面中央的矩形區(qū)域做檢測(cè)比如只檢測(cè)畫(huà)面中間 70% 的區(qū)域這個(gè)改動(dòng)對(duì)性能提升立竿見(jiàn)影。其次是先把幀 resize 到 640x480 再做檢測(cè)再用檢測(cè)框放大回原圖坐標(biāo)去裁剪人臉這能省一半以上計(jì)算量。如果還是不夠就把 face_size 從 200 降到 160LBPH 的特征維度會(huì)下降識(shí)別計(jì)算量也隨之下降。6. 往這個(gè)源碼包里加新人訓(xùn)練腳本、ID 對(duì)齊與實(shí)測(cè)驗(yàn)證技巧這個(gè)源碼包不是只能跑那 10 個(gè)人你完全可以按照同樣的數(shù)據(jù)格式往里加新人。要做的核心工作是把新人的 yml 文件生成出來(lái)并讓配置文件認(rèn)識(shí)他。我來(lái)給你一套我自己反復(fù)用過(guò)的完整操作流程。第一步構(gòu)建數(shù)據(jù)集目錄。我一般會(huì)在項(xiàng)目根目錄下新建 dataset 文件夾結(jié)構(gòu)是dataset/11/img1.jpg、dataset/11/img2.jpg這樣其中 11 是新人的 ID要和現(xiàn)有 1 到 10 錯(cuò)開(kāi)。從攝像頭采集照片可以直接復(fù)用 Haar 檢測(cè)人臉區(qū)域再去重采樣每個(gè) ID 采集 30 張左右涵蓋正臉、左右轉(zhuǎn)頭、戴不戴眼鏡等變化。手動(dòng)從歷史照片里整理也可以關(guān)鍵是保證統(tǒng)一尺寸和灰度模式。第二步寫(xiě)訓(xùn)練腳本。剛才第 4 章給的訓(xùn)練代碼可以直接用把 label 從數(shù)據(jù)集目錄名自動(dòng)讀取這一步注意 labels 必須是整數(shù)數(shù)組。訓(xùn)練完成后保存成new_model.yml。第三步做 ID 對(duì)齊和模型掃描。把訓(xùn)練好的 yml 文件命名為和 ID 一致的11.yml和原有的 1.yml 到 10.yml 放在同一目錄下。然后在 config.txt 里加一行11: 新人姓名主程序啟動(dòng)時(shí)會(huì)自動(dòng)掃到 11.yml 并加載。這個(gè)做法比改代碼里的 id_map 硬編碼要干凈得多以后加第 12 個(gè)人也不用改代碼。第四步實(shí)測(cè)驗(yàn)證這里我有一個(gè)強(qiáng)烈推薦的做法不要只看屏幕上顯示的姓名要看置信度。為了讓置信度暴露出來(lái)可以臨時(shí)改代碼在識(shí)別結(jié)果旁邊畫(huà)上 confidence 數(shù)值# 臨時(shí)調(diào)試代碼把置信度顯示在框上方 label, confidence recognizer.predict(face_roi) display_text f{id_map.get(label, Unknown)} ({confidence:.1f}) cv2.putText(frame, display_text, (x, y-10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)實(shí)測(cè)時(shí)新人站在攝像頭前如果置信度穩(wěn)定在 30 到 60 之間說(shuō)明模型訓(xùn)練質(zhì)量很好如果一直在 80 附近抖動(dòng)說(shuō)明訓(xùn)練集的光線或姿態(tài)太單一需要補(bǔ)數(shù)據(jù)。我通常要求每位新人的“自測(cè)置信度”穩(wěn)定低于閾值的一半才認(rèn)為這個(gè)模型合格。還有一個(gè)細(xì)節(jié)測(cè)試時(shí)不要只測(cè)正臉故意測(cè)側(cè)臉和低頭看置信度的惡化程度這決定了這個(gè)系統(tǒng)在實(shí)際使用中到底可不可靠。從那次調(diào)優(yōu)以后我每次拿到此類(lèi)人臉識(shí)別源碼都會(huì)強(qiáng)制走一遍這套流程先跑通原版、看每個(gè) ID 自測(cè)置信度分布、再調(diào)閾值、最后加新人驗(yàn)證擴(kuò)展流程這已經(jīng)是我的肌肉記憶了。希望這個(gè)思路能幫你少走點(diǎn)彎路。本文還有配套的精品資源點(diǎn)擊獲取