这篇文章的话题依然是人脸识别,不过仅仅使用了opencv-python以及opencv-contrib-python这两个包,而且就我做的测试用例来看识别的正确率比face_recognition还要更高,话不多说,咱们这就开始。
人脸检测
要想做人脸识别,人脸检测必须是要做的,毕竟识别也得你检测到人脸之后才能辨别。那么如何检测到人脸呢?提取出图像的细节对产生稳定分类结果很重要,这些提取的结果被称为特征,专业的表述为:从图像数据中提取特征。虽然任意像素都可以能影响多个特征,但特征应该比像素少得多。两个图像的相似程度可以通过它们对应特征的欧氏距离来度量。 Haar 特征是一种用于实现实时人脸跟踪的征。每一个 Haar 特征都描述了相邻图像区域的对比模式。例如,边、顶点和细线都能生成具有判别性的特征。获取 Haar 特征的方法有很多种,这里我用的是安装opencv以后opencv安装目录里的部分xml文件获取的,如果你不想安装opencv的话,也可以到文末直接下载我打包好的文件。如果你已经安装了opencv,找到你的安装目录,一般如下图:
接着打开sources/data/haarcascades文件夹,你会看到下图:
我提供的资源就是上图所示的所有xml文件,不用再在电脑上安装opencv了。默认的人脸检测器是haarcascade_frontalface_default.xml。当然这个是可以更改的,使用的方法如下:
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人脸检测
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是训练数据用到的两个参数,face_sampes是人脸特征矩阵,ids是每个人脸对应的id。
训练数据
这部分比较简单,如果有异常应该是未安装opencv-contrib-python导致的,直接上代码了。
opencv_recognizer = cv2.face.LBPHFaceRecognizer_create()
opencv_recognizer.train(face_sampes, np.array(ids))
opencv_recognizer.write('train/train.yml')
执行完代码之后会在当前目录生成train.yml文件,人脸识别的时候会用到。
人脸识别
相信大家都已经看到了我在训练数据时使用的代码,其中opencv_recognizer是比较重要的,当然其实是cv2.face.LBPHFaceRecognizer_create()比较重要。这个人脸识别主要用的是LBPH算法**。它将检测到的人脸分为小单元,并将其与模型中的对应单元进行比较,对每个区域的匹配值产生一个直方图。由于这种方法的灵活性,LBPH是唯一允许模型样本人脸和检测到的人脸在形状、大小上可以不同的人脸识别算法。具体的用法见以下代码。
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)
识别的主体在predict方法中,它的返回值一个是id,一个是置信度。id是与人脸一一对应的,好的置信度要低于50,越小越好。高于80的置信度都是较差的。然后由于我可以根据id得到人的姓名,所以我可以直接把人名实时显示在摄像头视频中,如何做到的欢迎移步这里看我的人脸照片目录结构,谢谢大家。
完整代码附上:
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人脸检测
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()