這篇文章的話題依然是人臉識(shí)別,不過(guò)僅僅使用了opencv-python以及opencv-contrib-python這兩個(gè)包馋劈,而且就我做的測(cè)試用例來(lái)看識(shí)別的正確率比f(wàn)ace_recognition還要更高攻锰,話不多說(shuō),咱們這就開(kāi)始妓雾。
人臉檢測(cè)
要想做人臉識(shí)別娶吞,人臉檢測(cè)必須是要做的,畢竟識(shí)別也得你檢測(cè)到人臉之后才能辨別械姻。那么如何檢測(cè)到人臉呢妒蛇?提取出圖像的細(xì)節(jié)對(duì)產(chǎn)生穩(wěn)定分類結(jié)果很重要,這些提取的結(jié)果被稱為特征楷拳,專業(yè)的表述為:從圖像數(shù)據(jù)中提取特征绣夺。雖然任意像素都可以能影響多個(gè)特征,但特征應(yīng)該比像素少得多欢揖。兩個(gè)圖像的相似程度可以通過(guò)它們對(duì)應(yīng)特征的歐氏距離來(lái)度量陶耍。 Haar 特征是一種用于實(shí)現(xiàn)實(shí)時(shí)人臉跟蹤的征。每一個(gè) Haar 特征都描述了相鄰圖像區(qū)域的對(duì)比模式她混。例如烈钞,邊、頂點(diǎn)和細(xì)線都能生成具有判別性的特征坤按。獲取 Haar 特征的方法有很多種毯欣,這里我用的是安裝opencv以后opencv安裝目錄里的部分xml文件獲取的,如果你不想安裝opencv的話臭脓,也可以到文末直接下載我打包好的文件酗钞。如果你已經(jīng)安裝了opencv,找到你的安裝目錄来累,一般如下圖:
接著打開(kāi)sources/data/haarcascades文件夾砚作,你會(huì)看到下圖:
我提供的資源就是上圖所示的所有xml文件,不用再在電腦上安裝opencv了佃扼。默認(rèn)的人臉檢測(cè)器是haarcascade_frontalface_default.xml偎巢。當(dāng)然這個(gè)是可以更改的,使用的方法如下:
face_detector = cv2.CascadeClassifier('D:/OPENCV/sources/data/haarcascades/haarcascade_frontalface_default.xml')
for i in range(len(person_list)):
? ? person_name = os.listdir("faces/" + "person_" + str(i + 1))
? ? img_path = "faces/" + "person_" + str(i + 1) + "/" + person_name[0]
? ? # opencv人臉檢測(cè)
? ? PIL_img = Image.open(img_path).convert('L')
? ? img_numpy = np.array(PIL_img, 'uint8')
? ? faces = face_detector.detectMultiScale(img_numpy)
? ? #print(len(faces))
? ? for x,y,w,h in faces:
? ? ? ? face_sampes.append(img_numpy[y:y+h, x:x+w])
? ? ? ? ids.append(i + 1)
face_sampes兼耀,ids是訓(xùn)練數(shù)據(jù)用到的兩個(gè)參數(shù),face_sampes是人臉特征矩陣,ids是每個(gè)人臉對(duì)應(yīng)的id瘤运。
訓(xùn)練數(shù)據(jù)
這部分比較簡(jiǎn)單窍霞,如果有異常應(yīng)該是未安裝opencv-contrib-python導(dǎo)致的,直接上代碼了拯坟。
opencv_recognizer = cv2.face.LBPHFaceRecognizer_create()
opencv_recognizer.train(face_sampes, np.array(ids))
opencv_recognizer.write('train/train.yml')
執(zhí)行完代碼之后會(huì)在當(dāng)前目錄生成train.yml文件但金,人臉識(shí)別的時(shí)候會(huì)用到。
人臉識(shí)別
相信大家都已經(jīng)看到了我在訓(xùn)練數(shù)據(jù)時(shí)使用的代碼郁季,其中opencv_recognizer是比較重要的冷溃,當(dāng)然其實(shí)是cv2.face.LBPHFaceRecognizer_create()比較重要。這個(gè)人臉識(shí)別主要用的是LBPH算法**梦裂。它將檢測(cè)到的人臉?lè)譃樾卧普恚⑵渑c模型中的對(duì)應(yīng)單元進(jìn)行比較,對(duì)每個(gè)區(qū)域的匹配值產(chǎn)生一個(gè)直方圖年柠。由于這種方法的靈活性凿歼,LBPH是唯一允許模型樣本人臉和檢測(cè)到的人臉在形狀、大小上可以不同的人臉識(shí)別算法冗恨。具體的用法見(jiàn)以下代碼答憔。
opencv_recognizer.read('train/train.yml')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
new_faces = face_detector.detectMultiScale(gray)
for x, y, w, h in new_faces:
? ? ? ? cv2.rectangle(img, (x,y), (x+w, y+h), (0, 255, 0), 2)
? ? ? ? id, confidence = opencv_recognizer.predict(gray[y:y+h, x:x+w])
? ? ? ? cv2.putText(img, face_names[id-1]+str(int(confidence)), (x + 6, y + h - 6), font, 1.0, (255, 255, 255), 1)
識(shí)別的主體在predict方法中,它的返回值一個(gè)是id掀抹,一個(gè)是置信度虐拓。id是與人臉一一對(duì)應(yīng)的,好的置信度要低于50傲武,越小越好蓉驹。高于80的置信度都是較差的。然后由于我可以根據(jù)id得到人的姓名谱轨,所以我可以直接把人名實(shí)時(shí)顯示在攝像頭視頻中戒幔,如何做到的歡迎移步這里看我的人臉照片目錄結(jié)構(gòu),謝謝大家土童。
完整代碼附上:
import cv2
import os
import numpy as np
from PIL import Image
face_detector = cv2.CascadeClassifier('D:/OPENCV/sources/data/haarcascades/haarcascade_frontalface_default.xml')
face_sampes = []
ids = []
font = cv2.FONT_HERSHEY_DUPLEX
face_names = []
person_list = os.listdir("faces/")
for i in range(len(person_list)):
? ? person_name = os.listdir("faces/" + "person_" + str(i + 1))
? ? img_path = "faces/" + "person_" + str(i + 1) + "/" + person_name[0]
? ? face_names.append(person_name[0][:person_name[0].index(".")])
? ? # opencv人臉檢測(cè)
? ? PIL_img = Image.open(img_path).convert('L')
? ? img_numpy = np.array(PIL_img, 'uint8')
? ? faces = face_detector.detectMultiScale(img_numpy)
? ? for x,y,w,h in faces:
? ? ? ? face_sampes.append(img_numpy[y:y+h, x:x+w])
? ? ? ? ids.append(i + 1)
opencv_recognizer = cv2.face.LBPHFaceRecognizer_create()
opencv_recognizer.train(face_sampes, np.array(ids))
opencv_recognizer.write('train/train.yml')
camera = cv2.VideoCapture(0)
while True:
? ? success, img = camera.read()
? ? opencv_recognizer.read('train/train.yml')
? ? gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
? ? new_faces = face_detector.detectMultiScale(gray)
? ? for x, y, w, h in new_faces:
? ? ? ? cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
? ? ? ? id, confidence = opencv_recognizer.predict(gray[y:y + h, x:x + w])
? ? ? ? cv2.putText(img, face_names[id - 1] + str(int(confidence)), (x + 6, y + h - 6), font, 1.0, (255, 255, 255), 1)
? ? cv2.imshow('camera', img)
? ? cv2.waitKey(0)
? ? cv2.destroyAllWindows()