第五章
人脸检测和识别
Haar级联
- Haar级联具有
尺度不变性
(不同尺度的两幅图像也有相似特征) - OpenCV的Haar级联不具有
旋转不变形
- 类Harr特征是一种用于实现实时人脸跟踪的特征,每个类Haar特征都描述了相邻图像区域的对比模式
- 图像的特征集合称为
级联
获取Harr级联数据
- OpenCV源代码的副本中文件夹:
data/haarcascades
包含了OpenCV所有人脸检测的XML文件,可检测图像、视频、摄像头所得图像的人脸(需要正面,直立的人脸图像)
使用OpenCV人脸检测
对图片进行人脸检测
import cv2
filename = './5_1.jpg'
def detect(filename):
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
img = cv2.imread(filename)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 每次迭代时,人脸的压缩率;每个人脸矩形保留邻近数目的最小值
faces = face_cascade.detectMultiScale( gray , 1.3 , 5 )
for ( x, y , w , h ) in faces :
img = cv2.rectangle( img , (x,y) , (x+w,y+h) , (255,0,0) , 2 )
cv2.namedWindow('Detected!')
cv2.imshow('Detected!',img)
cv2.waitKey(0)
detect(filename)
视频中的人脸检测
import cv2
def detect():
# 加载Haar级联文件
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('./cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0) # 初始化摄像头
# 与静态图像的人脸检测类似,视频中对每一帧进行静态图像的人脸检测
while True:
ret , frame = camera.read()
gray = cv2.cvtColor(frame , cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale( gray , 1.3 , 5 ) # 在灰度色彩空间检测
for ( x , y , w , h ) in faces:
cv2.rectangle( frame , (x,y) , (x+w,y+h) , (255,0,0) , 2 ) # 在源图像中画框
img = frame[y:y+h , x:x+w]
roi_gray = gray[y:y+h , x:x+w]
# 人脸检测时,后两个参数默认即可,但眼睛是一个比较小的人脸特征,且鼻子等的随机阴影都会产生假阳性
#通过限制对人眼搜索的最小尺寸40*40像素,可去除所有假阳性
eyes = eye_cascade.detectMultiScale( roi_gray , 1.03 , 5 , 0 , (40,40) )
for ( ex , ey , ew , eh ) in eyes:
cv2.rectangle( img , (ex,ey) , (ex+ew , ey+eh) , (0,255,0) , 2 ) # 人眼区域画框
cv2.imshow("camera",frame)
if cv2.waitKey( 5 ) & 0xff == ord("q"): # 等待键盘事件(每5ms),q退出
break
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
detect()
[注]:灰度图像中进行人脸检测,源图像中画框(涉及两张图片)
人脸识别
- OpenCV的三种人脸识别方法:
Eigenfaces
,Fisherfaces
,Local Binary Pattern Histogram(LBPH)
LBPH
是唯一允许模型样本人脸和检测到的人脸在形状,大小可以不同的人脸识别算法
生成人脸识别数据
- 打开摄像头获取人脸并存储为.pgm格式
import cv2
def generate():
face_cascade = cv2.CascadeClassifier('./cascades/haarcascade_frontalface_default.xml')
#eye_cascade = cv2.CascadeClassifier('/cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0)
count = 0
while True:
ret , frame = camera.read()
gray = cv2.cvtColor(frame , cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale( gray , 1.3 , 5 )
for x , y , w , h in faces:
img = cv2.rectangle(frame , ( x , y ) , ( x + w , y + h ) , (255,0,0) , 2 )
f = cv2.resize( gray[y:y+h,x:x+w] , (200,200) )
cv2.imwrite('./data/at/jm/%s.pgm' % str(count) , f )
count += 1
cv2.imshow("camera" , frame)
if cv2.waitKey( 1000 // 12 ) & 0xFF == ord("q") :
break
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
generate()
生成.csv文件
- 基于逗号分隔值的(.CSV)文件,根据ID记录样本图像路径(最后的数字表示ID)
def generate_csv(id=0): #在csv文件中加入用户id条目
count = 0
fout = open('a.csv', 'w', encoding='utf-8')
for i in range(21):
fout.write('jm/%s.pgm;'%str(i))
fout.write('%s'%str(id))
fout.write('\n')
if __name__ == "__main__":
generate_csv()
加载数据识别人脸
- 基于Eigenfaces的人脸识别
- 书中的实现未用到.csv,所有就自己改动了一下,但是写的比较僵硬。
- 先给出根目录,然后加上
.csv
文件中的每个.pgm
图像的路径,得到完整路径并读取图片加入图像数组
中,截取.csv的每个条目分号后位数(ID),加入标签数组中。
import cv2
import os
import sys
import numpy as np
import csv
def parse_csv(): # 逐行解析csv文件
csv_file = open("./a.csv")
csv_lines = csv.reader(csv_file)
path = []
tot = 0
for line in csv_lines:
path.append(line)
tot += 1
return path
def read_images(root):
path = parse_csv()
X , y = [] , [] # x: 图像数组 y: 标签数组
i = 0
tot = len(path)
while i < tot :
pic_path = root + path[i][0][0:-2] #获取用户图片集完整路径
#print(pic_path)
try:
im = cv2.imread(pic_path, cv2.IMREAD_GRAYSCALE)
if im is not None:
im = cv2.resize(im, (200, 200))
else:
continue
X.append(np.asarray(im, dtype=np.uint8))
id = path[i][0].split(';')[1:]
# print(id)
y.append(id) # ID
except IOError as e:
print("I/O error({0}):{1}".format(e.errno, e.strerror))
except:
print("Unexpected error:", sys.exc_info()[0])
raise
i += 1
return [X,y]
def face_rec():
filepath = 'F:/pyCharm/cv/chapter5/data/at/'
names = ['Dave','Jane','Jack']
[X,y] = read_images(filepath)
y = np.asarray( y , dtype=np.int32 )
model = cv2.face.EigenFaceRecognizer_create() # 基于Eigenfaces的人脸识别
# model = cv2.face.LBPHFaceRecognizer_create() # 基于LBPH的人脸识别
model.train( np.asarray(X) , np.asarray(y) ) # train()中传入图像数组,标签数组(ID)
face_cascade = cv2.CascadeClassifier('F:\pyCharm\cv\chapter5\cascades\haarcascade_frontalface_default.xml')
camera = cv2.VideoCapture(0)
while True:
read , img = camera.read()
faces = face_cascade.detectMultiScale( img , 1.3 , 5 )
for ( x , y , w , h ) in faces:
img = cv2.rectangle( img , (x,y) , (x+w,y+h) , (255,0,0) , 2 )
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
roi = gray[x:x+w,y:y+h]
try:
roi = cv2.resize(roi,(200,200) , interpolation=cv2.INTER_LINEAR)
params = model.predict(roi) params = model.predict(roi) # 返回含有两个元素的数组:所识别个体的标签,置信度评分
print("Label: %s , Confidence: %.2f" % (params[0],params[1]))
#打印匹配的名字
cv2.putText(img , names[params[0]] , (x,y-20) , cv2.FONT_HERSHEY_SIMPLEX , 1 , 255 , 2 )
except:
continue
cv2.imshow("camera",img)
if cv2.waitKey( 1000 // 12 ) & 0xff == ord("q"):
break
camera.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
face_rec()