OpenCV實現(xiàn)人臉檢測
要實現(xiàn)人臉識別功能,首先要進(jìn)行人臉檢測,判斷出圖片中人臉的位置,才能進(jìn)行下一步的操作。
參考鏈接:
1、OpenCV人臉檢測
2、【OpenCV-Python】32.OpenCV的人臉檢測和識別——人臉檢測
3、【youcans 的圖像處理學(xué)習(xí)課】23. 人臉檢測:Haar 級聯(lián)檢測器
4、OpenCV實戰(zhàn)5:LBP級聯(lián)分類器實現(xiàn)人臉檢測
5、計算機(jī)視覺OpenCv學(xué)習(xí)系列:第十部分、實時人臉檢測
OpenCV人臉檢測方法
在OpenCV中主要使用了兩種特征(即兩種方法)進(jìn)行人臉檢測,Haar特征和LBP特征。用的最多的是Haar特征人臉檢測,此外OpenCV中還集成了深度學(xué)習(xí)方法來實現(xiàn)人臉檢測。
基于Haar特征的人臉檢測
Haar級聯(lián)檢測器預(yù)訓(xùn)練模型下載
在OpenCV中,使用已經(jīng)訓(xùn)練好的XML格式的分類器進(jìn)行人臉檢測。在OpenCV的安裝目錄下的sources文件夾里的data文件夾里或者在github上下載opencv源代碼,在源代碼的data文件夾里都可以找到模型文件:
https://github.com/opencv/opencv/tree/4.x/data
haarcascade_eye.xml, 眼睛
haarcascade_eye_tree_eyeglasses.xml, 戴眼鏡的眼睛
haarcascade_frontalcatface.xml, 正面貓臉
haarcascade_frontalcatface_extended.xml, 正面貓臉
haarcascade_frontalface_alt.xml, 正面人臉
haarcascade_frontalface_alt2.xml, 正面人臉
haarcascade_frontalface_alt_tree.xml, 正面人臉
haarcascade_frontalface_default.xml, 正面人臉
haarcascade_fullbody.xml, 人體
haarcascade_lefteye_2splits.xml, 左眼
haarcascade_license_plate_rus_16stages.xml,
haarcascade_lowerbody.xml,
haarcascade_profileface.xml,
haarcascade_righteye_2splits.xml, 右眼
haarcascade_russian_plate_number.xml,
haarcascade_smile.xml, 笑臉
haarcascade_upperbody.xml, 上身
Haar 級聯(lián)分類器
基于 Haar 特征的級聯(lián)分類器是 Paul Viola 在論文”Rapid Object Detection using a Boosted Cascade of Simple Features”中提出的一種目標(biāo)檢測方法。
Haar 級聯(lián)分類器在每一級的節(jié)點中,使用 AdaBoost 算法學(xué)習(xí)一個高檢測率低拒絕率的多層分類器。其特點是:
- 使用 Haar-like 輸入特征,對矩形圖像區(qū)域的和或者差進(jìn)行閾值化。
- 使用積分圖像計算 45°旋轉(zhuǎn)區(qū)域的像素和,加速 Haar-like 輸入特征的計算。
- 使用統(tǒng)計 Boosting 來創(chuàng)建二分類(人臉/非人臉)的分類器節(jié)點(高通過率,低拒絕率)。
- 將弱分類器并聯(lián)組合起來,構(gòu)成篩選式級聯(lián)分類器。
各級的 Boosting 分類器對于有人臉的檢測窗口都能通過,同時拒絕一小部分非人臉的檢測窗口,并將通過的檢測窗口傳給下一個分類器。依次類推,最后一個分類器將幾乎所有非人臉的檢測窗口都拒絕掉,只剩下有人臉的檢測窗口。因此,只要檢測窗口區(qū)域通過了所有各級 Boosting 分類器,則認(rèn)為檢測窗口中有人臉。
在實際應(yīng)用中輸入圖片的尺寸較大,需要進(jìn)行多區(qū)域、多尺度的檢測。多區(qū)域是要遍歷圖片的不同位置,多尺度是為了檢測圖片中不同大小的人臉。
在 Haar 級聯(lián)分類人臉檢測器中,主要利用了人臉的結(jié)構(gòu)化特征:
1)與臉頰相比,眼部顏色較深
2)與眼睛相比,鼻梁區(qū)域較為明亮
3)眼睛、嘴巴、鼻子的位置較為固定
通過這 5 個矩形區(qū)域的明暗關(guān)系,就可以形成對人臉的各個部分的判別特征。例如在下圖中,第一個特征檢測眼部和上臉頰之間的強(qiáng)度差異,第二個特征檢測雙眼的間距。
Haar 人臉檢測正臉檢測識別率很高,但對側(cè)臉的檢測性能較差。
OpenCV-Python實現(xiàn)
使用 Haar 級聯(lián)檢測器檢測圖片中的人臉的步驟:
(1)創(chuàng)建一個 CascadeClassifier 級聯(lián)分類器對象,從 .xml 文件加載級聯(lián)分類器模型。
(2)讀取待檢測的圖片。
(3)使用 detectMultiScale() 方法檢測圖片,返回檢測到的面部或眼睛的邊界矩形。
(4)將檢測到的邊界矩形繪制到檢測圖片上。
OpenCV 中定義了級聯(lián)分類器類 cv::CascadeClassifier。在 Python 語言中,使用接口函數(shù) cv2.CascadeClassifier() 從文件創(chuàng)建分類器。成員函數(shù) cv.CascadeClassifier.detectMultiScale() 用于執(zhí)行對圖像進(jìn)行目標(biāo)檢測。
import cv2
cv2.CascadeClassifier.detectMultiScale(image[, scaleFactor=1.1, minNeighbors=3, flags=0, minSize=Size(), maxSize=Size()]) → objects
參數(shù)說明:
- filename:加載分類器模型的文件路徑和名稱,字符串。加載的級聯(lián)分類器模型文件,擴(kuò)展名為 .xml。
- image:待檢測的輸入圖像,CV_8U 格式。
- scaleFactor:搜索窗口的縮放比例,默認(rèn)值為1.1。
- minNeighbors:表示構(gòu)成檢測目標(biāo)的相鄰矩形的最小個數(shù),默認(rèn)值為 3。
- flags:版本兼容標(biāo)志,默認(rèn)值為 0。
- minSize:檢測目標(biāo)的最小尺寸,元組 (h,w)。
- maxSize:檢測目標(biāo)的最大尺寸,元組 (h,w)。
返回值
- objects:返回值,檢測目標(biāo)的矩形邊界框 ,是形如 (N,4) 的Numpy數(shù)組。每行有 4個元素 (x, y, width, height) 表示矩形框的左上頂點坐標(biāo) (x,y) 和寬度 width、高度 height。
使用Haar 級聯(lián)檢測器檢測圖片中的人臉:
import numpy as np
import cv2 as cv
if __name__ == '__main__':
# (6) 使用 Haar 級聯(lián)分類器 預(yù)訓(xùn)練模型 檢測人臉
# 讀取待檢測的圖片
img = cv.imread("../data/single.jpg")
print(img.shape)
# 加載 Haar 級聯(lián)分類器 預(yù)訓(xùn)練模型
model_path = "../data/haarcascade_frontalface_alt2.xml"
face_detector = cv.CascadeClassifier(model_path) # <class 'cv2.CascadeClassifier'>
# 使用級聯(lián)分類器檢測人臉
faces = face_detector.detectMultiScale(img, scaleFactor=1.1, minNeighbors=1,
minSize=(30, 30), maxSize=(300, 300))
print(faces.shape) # (17, 4)
print(faces[0]) # (x, y, width, height)
# 繪制人臉檢測框
for x, y, width, height in faces:
cv.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
# 顯示圖片
cv.imshow("faces", img)
cv.waitKey(0)
cv.destroyAllWindows()
使用Haar 級聯(lián)檢測器檢測圖片中的人眼:
人眼檢測的方法與人臉檢測方法相同,只是使用了不同的預(yù)訓(xùn)練模型,例如 haarcascade_eye.xml。
由于眼睛比人臉的尺寸小,因此減小了檢測函數(shù) detectMultiScale() 的參數(shù) minSize=(20, 20)。
此外scaleFactor和minNeighbors也會影響到檢測出的人眼個數(shù)。
import cv2 as cv
if __name__ == '__main__':
# (7) 使用 Haar 級聯(lián)分類器 預(yù)訓(xùn)練模型 檢測人眼
# 讀取待檢測的圖片
img = cv.imread("./data/single.jpg")
print(img.shape)
# 加載 Haar 級聯(lián)分類器 預(yù)訓(xùn)練模型
model_path = "./data/haarcascade_eye.xml"
eye_detector = cv.CascadeClassifier(model_path) # <class 'cv2.CascadeClassifier'>
# 使用級聯(lián)分類器檢測人臉
eyes = eye_detector.detectMultiScale(img, scaleFactor=1.1, minNeighbors=10,
minSize=(10, 10), maxSize=(80, 80))
# 繪制人臉檢測框
for x, y, width, height in eyes:
cv.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
# 顯示圖片
cv.imshow("Haar_Cascade", img)
# cv.imwrite("../images/imgSave3.png", img)
cv.waitKey(0)
cv.destroyAllWindows()
scaleFactor=1.1, minNeighbors=10
scaleFactor=1.1, minNeighbors=5
使用 Haar 級聯(lián)檢測器同時檢測人臉和人眼
為了提高檢測效率,可以先檢測人臉,再在人類窗口內(nèi)檢測人眼,不僅可以提高檢測效率,而且可以提高檢測精度。
import cv2 as cv
if __name__ == '__main__':
# (8) 使用 Haar 級聯(lián)分類器 預(yù)訓(xùn)練模型 檢測人臉和人眼
# 讀取待檢測的圖片
img = cv.imread("./data/multiface1.jpeg")
print(img.shape)
# 加載 Haar 級聯(lián)分類器 預(yù)訓(xùn)練模型
face_path = "./data/haarcascade_frontalface_alt2.xml" # 人臉檢測器
face_detector = cv.CascadeClassifier(face_path) # <class 'cv2.CascadeClassifier'>
eye_path = "./data/haarcascade_eye.xml" # 人眼檢測器
eye_detector = cv.CascadeClassifier(eye_path) # <class 'cv2.CascadeClassifier'>
# 使用級聯(lián)分類器檢測人臉
faces = face_detector.detectMultiScale(img, scaleFactor=1.1, minNeighbors=5,
minSize=(30, 30), maxSize=(300, 300))
print(faces.shape) # (15, 4)
# 繪制人臉檢測框
for x, y, width, height in faces:
cv.rectangle(img, (x, y), (x + width, y + height), (0, 0, 255), 2, cv.LINE_8, 0)
# 在人臉區(qū)域內(nèi)檢測人眼
roi = img[y:y + height, x:x + width] # 提取人臉
# 檢測人眼
eyes = eye_detector.detectMultiScale(roi, scaleFactor=1.1, minNeighbors=1,
minSize=(2, 2), maxSize=(80, 80))
# 繪制人眼
for ex, ey, ew, eh in eyes:
cv.rectangle(img, (x+ex, y+ey), (x+ex+ew, y+ey+eh), (255, 0, 0), 2)
# 顯示圖片
cv.imshow("Haar_Cascade", img)
# cv.imwrite("../images/imgSave4.png", img)
cv.waitKey(0)
cv.destroyAllWindows()
可以看到對于比較正常的人臉檢測效果還是不錯的(需要手動調(diào)整detectMultiScale()方法的參數(shù)),但是對于側(cè)臉、歪臉、小臉的檢測效果就不太理想了,而且對于眼睛的檢測只能畫框,不能實現(xiàn)關(guān)鍵點檢測,現(xiàn)在在考慮利用這個人眼檢測轉(zhuǎn)換成關(guān)鍵點來做人臉對齊,后面再看看效果。
基于深度學(xué)習(xí)的人臉檢測
OpenCV的深度神經(jīng)網(wǎng)絡(luò)(Deep Neural Network,DNN)模塊提供了基于深度學(xué)習(xí)的人臉檢測器。DNN模塊中使用了廣受歡迎的深度學(xué)習(xí)框架,包括Caffe、TensorFlow、Torch和Darknet等。
OpenCV提供了兩個預(yù)訓(xùn)練的人臉檢測模型:Caffe和TensorFlow模型。
Caffe模型需要加載以下兩個文件:
- deploy.prototxt:定義模型結(jié)構(gòu)的配置文件
- res10_300x300_ssd_iter_140000_fp16.caffemodel:包含實際層權(quán)重的訓(xùn)練模型文件
TensorFlow模型需要加載以下兩個文件:
- opencv_face_detector_uint8.pb:定義模型結(jié)構(gòu)的配置文件
- opencv_face_detector.pbtxt:包含實際層權(quán)重的訓(xùn)練模型文件
在OpenCV源代碼的“\samples\dnn\face_detector”的文件夾中提供了模型配置文件,但未提供模型訓(xùn)練文件??蛇\(yùn)行該文件夾中的download_models.py文件下載上述兩個訓(xùn)練模型文件?;蛑苯釉诠俜芥溄觝ttps://github.com/spmallick/learnopencv/find/master(這個鏈接太難下了)下載,在這個鏈接下載:OpenCV學(xué)堂/OpenCV課程資料https://gitee.com/opencv_ai/opencv_tutorial_data(關(guān)鍵時刻靠Gitee)
(在搜索框中輸入Age進(jìn)行搜索,不然找不到)??
使用預(yù)訓(xùn)練的模型執(zhí)行人臉檢測時主要包含下列步驟:
(1) 調(diào)用cv2.dnn.readNetFromCaffe()或cv2.dnn.readNetFromTensorflow()函數(shù)加載模型,創(chuàng)建檢測器。
(2) 調(diào)用cv2.dnn.blobFromImage()函數(shù)將待檢測圖像轉(zhuǎn)換為圖像塊數(shù)據(jù)。
(3) 調(diào)用檢測器的setInput()方法將圖像塊數(shù)據(jù)設(shè)置為模型的輸入數(shù)據(jù)。
(4) 調(diào)用檢測器的forward()方法執(zhí)行計算,獲得預(yù)測結(jié)果。
(5) 將可信度高于指定值的預(yù)測結(jié)果作為檢測結(jié)果,在原圖中標(biāo)注人臉,同時輸出可信度作為參考。
單張圖片檢測
# 基于深度學(xué)習(xí)的人臉檢測(臉-眼_視頻)
import cv2
import numpy as np
# dnnnet = cv2.dnn.readNetFromCaffe("deploy.prototxt", "res10_300x300_ssd_iter_140000_fp16.caffemodel")
dnnnet = cv2.dnn.readNetFromTensorflow("./data/opencv_face_detector_uint8.pb", "./data/opencv_face_detector.pbtxt")
img = cv2.imread("./data/multiface1.jpeg")
h, w = img.shape[:2]
blobs = cv2.dnn.blobFromImage(img, 1.0, (300, 300), [104., 117., 123.], False, False)
dnnnet.setInput(blobs)
detections = dnnnet.forward()
faces = 0
for i in range(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > 0.6:
faces += 1
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
x1,y1,x2,y2 = box.astype("int")
y = y1 - 10 if y1 - 10 > 10 else y1 + 10
text = "%.3f"%(confidence * 100)+'%'
cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)
cv2.putText(img,text, (x1, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
cv2.imshow('faces',img)
cv2.waitKey(0)
cv2.destroyAllWindows()
相比之下,還是深度學(xué)習(xí)模型的效果更勝一籌。
視頻檢測
import cv2
import numpy as np
# win7系統(tǒng)在代碼中所有的cv2.VideoCapture要加cv2.CAP_DSHOW,不然會報錯
capture = cv2.VideoCapture(0, cv2.CAP_DSHOW)
frame_width = capture.get(cv2.CAP_PROP_FRAME_WIDTH)
frame_height = capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
fps = capture.get(cv2.CAP_PROP_FPS)
dnnnet = cv2.dnn.readNetFromTensorflow("./data/opencv_face_detector_uint8.pb", "./data/opencv_face_detector.pbtxt")
if capture.isOpened() is False:
print('CAMERA ERROR !')
exit(0)
while capture.isOpened():
ret, frame = capture.read()
if ret is True:
# cv2.imshow('FRAME', frame) # 顯示捕獲的幀
h, w = frame.shape[:2]
blobs = cv2.dnn.blobFromImage(frame, 1.0, (300, 300), [104., 117., 123.], False, False)
dnnnet.setInput(blobs)
detections = dnnnet.forward()
faces = 0
for i in range(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
if confidence > 0.6:
faces += 1
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
x1, y1, x2, y2 = box.astype("int")
y = y1 - 10 if y1 - 10 > 10 else y1 + 10
text = "%.3f" % (confidence * 100) + '%'
cv2.rectangle(frame, (x1, y1), (x2, y2), (255, 0, 0), 2)
cv2.putText(frame, text, (x1, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
cv2.imshow('faces', frame)
k = cv2.waitKey(1)
if k == ord('q'):
break
else:
break
capture.release()
cv2.destroyAllWindows()
把手機(jī)放在攝像頭前進(jìn)行檢測,可以看到有些人臉還是檢測不出來,后面可以考慮加入活體檢測。
傳統(tǒng)視覺方法與深度學(xué)習(xí)方法對比
針對同一段視頻文件,速度與檢測總數(shù)統(tǒng)計比較
OpenCV實現(xiàn)人臉識別
參考鏈接:
1、opencv的人臉面部識別(主要代碼參考)
2、【OpenCV-Python】33.OpenCV的人臉檢測和識別——人臉識別
自己根據(jù)博主的代碼做了適當(dāng)?shù)男薷?,符合自己項目的要?/p>
OpenCV 有三種人臉識別的算法:
特征臉(Eigenfaces)人臉識別 是通過 PCA(主成分分析)實現(xiàn)的,它識別人臉數(shù)據(jù)集的主成分,并計算出待識別圖像區(qū)域相對于數(shù)據(jù)集的發(fā)散程度(0-20k),該值越小,表示差別越小,0值代表完全匹配。低于4k-5k都是相當(dāng)可靠的識別。
EigenFaces人臉識別的基本步驟如下:
(1) 調(diào)用cv2.face.EigenFaceRecognizer_create()方法創(chuàng)建EigenFace識別器。
(2) 調(diào)用識別器的train()方法以便使用已知圖像訓(xùn)練模型。
(3) 調(diào)用識別器的predict()方法以便使用未知圖像進(jìn)行識別,確認(rèn)其身份。
cv2.face.EigenFaceRecognizer_create()函數(shù)的基本格式如下:
recognizer = cv2.face.EigenFaceRecognizer_create([num_components[, threshold]])
# recognizer為返回的EigenFaces識別器對象
# num_components為分析時的分量數(shù)量, 默認(rèn)為0, 表示根據(jù)實際輸入決定
# threshold為人臉識別時采用的閾值
EigenFaces識別器的train()方法的基本格式如下:
recognizer.train(src, label)
# src為用于訓(xùn)練的已知圖像數(shù)組, 所有圖像必須為灰度圖且大小要相同
# label為標(biāo)簽數(shù)組, 與已知圖像數(shù)組中的人臉一一對應(yīng), 同一個人的人臉標(biāo)簽應(yīng)設(shè)置為相同值
EigenFaces識別器的predict()方法的基本格式如下:
label, confidence = recoginer.predict(testimg)
# label為返回的標(biāo)簽值
# confidence為返回的可信度, 表示未知人臉和模型中已知人臉之間的距離, 0表示完全匹配, 低于5000可認(rèn)為是可靠的匹配結(jié)果
# test_img為未知人臉圖像, 圖像必須為灰度圖且大小要與訓(xùn)練圖像相同
人魚臉(FisherFaces)人臉識別 是從 PCA發(fā)展而來,使用線性判別分析(Linear Discriminant Analysis,LDA)方法實現(xiàn)人臉識別,采用更復(fù)雜的計算,容易得到更準(zhǔn)確的結(jié)果。低于4k~5k都是相當(dāng)可靠的識別。
FisherFaces人臉識別的基本步驟如下:
(1) 調(diào)用cv2.face.FisherFaceRecognizer_create()方法創(chuàng)建FisherFaces識別器。
(2) 調(diào)用識別器的train()方法以便使用已知圖像訓(xùn)練模型。
(3) 調(diào)用識別器的predict()方法以便使用未知圖像進(jìn)行識別,確認(rèn)其身份。
在OpenCV中,cv2.face.EigenFaceRecognizer類和cv2.face.FisherFaceRecognizer類同屬于cv2.face.BasicFaceRecognizer類、cv2.face.FaceRecognizer類和cv2.Algorithm類的子類,對應(yīng)的xxx_create()、train()和predict()等方法的基本格式與用法相同。
局部二進(jìn)制編碼直方圖(Local Binary Patterns Histograms,LBPH)人臉識別 將人臉分成小單元,并將其與模型中的對應(yīng)單元進(jìn)行比較,對每個區(qū)域的匹配值產(chǎn)生一個直方圖。它允許待檢測人臉區(qū)域可以和數(shù)據(jù)集中圖像的形狀、大小不同,更方便靈活。參考值低于50則算是好的識別,高于80則認(rèn)為比較差。
LBPH算法處理圖像的基本原理如下:
(1) 取像素x周圍(鄰域)的8個像素與其比較,像素值比像素x大的取0,否則取1。將8個像素對應(yīng)的0、1連接得到一個8位二進(jìn)制數(shù),將其轉(zhuǎn)換為十進(jìn)制,作為像素x的LBP值。
(2) 對像素的所有像素按相同的方法進(jìn)行處理,得到整個圖像的LBP值,該圖像的直方圖就是圖像的LBPH。
LBPH人臉識別的基本步驟如下;
(1) 調(diào)用cv2.face.LBPHFaceRecognizer_create()方法創(chuàng)建LBPH識別器。
(2) 調(diào)用識別器的train()方法以便使用已知圖像訓(xùn)練模型。
(3) 調(diào)用識別器的predict()方法以便使用未知圖像進(jìn)行識別,確認(rèn)其身份。
cv2.face.LBPHFaceRecognizer_create()函數(shù)的基本格式如下:
recognizer = cv2.face.LBPHFaceRecognizer_create([radius[, neighbors[, grid_x[, grid_y[, threshold]]]]])
# recognizer為返回的LBPH識別器對象
# radius為鄰域的半徑大小
# neighbors為鄰域內(nèi)像素點的數(shù)量, 默認(rèn)為8
# grid_x為將LBP圖像劃分為多個單元格時, 水平方向上的單元格數(shù)量, 默認(rèn)為8
# grid_y為將LBP圖像劃分為多個單元格時, 垂直方向上的單元格數(shù)量, 默認(rèn)為8
# threshold為人臉識別時采用的閾值
LBPH識別器的train()方法的基本格式如下:
recognizer.train(src, label)
# src為用于訓(xùn)練的已知圖像數(shù)組, 所有圖像必須為灰度圖且大小要相同
# label為標(biāo)簽數(shù)組, 與已知圖像數(shù)組中的人臉一一對應(yīng), 同一個人的人臉標(biāo)簽應(yīng)設(shè)置為相同值
LBPH識別器的predict()方法的基本格式如下:
label, confidence = recoginer.predict(testimg)
# label為返回的標(biāo)簽值
# confidence為返回的可信度, 表示未知人臉和模型中已知人臉之間的距離, 0表示完全匹配, 低于50可認(rèn)為是非??煽康钠ヅ浣Y(jié)果
# test_img為未知人臉圖像, 圖像必須為灰度圖且大小要與訓(xùn)練圖像相同
制作數(shù)據(jù)集
不管使用哪種算法都需要有訓(xùn)練集。從視頻或者動圖創(chuàng)建訓(xùn)練集的效率比較高??梢詮木W(wǎng)上下載或者自己寫一個攝像頭捕獲程序進(jìn)行采集。本次實驗直接從網(wǎng)上下載了一些明星的動圖,然后將動圖按幀分解,使用OpenCV中的Haar級聯(lián)器檢測人臉區(qū)域,然后將人臉區(qū)域全部存為200X200的灰度圖,存入對應(yīng)的文件夾中,創(chuàng)建訓(xùn)練集。
from PIL import Image
import os
import cv2
import numpy as np
# GIF動圖轉(zhuǎn)圖片
def gifSplit2Array(gif_path):
import numpy as np
img = Image.open(os.path.join(path, gif_path))
for i in range(img.n_frames):
img.seek(i)
new = Image.new("RGBA", img.size)
new.paste(img)
arr = np.array(new).astype(np.uint8) # image: img (PIL Image):
yield arr[:, :, 2::-1] # 逆序(RGB 轉(zhuǎn)BGR), 舍棄alpha通道, 輸出數(shù)組供openCV使用
# 人臉檢測
def face_generate(img):
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
front_face_cascade = cv2.CascadeClassifier('./data/haarcascade_frontalface_alt2.xml') # 檢測正臉
faces0 = front_face_cascade.detectMultiScale(gray, 1.02, 5)
eye_cascade = cv2.CascadeClassifier('./data/haarcascade_eye_tree_eyeglasses.xml') # 檢測眼睛
if faces0 is not None:
for (x, y, w, h) in faces0:
face_area = gray[y: y + h, x: x + w] # (疑似)人臉區(qū)域
quasi_eyes = eye_cascade.detectMultiScale(face_area, 1.03, 5, 0) # 在人臉區(qū)域檢測眼睛
if len(quasi_eyes) == 0: continue
quasi_eyes = tuple(
filter(lambda x: x[2] / w > 0.18 and x[1] < 0.5 * h, quasi_eyes)) # ex,ey,ew,eh; ew/w>0.18,尺寸過濾 ,且眼睛在臉的上半部
if len(quasi_eyes) <= 1: continue
yield cv2.resize(face_area, (200, 200))
# 制作數(shù)據(jù)集
def get_dataset(path, gif_list):
i = 0
all_items = os.listdir(path)
print(all_items)
for item in all_items:
name = item.split('-')[0]
name_path = os.path.join(path, name)
if not os.path.exists(name_path):
os.mkdir(name_path)
for gif in gif_list:
print(gif)
for img in gifSplit2Array(gif):
for face in face_generate(img):
cv2.imwrite("./dataset/%s/%s.pgm" % (gif.split('-')[0], i), face)
# print(i)
i += 1
if __name__ == '__main__':
path = './dataset'
gif_list = ["Yangmi-1.gif", "Yangmi-2.gif", "Yangmi-3.gif", "Liushishi-1.gif", "Liushishi-2.gif", "Liushishi-3.gif"]
get_dataset(path, gif_list)
加載數(shù)據(jù)集
將所有數(shù)據(jù)放在一個ndarray數(shù)組中
def load_dataset(datasetPath):
names = []
X = []
y = []
ID = 0
for name in os.listdir(datasetPath):
subpath = os.path.join(datasetPath, name)
if os.path.isdir(subpath):
names.append(name)
for file in os.listdir(subpath):
im = cv2.imread(os.path.join(subpath, file), cv2.IMREAD_GRAYSCALE)
X.append(np.asarray(im, dtype=np.uint8))
y.append(ID)
ID += 1
X = np.asarray(X)
y = np.asarray(y, dtype=np.int32)
return X, y, names
訓(xùn)練數(shù)據(jù)集
X, y, names = load_dataset(path)
# 報錯找不到face模塊是因為只安裝了主模塊
# pip uninstall opencv-python, pip install opencv0-contrib-python
# 創(chuàng)建人臉識別模型(三種識別模式)
# model = cv2.face.EigenFaceRecognizer_create() #createEigenFaceRecognizer()函數(shù)已被舍棄
# model = cv2.face.FisherFaceRecognizer_create()
model = cv2.face.LBPHFaceRecognizer_create()
model.train(X, y)
單張圖片測試
注意:將face_generate()函數(shù)最后一行改為
yield cv2.resize(face_area, (200, 200)), x, y, w, h
開始進(jìn)行測試
path = './dataset'
infer_path = './data/Yangmi.jpeg'
# gif_list = ["Yangmi-1.gif", "Yangmi-2.gif", "Yangmi-3.gif", "Liushishi-1.gif", "Liushishi-2.gif", "Liushishi-3.gif"]
# get_dataset(path, gif_list)
X, y, names = load_dataset(path)
# 報錯找不到face模塊是因為只安裝了主模塊
# pip uninstall opencv-python, pip install opencv0-contrib-python
# 創(chuàng)建人臉識別模型(三種識別模式)
# model = cv2.face.EigenFaceRecognizer_create() #createEigenFaceRecognizer()函數(shù)已被舍棄
# model = cv2.face.FisherFaceRecognizer_create()
model = cv2.face.LBPHFaceRecognizer_create()
model.train(X, y)
img = cv2.imread(infer_path)
for roi, x, y, w, h in face_generate(img):
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2) # 畫紅色矩形框標(biāo)記正臉
ID_predict, confidence = model.predict(roi) # 預(yù)測?。。?/span>
name = names[ID_predict]
print("name:%s, confidence:%.2f" % (name, confidence))
text = name if confidence < 70 else "unknow" # 10000 for EigenFaces #70 for LBPH
cv2.putText(img, text, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) # 繪制綠色文字
cv2.imshow('', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
測試效果:文章來源:http://www.zghlxwxcb.cn/news/detail-715630.html
補(bǔ)充: 這個實現(xiàn)方法完全使用opencv中的自帶方法,目前只是進(jìn)行了單張圖片的識別,并且數(shù)據(jù)集比較小,在實際的環(huán)境中識別效果有待驗證,并且沒有加入自己寫的人臉對齊程序,后面希望能結(jié)合進(jìn)去,提高識別效果文章來源地址http://www.zghlxwxcb.cn/news/detail-715630.html
到了這里,關(guān)于使用OpenCV工具包成功實現(xiàn)人臉檢測與人臉識別,包括傳統(tǒng)視覺和深度學(xué)習(xí)方法(附完整代碼,模型下載......)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!