這篇教學會介紹使用 OpenCV 內建的 LBPH 人臉訓練功能 ( cv2.face.LBPHFaceRecognizer_create()),搭配人臉特徵模型,訓練判斷不同人臉的模型檔案,完成後就能透過攝影機的影像,辨識出不同的人臉,標記出對應的名字。
原文參考:OpenCV 辨識不同人臉
因為程式中的 OpenCV 會需要使用鏡頭或 GPU,所以請使用本機環境 ( 參考:使用 Python 虛擬環境 ) 或使用 Anaconda Jupyter 進行實作 ( 參考:使用 Anaconda ) ,並安裝 OpenCV 函式庫 ( 參考:OpenCV 函式庫 )。
要使用 cv2.face.LBPHFaceRecognizer_create(),必須先安裝 opencv_contrib_python,輸入下列指令進行安裝,opencv_contrib_python 提供 opencv 更多的操作方法。
如果使用 Anaconda Jupyter 搭配命令提示字元或終端機安裝,雖然可以順利安裝,但程式執行後可能會出現「module 'cv2' has no attribute 'face'」提示,有兩種解決方法:
- 第一、改成在 Jupyter 裡使用 !pip 直接安裝。
- 第二,移除 opencv-python 和 opencv_contrib_python,再次重新安裝。
pip install opencv_contrib_python
如果要辨識不同的人臉,必須先「訓練」不同人臉的模型,透過 cv2.face.LBPHFaceRecognizer_create() 方法,將收集好的人臉圖片 ( 同樣的人,不同角度的照片 20~30 張 ),以每個 id 為一個人的單位進行影像訓練,保留相關特徵值,屆時只要比對特徵值,就能得到人臉辨識的信心指數。
首先準備一些菜英文 ( 打出真正名字就不能發文,是哪招? ) 的照片和川普的照片 ( 使用 Google 搜尋 )
接著撰寫下方的程式,除了訓練菜英文 ( 打出真正名字就不能發文,是哪招? ) 和川普的照片,也搭配一組使用攝影鏡頭記錄自己的人臉影像,經過訓練後產生 yml 模型檔案儲存。
import cv2
import numpy as np
detector = cv2.CascadeClassifier('xml/haarcascade_frontalface_default.xml') # 載入人臉追蹤模型
recog = cv2.face.LBPHFaceRecognizer_create() # 啟用訓練人臉模型方法
faces = [] # 儲存人臉位置大小的串列
ids = [] # 記錄該人臉 id 的串列
for i in range(1,31):
img = cv2.imread(f'face01/{i}.jpg') # 依序開啟每一張菜英文的照片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 色彩轉換成黑白
img_np = np.array(gray,'uint8') # 轉換成指定編碼的 numpy 陣列
face = detector.detectMultiScale(gray) # 擷取人臉區域
for(x,y,w,h) in face:
faces.append(img_np[y:y+h,x:x+w]) # 記錄菜英文人臉的位置和大小內像素的數值
ids.append(1) # 記錄菜英文人臉對應的 id,只能是整數,都是 1 表示菜英文的 id 為 1
for i in range(1,16):
img = cv2.imread(f'face02/{i}.jpg') # 依序開啟每一張川普的照片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 色彩轉換成黑白
img_np = np.array(gray,'uint8') # 轉換成指定編碼的 numpy 陣列
face = detector.detectMultiScale(gray) # 擷取人臉區域
for(x,y,w,h) in face:
faces.append(img_np[y:y+h,x:x+w]) # 記錄川普人臉的位置和大小內像素的數值
ids.append(2) # 記錄川普人臉對應的 id,只能是整數,都是 1 表示川普的 id 為 1
print('camera...') # 提示啟用相機
cap = cv2.VideoCapture(0) # 啟用相機
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, img = cap.read() # 讀取影片的每一幀
if not ret:
print("Cannot receive frame")
break
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 色彩轉換成黑白
img_np = np.array(gray,'uint8') # 轉換成指定編碼的 numpy 陣列
face = detector.detectMultiScale(gray) # 擷取人臉區域
for(x,y,w,h) in face:
faces.append(img_np[y:y+h,x:x+w]) # 記錄自己人臉的位置和大小內像素的數值
ids.append(3) # 記錄自己人臉對應的 id,只能是整數,都是 1 表示川普的 id
cv2.imshow('oxxostudio', img) # 顯示攝影機畫面
if cv2.waitKey(100) == ord('q'): # 每一毫秒更新一次,直到按下 q 結束
break
print('training...') # 提示開始訓練
recog.train(faces,np.array(ids)) # 開始訓練
recog.save('face.yml') # 訓練完成儲存為 face.yml
print('ok!')
已經訓練好 yml 模型檔後,就可以開始進行辨識,當辨識到人臉,會回傳 id 與該 id 的信心指數 confidence,信心指數數值越小表示越準確,藉由 id 與信心指數就能判斷出現在畫面中的人臉,並進一步標記對應的名字,下方的程式碼會標記出菜英文、川普以及 oxxostudio 三個人臉,如果辨識的人臉不屬於這三個人,則會標記 ??? 的文字。
import cv2
recognizer = cv2.face.LBPHFaceRecognizer_create() # 啟用訓練人臉模型方法
recognizer.read('face.yml') # 讀取人臉模型檔
cascade_path = "xml/haarcascade_frontalface_default.xml" # 載入人臉追蹤模型
face_cascade = cv2.CascadeClassifier(cascade_path) # 啟用人臉追蹤
cap = cv2.VideoCapture(0) # 開啟攝影機
if not cap.isOpened():
print("Cannot open camera")
exit()
while True:
ret, img = cap.read()
if not ret:
print("Cannot receive frame")
break
img = cv2.resize(img,(540,300)) # 縮小尺寸,加快辨識效率
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) # 轉換成黑白
faces = face_cascade.detectMultiScale(gray) # 追蹤人臉 ( 目的在於標記出外框 )
# 建立姓名和 id 的對照表
name = {
'1':'Tsai',
'2':'Trump',
'3':'oxxostudio'
}
# 依序判斷每張臉屬於哪個 id
for(x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) # 標記人臉外框
idnum,confidence = recognizer.predict(gray[y:y+h,x:x+w]) # 取出 id 號碼以及信心指數 confidence
if confidence < 60:
text = name[str(idnum)] # 如果信心指數小於 60,取得對應的名字
else:
text = '???' # 不然名字就是 ???
# 在人臉外框旁加上名字
cv2.putText(img, text, (x,y-5),cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2, cv2.LINE_AA)
cv2.imshow('oxxostudio', img)
if cv2.waitKey(5) == ord('q'):
break # 按下 q 鍵停止
cap.release()
cv2.destroyAllWindows()
大家好,我是 OXXO,是個即將邁入中年的斜槓青年,我已經寫了超過 400 篇 Python 的教學,有興趣可以參考下方連結呦~ ^_^
如果把菜英文的「菜打成蔡」就不能發文?這是哪招?
浪費我兩三個小時在找哪裡有問題,只是因為不能打出總統的名字????
這未免太扯,超前部署的網路言論審查嗎?
您好 想請問照片集要放在哪個檔案夾才能訓練~謝謝!!
可以看一下程式碼裡面的路徑,
模型應該是在同一層的 xml 資料夾裡,
臉應該是在 face01 和 face02 資料夾中