提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
其实不一定使用ssd,fasterRcnn, yolov 都可以~
所以假设我们已经实现了这个监测模型。那么我们直接进入识别环境。
OpenCV提供了三种人脸识别的方法,分别是LBPH方法、EigenFishfaces方法、Fisherfaces方法。
EigenFaces就是对原始数据使用PCA方法进行降维,获取其中的主成分信息,从而实现人脸识别的方法。opencv已经帮我们打包好了。
具体使用步骤:
1.cv2.face.EigenFaceRecognizer_create()生成EigenFaces特征脸识别器实例模型
2.应用函数cv2.face_FaceRecognizer.train()完成训练
3.cv2.face_FaceRecognizer.predict()完成人脸识别。
在使用EigenFaces模块完成人脸识别时,其流程如图1所示。
LBPH(Local Binary PatternsHistograms)局部二进制编码直方图,建立在LBPH基础之上的人脸识别法基本思想如下:首先以每个像素为中心,判断与周围像素灰度值大小关系,对其进行二进制编码,从而获得整幅图像的LBP编码图像;再将LBP图像分为个区域,获取每个区域的LBP编码直方图,继而得到整幅图像的LBP编码直方图,通过比较不同人脸图像LBP编码直方图达到人脸识别的目的,其优点是不会受到光照、缩放、旋转和平移的影响。
由于这种方法的灵活性, LBPH是唯一允许模型样本人脸和检测到的人脸在形状、 大小上可以不同的人脸识别算法。
人脸录入
import cv2
cap = cv2.VideoCapture(0)
face_detector = cv2.CascadeClassifier('D:/opencv\sources/data/haarcascades/haarcascade_frontalface_default.xml')
face_id = input('User data input,Look at the camera and wait ...')
count = 0
while cap.isOpened():
ret, frame = cap.read()
if ret is True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
else:
break
faces = face_detector.detectMultiScale(gray, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + w), (255, 0, 0))
count += 1
cv2.imwrite("D:/opencv_test/" + str(face_id) + '.' + str(count) + '.jpg', gray[y:y + h, x:x + w])
cv2.imshow('image', frame)
k = cv2.waitKey(1)
if k == 27:
break
elif count >= 200:
break
cap.release()
cv2.destroyAllWindows()
代码解析:
cap = cv2.VideoCapture(0):调用摄像头,参数0表示默认为笔记本的内置第一个摄像头
cap.isOpened():判断视频对象是否成功读取,成功读取视频对象返回True,这里作为循环一直执行的条件。
ret,frame = cap.read():按帧读取视频,返回值ret是布尔型,正确读取则返回True,读取失败或读取视频结尾则会返回False;frame为每一帧的图像。
faces = face_detector.detectMultiScale(gray, 1.3, 5):#第一个参数是灰度图像,第二个参数是尺度变换,就是向上或者向下每次是原来的多少倍,这里是1.02倍,第三个参数是人脸检测次数,设置越高,误检率越低,但是对于迷糊图片,我们设置越高,越不易检测出来,要适当降低
key = cv2.waitKey(1):等待键盘输入,参数1表示延时1ms切换到下一帧,参数为0表示显示当前帧,相当于暂停,让其等于27,27在电脑上表示Esc退出。
这里根据count的数值,录入200张结束,实际也可以录入更多,但也不是更多更好。
这里的保存的图片都固定放到了一个人脸图像集里面,里面的图片名为user.count.jpg
运行代码会在User data input,Look at the camera and wait …停下,这里是要输入,因为后期是需要用names数组来显示名字,所以这里的user名为0,1,2的下标,输入为0,1,2……
import os
import cv2
import numpy as np
from PIL import Image
path = 'D:/opencv_test/'
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier('D:/opencv\sources/data/haarcascades/haarcascade_frontalface_default.xml')
def get_images_and_labels(path):
image_paths = [os.path.join(path, f) for f in os.listdir(path)]
face_samples = []
ids = []
for image_path in image_paths:
img = Image.open(image_path).convert('L')
img_np = np.array(img, 'uint8')
if os.path.split(image_path)[-1].split(".")[-1] != 'jpg':
continue
id = int(os.path.split(image_path)[-1].split(".")[0])
faces = detector.detectMultiScale(img_np)
for (x, y, w, h) in faces:
face_samples.append(img_np[y:y + h, x:x + w])
ids.append(id)
return face_samples, ids
faces, ids = get_images_and_labels(path)
recognizer.train(faces, np.array(ids))
recognizer.save('trainer/trainer.yml')
代码解析:
recognizer = cv2.face.LBPHFaceRecognizer_create():生成LBPH识别器实例模型
cv2.face_FaceRecognizer.train():对每个参考图像计算LBPH,得到一个向量,每个人脸都是整个向量集中的一个点
detector = cv2.CascadeClassifier(‘sources/data/haarcascades/haarcascade_frontalface_default.xml’):调用Opencv自带训练好的人脸检测器(默认)
OpenCV自带的人脸检测器在sources/data/目录下,根据每个人OpenCV安装的目录不同,这里也都是用的绝对地址
这里获取的id是user而不是count,这也就是我改善了那位博客主的代码问题,将对应路径下的所有人脸图片按对应的user名进行训练,保存训练好的数据集。
人脸识别流程:
step1:调用摄像头,获取视频流的图像帧,框出人脸,用训练好的人脸图像集去和视频中的人脸进行匹配,使用预测函数predict()获取置信评分。
step2:LBPH识别置信评分80以上就算是不合格,所以判断预测出来的置信评分,如果视频流中的人脸没有在训练集中,那么就表示成unknow。
step3:框出的视频流图像帧,把人脸框出来,显示置信评分和预测出来的人脸的标签,用标签去指定输出是图像集中的哪个人。
step4:释放摄像头资源并关闭窗口。
人脸识别完整代码
import cv2
recognizer = cv2.face.LBPHFaceRecognizer_create()
recognizer.read('trainer/trainer.yml')
face_cascade = cv2.CascadeClassifier("D:/opencv\sources/data/haarcascades/haarcascade_frontalface_default.xml")
font = cv2.FONT_HERSHEY_SIMPLEX
idnum = 0
cam = cv2.VideoCapture(0)
cam.set(6, cv2.VideoWriter.fourcc('M', 'J', 'P', 'G'))
minW = 0.1 * cam.get(3)
minH = 0.1 * cam.get(4)
names = ['linluocheng','zhupengcheng']
while True:
ret, img = cam.read()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(
gray,
scaleFactor=1.2,
minNeighbors=5,
minSize=(int(minW), int(minH))
)
for (x, y, w, h) in faces:
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)
idnum, confidence = recognizer.predict(gray[y:y + h, x:x + w])
if confidence < 80:
idum = names[idnum]
confidence = "{0}%".format(round(100 - confidence))
else:
idum = "unknown"
confidence = "{0}%".format(round(100 - confidence))
cv2.putText(img, str(idum), (x + 5, y - 5), font, 1, (0, 0, 255), 1)
cv2.putText(img, str(confidence), (x + 5, y + h - 5), font, 1, (0, 0, 0), 1)
cv2.imshow('camera', img)
k = cv2.waitKey(10)
if k == 27:
break
cam.release()
cv2.destroyAllWindows()
代码解析:
recongnizer.predict():一个预测函数,获取图像的标签和图像和训练集的相似度,也称置信评分。
cv2.putText():参数(图片 添加的文字 位置 字体 字体大小 字体颜色 字体粗细),将文字显示到图像上,中文会显示乱码。
format 格式化函数:基本语法是通过{}和:来代替之前前的%,有点类似C语言的格式符
round() 方法返回浮点数x的四舍五入值
转成灰度图并在上面框住人脸,用人脸和训练好的去比较,当置信评分达到一定程度,即为匹配成功,显示人脸和置信评分。
这里还是有一处是那位博客主的错误,就是format函数和前面的“”之前是用.隔开,而不是逗号.