[ OpenCV ] 利用 OpenCV進行臉部辨識批量訓練
透過上一章 "利用 OpenCV抓取影片中的臉部數據",有了大量的圖片數據後,可能沒有辦法像之前一樣,全部一起訓練模型,必須採用批量訓練。
但模型更新受到一定的限制,官方說法是只有 Local Binary Pattern Histogram ( LBPH )可以對模型進行更新。所以本章只會使用 LBPH練習。
開始訓練前的資料夾結構如下
os.walk抓取也會抓取資料夾中的資料夾內的資料,所以可能要避免讀取移動過的資料(代碼中有提到)。
每當 list中有 50筆資料時就訓練,訓練後移動,移動後就把所有的 list清空。
最後把未滿 50筆的資料也重複一樣的動作。
模型的部分,代碼開頭先建立 LBPH模型,檢查有沒有之前訓練儲存的 xml檔,有就讀取。
model_training function中,一樣先檢查 xml檔,沒有就訓練新的,有就更新。完成後存檔。
訓練數據共使用了九位成員的 TT前導宣傳短片做數據捕捉,大約抓了 5000多張相片來訓練這個模型。
對這幾部影片有興趣的話可以點擊這裡,可以在右邊的 list看到許多由 JYP娛樂提供的影片。
接著就拿它來進行辨識吧。
比較值得注意的是第 33行的 "if params[1] < 80:",這裡可以對精度設定條件,再決定要不要加上標籤。
Eigenfaces、Fisherfaces和 LBPH顯示出的數字對精度的定義不太一樣,這裡也需要注意一下。
本篇是針對 LBPH設定,至於要設定多少,我也不好拿捏,不過數字越低,則表示預測的可靠度越高。
matplotlib.pyplot的部分被著解掉了,因為實在太消耗資源了,處理速度慢太多了。
接著我把臉部偵測的條件降低,眼睛至少偵測到一隻,就進行辨識,若辨識不出來或不精準精度高過 80就不顯示。
利用這個辨識模型製作了下面兩部影片。
(實際捕捉時的參數不一定和上面的代碼一樣,辨識不同的素材時,多少做了些修改,所以用上面的代碼可能是某次調適時所設定的,不一定會得到一樣的結果。)
第一部是使用了相同訓練素材製作的 MV,影片中的精度還算高,當然也因為有對精度進行篩選。
第二部也是使用了相同的模型對沒有訓練過的影片進行辨識,但可能因為造型變化大,且鏡頭移動快速,結果慘不人睹。
其實嘗試辨識了五六部影片的,但有些因為臉部捕捉率太低,或是版權問題無法分享,
由於對 OpenCV的辨識系統沒有很了解,但下意識覺得有可能是 Overfitting之類的問題,或是訓練數據仍不夠或品質不佳等原因。
有機會再來用 Face Alignment的方式提高數據品質,還有機會的話也來做個用深度學習的辨識系統。
但模型更新受到一定的限制,官方說法是只有 Local Binary Pattern Histogram ( LBPH )可以對模型進行更新。所以本章只會使用 LBPH練習。
開始訓練前的資料夾結構如下
. ├── Chaeyoung │ └── ... ├── Dahyun │ └── ... ├── Jeongyeon │ └── ... ├── Jihyo │ └── ... ├── Mina │ └── ... ├── Momo │ └── ... ├── Nayeon │ └── ... ├── Sana │ └── ... ├── Tzuyu │ └── ... └── model_train.pymodel_train.py代碼如下
import os
import cv2
import numpy as np
batch = 50
names = ["Nayeon", "Jeongyeon", "Momo", "Sana", "Jihyo", "Mina", "Dahyun", "Chaeyoung", "Tzuyu"]
model_LBPH = cv2.face.createLBPHFaceRecognizer()
if os.path.isfile("./twice_model_LBPH.xml"):
model_LBPH.load("twice_model_LBPH.xml")
trained_data = 0
def model_training(x,y):
if not os.path.isfile("./twice_model_LBPH.xml"):
model_LBPH.train(np.asarray(x), np.asarray(y))
else:
model_LBPH.update(np.asarray(x), np.asarray(y))
model_LBPH.save("twice_model_LBPH.xml")
global trained_data
trained_data = trained_data + len(y)
print("Model are trained {0} images".format(trained_data))
def move_trained_image(image_paths, trained_folders):
for image_path, trained_folder in zip(image_paths, trained_folders):
if not os.path.isdir(trained_folder):
os.system("mkdir {0}".format(trained_folder))
print("Create {0}".format(trained_folder))
os.system("mv {0} {1}".format(image_path, trained_folder))
print("Moved {0} images".format(len(image_paths)))
x,y = [],[]
image_paths, trained_folders = [],[]
for label,member in enumerate(names):
for fileNames in os.walk("./{0}".format(member)):
if ("./{0}/trained".format(member)) == fileNames[0]: # 避免 os.walk爬到第二層導致錯誤。
continue
for fileName in fileNames[-1]:
if fileName.endswith('.png'):
image_paths.append("./{0}/{1}".format(member, fileName))
trained_folders.append("./{0}/trained".format(member))
img = cv2.imread("./{0}/{1}".format(member, fileName), cv2.IMREAD_GRAYSCALE)
x.append(img)
y.append(label)
if len(y)!=0 and len(y)%batch == 0:
model_training(x,y)
move_trained_image(image_paths,trained_folders)
x,y = [],[]
image_paths, trained_folders = [],[]
if len(y)!=0:
model_training(x,y)
move_trained_image(image_paths,trained_folders)
x,y = [],[]
image_paths, trained_folders = [],[]
print("Done!!")
訓練數據的部分一樣透過 os.walk抓取,訓練後會將訓練過的照片移動到底下的 trained資料夾中。os.walk抓取也會抓取資料夾中的資料夾內的資料,所以可能要避免讀取移動過的資料(代碼中有提到)。
每當 list中有 50筆資料時就訓練,訓練後移動,移動後就把所有的 list清空。
最後把未滿 50筆的資料也重複一樣的動作。
模型的部分,代碼開頭先建立 LBPH模型,檢查有沒有之前訓練儲存的 xml檔,有就讀取。
model_training function中,一樣先檢查 xml檔,沒有就訓練新的,有就更新。完成後存檔。
訓練數據共使用了九位成員的 TT前導宣傳短片做數據捕捉,大約抓了 5000多張相片來訓練這個模型。
對這幾部影片有興趣的話可以點擊這裡,可以在右邊的 list看到許多由 JYP娛樂提供的影片。
接著就拿它來進行辨識吧。
import cv2
import numpy as np
# import matplotlib.pyplot as plt
names = ["Nayeon", "Jeongyeon", "Momo", "Sana", "Jihyo", "Mina", "Dahyun", "Chaeyoung", "Tzuyu"]
model_LBPH = cv2.face.createLBPHFaceRecognizer()
model_LBPH.load("twice_model_LBPH.xml")
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
def detect(img, idx):
font_size = 1.2
font_thickness = 3
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray,
scaleFactor=1.1,
minNeighbors=3,
minSize=(130,130),)
for (x,y,w,h) in faces:
roi = gray[y:y+h, x:x+w]
eyes = eye_cascade.detectMultiScale(roi,
scaleFactor=1.06,
minNeighbors=5,
minSize=(30,30),)
if len(eyes)>=1:
try:
roi = cv2.resize(roi, (200,200), interpolation=cv2.INTER_LINEAR)
params = model_LBPH.predict(roi)
print("Label: %s, Confidence: %.2f" % (params[0], params[1]))
if params[1] < 80:
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),3)
cv2.putText(img, names[params[0]], (x+5,y+h-5), cv2.FONT_HERSHEY_SIMPLEX, font_size, (255,0,0), font_thickness)
else:
pass
# img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),3)
# cv2.putText(img, 'Happy partner', (x+5,y+h-5), cv2.FONT_HERSHEY_SIMPLEX, font_size, (255,0,0), font_thickness)
except:
pass
# img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),3)
# cv2.putText(img, 'Happy partner', (x+5,y+h-5), cv2.FONT_HERSHEY_SIMPLEX, font_size, (255,0,0), font_thickness)
print('Working with %s frame' % idx)
return img
input_file = 'twice_song.mp4'
output_file = 'face_twice_song.avi'
videoCapture = cv2.VideoCapture(input_file)
fps = videoCapture.get(cv2.CAP_PROP_FPS)
size = (int(videoCapture.get(cv2.CAP_PROP_FRAME_WIDTH)),
int(videoCapture.get(cv2.CAP_PROP_FRAME_HEIGHT)))
videoWriter = cv2.VideoWriter(output_file, cv2.VideoWriter_fourcc('I','4','2','0'), fps, size)
success, frame = videoCapture.read()
frame_counter = 1
# plt.ion()
while success:
frame = detect(frame, frame_counter)
videoWriter.write(frame)
# plt.imshow(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
# plt.pause(.01)
# plt.cla() # Clear axis
# plt.clf() # Clear figure
success, frame = videoCapture.read()
frame_counter += 1
# plt.ioff()
print("Done!!")
內容與 "利用 OpenCV進行臉部辨識" 這張相當類似,參數的部分可以參考該篇。比較值得注意的是第 33行的 "if params[1] < 80:",這裡可以對精度設定條件,再決定要不要加上標籤。
Eigenfaces、Fisherfaces和 LBPH顯示出的數字對精度的定義不太一樣,這裡也需要注意一下。
本篇是針對 LBPH設定,至於要設定多少,我也不好拿捏,不過數字越低,則表示預測的可靠度越高。
matplotlib.pyplot的部分被著解掉了,因為實在太消耗資源了,處理速度慢太多了。
接著我把臉部偵測的條件降低,眼睛至少偵測到一隻,就進行辨識,若辨識不出來或不精準精度高過 80就不顯示。
利用這個辨識模型製作了下面兩部影片。
(實際捕捉時的參數不一定和上面的代碼一樣,辨識不同的素材時,多少做了些修改,所以用上面的代碼可能是某次調適時所設定的,不一定會得到一樣的結果。)
第一部是使用了相同訓練素材製作的 MV,影片中的精度還算高,當然也因為有對精度進行篩選。
第二部也是使用了相同的模型對沒有訓練過的影片進行辨識,但可能因為造型變化大,且鏡頭移動快速,結果慘不人睹。
其實嘗試辨識了五六部影片的,但有些因為臉部捕捉率太低,或是版權問題無法分享,
由於對 OpenCV的辨識系統沒有很了解,但下意識覺得有可能是 Overfitting之類的問題,或是訓練數據仍不夠或品質不佳等原因。
有機會再來用 Face Alignment的方式提高數據品質,還有機會的話也來做個用深度學習的辨識系統。
錯誤/修改:model_train.py代碼如下
回覆刪除os.system("mv {0} {1}".format(image_path, trained_folder))
中在在命令台中顯示
>> 'mv' 不是內部或外部命令、可執行的程式或批次檔。
這裡的'mv'須改為 'move'
os.system("move {0} {1}".format(image_path, trained_folder))