目录
一、生成人脸识别数据
二、加载人脸识别的训练数据
三、基于特征脸进行人脸识别
四、基于 Fisherface 进行人脸识别
五、基于 LBPH 进行人脸识别
全部代码
为了进行人脸识别,我们需要待识别的人脸,人脸可以通过两种方式获取
(下面,我们用自己提供的图像(摄像头)完成人脸数据的收集)
一、生成人脸识别数据
代码
# 可直接运行
import cv2
import os
# 创建一个特定的文件夹,用于存放人脸数据
output_folder = '../data/at/ReadyGo'
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 初始化两个CascadeClassifier对象,分别用于人脸和眼睛
face_cascade = cv2.CascadeClassifier(
'C:/MyOpenCV/cascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(
'C:/MyOpenCV/cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0)
count = 0
while (cv2.waitKey(1) == -1):
success, frame = camera.read()
if success:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(
gray, 1.3, 5, minSize=(120, 120))
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 将人脸区域调整为200*200像素
face_img = cv2.resize(gray[y:y + h, x:x + w], (200, 200))
face_filename = '%s/%d.pgm' % (output_folder, count)
cv2.imwrite(face_filename, face_img)
count += 1
cv2.imshow('Capturing Faces...', frame)
camera.release()
cv2.destroyAllWindows()
代码解析
- 创建文件夹,用于存放人脸数据
- 初始化CascadeClassifier对象
- 打开摄像头,读取一帧(循环):
- 转换为灰度图片
- 进行人脸检测
- 将人脸区域调整为200*200像素并保存为pgm格式图片
- 读取下一帧
- 关闭摄像头
- 想要训练其他人的脸部数据,更改文件夹名称(人名或人名首字母),再次重复上述步骤即可。
二、加载人脸识别的训练数据
? ? ? ? 上面,我们生成了训练数据,并将他们保存在根据人名或者人名首字母进行组织的文件夹中。
? ? ? ? 下面,我们编写一个脚本加载这些图像,并以一种 OpenCV 的人脸识别器能够理解的方式对它们进行标签。
代码
import os
import cv2
import numpy
def read_images(path, image_size):
names = []
training_images, training_labels = [], []
label = 0
for dirname, subdirnames, filenames in os.walk(path):
for subdirname in subdirnames:
names.append(subdirname)
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
img = cv2.imread(os.path.join(subject_path, filename),
cv2.IMREAD_GRAYSCALE)
if img is None:
# The file cannot be loaded as an image.
# Skip it.
continue
img = cv2.resize(img, image_size)
training_images.append(img)
training_labels.append(label)
label += 1
training_images = numpy.asarray(training_images, numpy.uint8)
training_labels = numpy.asarray(training_labels, numpy.int32)
return names, training_images, training_labels
通过如下代码调用 read_images 函数:
path_to_training_images = '../data/at'
training_image_size = (200, 200)
names, training_images, training_labels = read_images(
path_to_training_images, training_image_size)
代码分析
- read_images 函数:
- 创建人名或人名首字母列表 names(基于子文件夹名称)
- 创建用于存放的图像列表training_imags ,和与加载的图像相关联的数字ID列表 training_labels。
(第一个列表用于存放调整后的图像) (第二个列表用于存放某个子文件夹内的数字ID,主要用于标识当前的图片在哪个子文件夹内,相同的子文件夹内的所有图片的标签(数字ID)都是一样的,例如,0可以是子文件夹ReadyGo加载的所有图像的标签,1是下一个子文件夹内的所有图像的标签) - (循环)遍历 子文件夹名:
- 将第1(2......n)个子文件夹名存入names列表中
- (循环)遍历当前子文件夹内的文件名:
- 以灰度图读取第1(2......n)张图片
- 将图片调整为指定大小
- training_images 列表存入修改后的图片
- training_labels 列表存入对应于子文件夹的标签值
- 标签值+1(即上一个子文件夹内的所有图片已处理完毕)
- 返回:names列表,training_images列表,training_labels列表
到目前为止,我们已经有了有用格式的训练数据(但还没有训练),而且还没有创建人脸识别器。
下面的脚本,与此脚本为同一个脚本,运行时需同时运行。
三、基于特征脸进行人脸识别
? ? ? ? 上面,我们已经有了有用格式的训练图像(数组)和标签(数组)。
? ? ? ? 下面,用两行代码创建和训练一个人脸识别器。
代码
model = cv2.face.EigenFaceRecognizer_create() # 使用默认参数
model.train(training_images, training_labels)
我们可以选择地将两个参数传递给cv2.EigenFaceRecognizer_create():
- num_components:这是PCA需要保留的主成分数量
- threshold:这是一个浮点值,指定置信度阈值。丢弃置信度低于阈值的人脸(默认不丢弃任何人脸)。
下面,我们将进行人脸识别器的初始化:
face_cascade = cv2.CascadeClassifier(
'C:/MyOpenCV/cascades/haarcascade_frontalface_default.xml')
然后初始化摄像头回传信号,遍历帧,对每一帧进行人脸识别和检测
camera = cv2.VideoCapture(0)
while (cv2.waitKey(1) == -1):
success, frame = camera.read()
if success:
faces = face_cascade.detectMultiScale(frame, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
roi_gray = gray[x:x + w, y:y + h]
if roi_gray.size == 0:
continue
roi_gray = cv2.resize(roi_gray, training_image_size)
label, confidence = model.predict(roi_gray)
text = '%s, confidence = %.2f' % (names[label], confidence)
cv2.putText(frame, text, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('Face Recognition', frame)
camera.release()
cv2.destroyAllWindows()
代码分析
- 读取一帧(循环):
- 检测人脸
- 绘制矩形
- 转换为灰度图
- 修改人脸区域大小尺寸
- 将人脸区域传递给人脸识别器的 predict 函数
(返回标签 和 置信度) - 根据标签查找人名
- 显示带注释的图像
拓展:
????????置信度典型的取值范围取决于算法,特征脸和Fisherfish产生的值的范围大致在0~20000,低于4000的所有数值都表示是一个相当有信心的识别结果。对于LBPH,好的识别结果参考值低于50,所有超过80的值都被认为是糟糕的置信度。
下面,我们用其他算法替换特征脸
四、基于 Fisherface 进行人脸识别
cv2.face.FisherFaceRecognizer_create() 和?cv2.face.EigenFaceRecognizer_create()接收相同的两个可选参数:主成分数量和置信度阈值
只需替换一行代码(使用默认参数):
model = cv2.face.FisherFaceRecognizer_create()
五、基于 LBPH 进行人脸识别
LBPH 算法接收以下可选参数(按顺序):
- radius:用于计算单元格直方图的领域之间的像素距离(默认为1)
- neighbors:用于计算单元格直方图的领域数(默认为8)
- grid_x:水平分割人脸的单元格数量(默认为8)
- grid_y:垂直分割人脸的单元格数量(默认为8)
- threshold:置信度阈值(默认最高,即不丢弃任何人脸)
替换一行代码(使用默认参数):
model = cv2.face.LBPHFaceRecognizer_create()
注意:
? ? ? ??使用LBPH不需要调整(resize)图像的大小
全部代码
1.采集人脸数据(.py)
import cv2
import os
# 创建一个特定的文件夹,用于存放人脸数据
output_folder = '../data/at/ReadyGo'
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 初始化两个CascadeClassifier对象,分别用于人脸和眼睛
face_cascade = cv2.CascadeClassifier(
'C:/MyOpenCV/cascades/haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier(
'C:/MyOpenCV/cascades/haarcascade_eye.xml')
camera = cv2.VideoCapture(0)
count = 0
while (cv2.waitKey(1) == -1):
success, frame = camera.read()
if success:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(
gray, 1.3, 5, minSize=(120, 120))
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
# 将人脸区域调整为200*200像素
face_img = cv2.resize(gray[y:y + h, x:x + w], (200, 200))
face_filename = '%s/%d.pgm' % (output_folder, count)
cv2.imwrite(face_filename, face_img)
count += 1
cv2.imshow('Capturing Faces...', frame)
camera.release()
cv2.destroyAllWindows()
2.识别人脸(.py)
import os
import cv2
import numpy
def read_images(path, image_size):
names = []
training_images, training_labels = [], []
label = 0
for dirname, subdirnames, filenames in os.walk(path):
for subdirname in subdirnames:
names.append(subdirname)
subject_path = os.path.join(dirname, subdirname)
for filename in os.listdir(subject_path):
img = cv2.imread(os.path.join(subject_path, filename),
cv2.IMREAD_GRAYSCALE)
if img is None:
# The file cannot be loaded as an image.
# Skip it.
continue
img = cv2.resize(img, image_size)
training_images.append(img)
training_labels.append(label)
label += 1
training_images = numpy.asarray(training_images, numpy.uint8)
training_labels = numpy.asarray(training_labels, numpy.int32)
return names, training_images, training_labels
path_to_training_images = '../data/at'
training_image_size = (200, 200)
names, training_images, training_labels = read_images(
path_to_training_images, training_image_size)
model = cv2.face.LBPHFaceRecognizer_create()
model.train(training_images, training_labels)
face_cascade = cv2.CascadeClassifier(
'C:/MyOpenCV/cascades/haarcascade_frontalface_default.xml')
camera = cv2.VideoCapture(0)
while (cv2.waitKey(1) == -1):
success, frame = camera.read()
if success:
faces = face_cascade.detectMultiScale(frame, 1.3, 5)
for (x, y, w, h) in faces:
cv2.rectangle(frame, (x, y), (x + w, y + h), (255, 0, 0), 2)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
roi_gray = gray[x:x + w, y:y + h]
if roi_gray.size == 0:
continue
# roi_gray = cv2.resize(roi_gray, training_image_size)
label, confidence = model.predict(roi_gray)
text = '%s, confidence = %.2f' % (names[label], confidence)
cv2.putText(frame, text, (x, y - 20), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 2)
cv2.imshow('Face Recognition', frame)
camera.release()
cv2.destroyAllWindows()
【参考】:OpenCV 4计算机视觉 Python语言实现(原书第三版) 作者:Joseph Howse
|