Python | OpenCV 專案:即時人臉辨識系統
📚 前言 在上一篇 即時濾鏡相機 中,我們完成了第一個整合專案。
這一篇進入更有挑戰性的應用:即時人臉辨識系統 。 不只是「偵測到臉」,而是能辨識出「這張臉是誰」,並在即時畫面中顯示姓名與信心度。
這個專案不依賴深度學習框架,完全使用 OpenCV 內建的 LBPH(Local Binary Pattern Histogram)演算法即可完成。
🎯 專案目標
蒐集多人的人臉樣本
訓練 LBPH 辨識模型
影片辨識,顯示姓名與信心度
支援隨時新增人員(重新蒐集 + 重新訓練)
🗃️ 專案結構 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 face_recognition/ ├── assets/ ← 素材影片(每人一段) │ ├── person_a.mp4 │ ├── person_b.mp4 │ └── test.mp4 ├── 1_collect.py ← 步驟一:從影片蒐集人臉樣本 ├── 2_train.py ← 步驟二:訓練辨識模型 ├── 3_recognize.py ← 步驟三:影片辨識 ├── dataset/ ← 蒐集的人臉圖片(自動建立) │ ├── 0_PersonA/ │ ├── 1_PersonB/ │ └── ... └── models/ ← 儲存訓練好的模型(自動建立) ├── face_model.yml └── label_map.json
🎬 準備影片素材 本篇以影片檔取代即時攝影機,不需要攝影機設備也不涉及個人隱私即可完整練習。
建議使用公開演講影片(例如 TED Talks,採 Creative Commons 授權),正面清晰、光線穩定,非常適合人臉辨識練習。每位人員各準備一段演講影片,另外再準備一段測試用影片(建議選不同段落,讓辨識測試更有說服力)。
使用 yt-dlp 下載:
1 2 3 4 5 6 pip install yt-dlp yt-dlp -f "mp4[height<=720]" -o "assets/person_a.mp4" [影片 URL] yt-dlp -f "mp4[height<=720]" -o "assets/person_b.mp4" [影片 URL]
此處示範使用 TED Talks 的兩部影片:
💻 步驟一:蒐集人臉樣本 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 import cv2import osperson_id = 0 person_name = "PersonA" video_path = "assets/person_a.mp4" sample_count = 100 frame_interval = 3 save_dir = f"dataset/{person_id} _{person_name} " os.makedirs(save_dir, exist_ok=True ) face_cascade = cv2.CascadeClassifier( cv2.data.haarcascades + "haarcascade_frontalface_default.xml" ) cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"無法開啟影片:{video_path} " ) exit() count = 0 frame_idx = 0 print(f"開始從影片蒐集 {person_name} 的人臉樣本,目標 {sample_count} 張" ) while count < sample_count: ret, frame = cap.read() if not ret: print("影片播放完畢" ) break frame_idx += 1 if frame_idx % frame_interval != 0 : continue gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3 , 5 ) for (x, y, w, h) in faces: face_img = gray[y:y+h, x:x+w] face_rsz = cv2.resize(face_img, (200 , 200 )) filename = os.path.join(save_dir, f"{count:04 d} .jpg" ) cv2.imwrite(filename, face_rsz) count += 1 cv2.rectangle(frame, (x, y), (x+w, y+h), (0 , 255 , 0 ), 2 ) cv2.putText(frame, f"{count} /{sample_count} " , (x, y - 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.7 , (0 , 255 , 0 ), 2 ) cv2.imshow("Collecting" , frame) if cv2.waitKey(30 ) & 0xFF == ord("q" ): break cap.release() cv2.destroyAllWindows() print(f"完成!共蒐集 {count} 張樣本,儲存於 {save_dir} " )
圖:從影片逐幀偵測人臉,每隔 N 幀截取一次,自動儲存灰階人臉圖片,累積到指定樣本數後結束
💡 每位人員執行一次,修改 person_id、person_name 與 video_path 後重新執行,即可累積多人資料集。
📷 改用即時攝影機 :將 video_path 那行改為 cap = cv2.VideoCapture(0),並移除 frame_interval 的跳幀邏輯(或設為 1),即可改用攝影機即時蒐集,程式邏輯完全相同。
💻 步驟二:訓練辨識模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import cv2import numpy as npimport osimport jsondataset_dir = "dataset" faces = [] labels = [] label_map = {} for folder in sorted(os.listdir(dataset_dir)): folder_path = os.path.join(dataset_dir, folder) if not os.path.isdir(folder_path): continue parts = folder.split("_" , 1 ) person_id = int(parts[0 ]) person_name = parts[1 ] if len(parts) > 1 else folder label_map[person_id] = person_name for fname in os.listdir(folder_path): if not fname.lower().endswith(".jpg" ): continue img_path = os.path.join(folder_path, fname) img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) if img is not None : faces.append(img) labels.append(person_id) print(f"載入完成:{len(faces)} 張樣本,{len(label_map)} 位人員" ) print(f"人員清單:{label_map} " ) recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.train(faces, np.array(labels)) os.makedirs("models" , exist_ok=True ) recognizer.save("models/face_model.yml" ) with open("models/label_map.json" , "w" , encoding="utf-8" ) as f: json.dump({str(k): v for k, v in label_map.items()}, f, ensure_ascii=False ) print("訓練完成!模型已儲存至 model/face_model.yml" )
圖:讀取所有人員的人臉樣本,使用 LBPH 演算法訓練辨識模型並儲存為 yml 與 JSON 標籤檔
⚠️ cv2.face 需要 opencv-contrib-python:pip install opencv-contrib-python
💻 步驟三:影片辨識 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 import cv2import jsonrecognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.read("models/face_model.yml" ) with open("models/label_map.json" , encoding="utf-8" ) as f: raw_map = json.load(f) label_map = {int(k): v for k, v in raw_map.items()} face_cascade = cv2.CascadeClassifier( cv2.data.haarcascades + "haarcascade_frontalface_default.xml" ) CONFIDENCE_THRESHOLD = 80 video_path = "assets/test.mp4" cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"無法開啟影片:{video_path} " ) exit() print("影片辨識啟動,按 q 離開" ) while True : ret, frame = cap.read() if not ret: print("影片播放完畢" ) break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces = face_cascade.detectMultiScale(gray, 1.3 , 5 ) for (x, y, w, h) in faces: face_img = gray[y:y+h, x:x+w] face_rsz = cv2.resize(face_img, (200 , 200 )) label, confidence = recognizer.predict(face_rsz) if confidence < CONFIDENCE_THRESHOLD: name = label_map.get(label, "Unknown" ) color = (0 , 255 , 0 ) text = f"{name} ({confidence:.1 f} )" else : name = "Unknown" color = (0 , 0 , 255 ) text = f"Unknown ({confidence:.1 f} )" cv2.rectangle(frame, (x, y), (x+w, y+h), color, 2 ) cv2.putText(frame, text, (x, y - 10 ), cv2.FONT_HERSHEY_SIMPLEX, 0.7 , color, 2 ) cv2.imshow("Face Recognition" , frame) if cv2.waitKey(30 ) & 0xFF == ord("q" ): break cap.release() cv2.destroyAllWindows()
圖:載入 LBPH 模型對測試影片進行辨識,依信心度顯示姓名或 Unknown 並標示邊界框
📷 改用即時攝影機 :將 video_path = "assets/test.mp4" 改為 cap = cv2.VideoCapture(0),即可改為即時攝影機辨識,程式邏輯完全相同。
💻 新增人員 只需:
修改 1_collect.py 的 person_id(遞增)、person_name 與 video_path,重新執行蒐集
重新執行 2_train.py 訓練(會自動載入所有已蒐集的資料)
重新執行 3_recognize.py
不需要修改任何辨識邏輯。
⚠️ 注意事項
影片品質 :蒐集樣本的影片建議選正面清晰、光線均勻的片段,避免快速搖晃或逆光。
LBPH 對光線敏感 :蒐集影片與測試影片的光線環境差異越小,辨識率越高。
信心度閾值需要調整 :CONFIDENCE_THRESHOLD = 80 是參考值,不同影片品質與光線條件可能需要調高或調低。
樣本多樣性 :若影片角度過於單一,辨識率可能偏低,建議選取包含多種頭部角度的片段。
frame_interval 設定 :影片較短但樣本需求量大時可調低;角度變化緩慢時可調高以增加多樣性。
opencv-contrib-python 與 opencv-python 不能同時安裝 :若已安裝 opencv-python,需先 pip uninstall opencv-python 再安裝 opencv-contrib-python。
🎯 結語 LBPH 人臉辨識輕量且不需要 GPU,適合在本機快速建立小規模的人員辨識系統。 若需要更高準確度(例如跨光線、跨角度),可考慮改用 face_recognition 套件(基於深度學習的人臉嵌入向量)。
下一篇將進入 OpenCV 專案:車牌辨識應用 ,結合輪廓分析與 OCR,識別圖片中的車牌號碼。
📖 如在學習過程中遇到疑問,或是想了解更多相關主題,建議回顧一下 Python | OpenCV 系列導讀 ,掌握完整的章節目錄,方便快速找到你需要的內容。
註:以上參考了OpenCV 官方文件 — Face Recognition OpenCV LBPH Face Recognizer