[ 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))