📢 公告:OpenCV 系列文章重構完成(75%)。專案實作篇仍在製作中,完成時間未定,敬請期待!→ 查看文章索引

熱門系列
Like Share Discussion Bookmark Smile

J.J. Huang   2026-04-14   Python OpenCV 08.專案實作篇   瀏覽次數:次   DMCA.com Protection Status

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
# install_yt_dlp.sh
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
# 1_collect.py
import cv2
import os

# ===== 設定 =====
person_id = 0 # 每位人員指定一個唯一 ID(從 0 開始遞增)
person_name = "PersonA" # 人員姓名
video_path = "assets/person_a.mp4" # 來源影片路徑
sample_count = 100 # 目標蒐集樣本數
frame_interval = 3 # 每 N 幀處理一次,避免連續幀過於相似
# ================

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:04d}.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_idperson_namevideo_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
# 2_train.py
import cv2
import numpy as np
import os
import json

dataset_dir = "dataset"
faces = []
labels = []
label_map = {} # id → name

for folder in sorted(os.listdir(dataset_dir)):
folder_path = os.path.join(dataset_dir, folder)
if not os.path.isdir(folder_path):
continue

# 資料夾命名規則:{id}_{name}
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-pythonpip 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
# 3_recognize.py
import cv2
import json

# 載入模型與標籤
recognizer = 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)

# LBPH:confidence 越低代表越相似(0 = 完全一致)
if confidence < CONFIDENCE_THRESHOLD:
name = label_map.get(label, "Unknown")
color = (0, 255, 0)
text = f"{name} ({confidence:.1f})"
else:
name = "Unknown"
color = (0, 0, 255)
text = f"Unknown ({confidence:.1f})"

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. 修改 1_collect.pyperson_id(遞增)、person_namevideo_path,重新執行蒐集
  2. 重新執行 2_train.py 訓練(會自動載入所有已蒐集的資料)
  3. 重新執行 3_recognize.py

不需要修改任何辨識邏輯。

⚠️ 注意事項

  • 影片品質:蒐集樣本的影片建議選正面清晰、光線均勻的片段,避免快速搖晃或逆光。
  • LBPH 對光線敏感:蒐集影片與測試影片的光線環境差異越小,辨識率越高。
  • 信心度閾值需要調整CONFIDENCE_THRESHOLD = 80 是參考值,不同影片品質與光線條件可能需要調高或調低。
  • 樣本多樣性:若影片角度過於單一,辨識率可能偏低,建議選取包含多種頭部角度的片段。
  • frame_interval 設定:影片較短但樣本需求量大時可調低;角度變化緩慢時可調高以增加多樣性。
  • opencv-contrib-pythonopencv-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