python+OpenCV笔记(三十一):人脸检测与识别(三)——人脸识别

目录

一、生成人脸识别数据

二、加载人脸识别的训练数据

三、基于特征脸进行人脸识别

四、基于 Fisherface 进行人脸识别

五、基于 LBPH 进行人脸识别

全部代码


为了进行人脸识别,我们需要待识别的人脸,人脸可以通过两种方式获取

  • 免费的人脸数据库
    Face Recognition Homepage - Databases
  • 自己提供图像

(下面,我们用自己提供的图像(摄像头)完成人脸数据的收集)

一、生成人脸识别数据

代码

# 可直接运行
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 算法接收以下可选参数(按顺序):

  1. radius:用于计算单元格直方图的领域之间的像素距离(默认为1)
  2. neighbors:用于计算单元格直方图的领域数(默认为8)
  3. grid_x:水平分割人脸的单元格数量(默认为8)
  4. grid_y:垂直分割人脸的单元格数量(默认为8)
  5. 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

你可能感兴趣的:(python+OpenCv,opencv,计算机视觉,python)