使用 OpenCV 实现人脸识别

1,818 阅读6分钟

「这是我参与2022首次更文挑战的第27天,活动详情查看:2022首次更文挑战」。

OpenCV

介绍

OpenCV 是一个跨平台计算机视觉库, 可以运行在 Linux、Windows、Android 和 Mac OS 操作系统上。它轻量级而且高效——由一系列 C 函数和少量 C++ 类构成,同时提供了 Python、Ruby、MATLAB 等语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。

安装

在我们编码的过程中,会使用到OpenCV 的两个模块,我们直接使用 pip 安装:

pip install opencv-python

另外一个:

pip install opencv-contrib-python

安装完成后,我们就可以开始学习 OpenCV 的使用了。

使用 OpenCV 处理视频图像

处理图像

读取并显示图像

读取图像和显示图像是图像的最基本操作,在 OpenCV 中实现起来也非常简单,代码如下:

import cv2

# 读取图片
im = cv2.imread('test.png')
# 显示图片,第一个参数为窗口名称
cv2.imshow('img', im)
# 等待键盘输入
cv2.waitKey(0)
# 销毁所有窗口
cv2.destroyAllWindows()

在我们导入模块的时候,是导入 cv2,我们读取图像使用到 imread 函数,显示图像使用到 imshow 函数。因为 imshow 函数只会显示一瞬间,所以我们在后面添加一句 waitkey(),该函数传入毫秒值,当传入0时表示无限等待键盘输入。因为 OpenCV 是使用 C/C++ 实现的,所以我们需要销毁窗口(类似于 free)。

灰度转换

我们可以简单理解为将彩色图像转换为黑白图像,在人脸识别时,我们通常使用灰度转换后的图像进行识别。

import cv2

# 读取图像
im = cv2.imread('test.png')
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 保存图像
cv2.imwrite('im.png', grey)
# 销毁所有窗口
cv2.destroyAllWindows()

灰度转换我们使用到 cv2.cvtColor 函数,第一个参数为 ndarray 对象(图像),第二个是一个 cv2 中的常数。我们从常数名称可以看出,对于 OpenCV 来说,图片一般都是 BGR 而不是 RGB 的。

我们灰度转换后,使用 imwrite 函数保存图像。

绘制图形

然后我们来看看如何用 OpenCV 绘制图形:

import cv2
# 读取图像
im = cv2.imread('test.jpg')
# 绘制图形
cv2.rectangle(im, (10, 10), (50, 50), (0, 255, 0), 3)
cv2.circle(im, (100, 100), 50, (0, 0, 255), 2)
# 显示图像
cv2.imshow('im', im)
cv2.waitKey(0)
cv2.destroyAllWindows()

上面代码我们绘制了一个矩形和一个圆形。我们看一下两个方法:

"""
im:ndarray对象
p1:左上角的坐标
p2:右下角的坐标
color:颜色,格式为BGR
thickness:轮廓宽
"""
rectangle(im, p1, p2, color, thickness)
"""
im:ndarray对象
center:圆心坐标
radius:半径
color:颜色BGR格式
thickness:轮廓宽
"""
circle(im, center, radius, color, thickness)

这里只是说了些会用到的参数。代码的效果如下:

在这里插入图片描述

后续在我们人脸检测的过程中,我们可以绘制图形,将人脸框起来。

检测人脸

获取特称数据

我们实现人脸检测需要先下载 OpenCV 的特征数据,我们去 OpenCV 的官网下载相应的文件。进入我们可以看到如下界面:

在这里插入图片描述

下载后,我们双击运行就可以了。我们进入 opencv\sources\data\haarcascades 目录,会发现里面有许多特征文件。我们通常使用 haarcascade_frontalface_default.xml 作为特征数据。我是直接将特征文件复制到项目根目录下,你们可以选择和我一样,或者直接使用绝对路径。

检测人脸

检测人脸的步骤如下:

  1. 读取图像
  2. 灰度转换
  3. 获取人脸检测器
  4. 检测人脸
  5. 遍历人脸

我们将上面的步骤写成代码:

import cv2
# 读取图像
im = cv2.imread('face.jpg')
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
# 获取人脸检测器
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 检测人脸
faces = face_detector.detectMultiScale(grey)
# 遍历检测到的人脸
for x, y, w, h in faces:
    # 在人脸区域绘制矩形
    cv2.rectangle(im, (x, y), (x+w, y+h), (0, 255, 0), 2)
    # 显示图像
    cv2.imshow('im', im)
    cv2.waitKey(0)
cv2.destroyAllWindows()

我们使用 cv2.CascadeClassifier 方法,加载特征数据。然后我们使用 detectMultiScale 方法检测人脸,该函数返回人脸数据。face.jpg 和绘制矩形后的图形如下:

在这里插入图片描述

在试验过程中,发现通常情况下都可以检测出,但是失误的情况也比较多。

训练数据

训练数据主要是需要获得两个数据,一个是人脸标签,另一个是人脸数据。为了方便获取人脸标签,我们先准备好一些图片:

在这里插入图片描述

这里有 40 张图片,其中前 20 张是胡歌,后二十张是小罗伯特唐尼。后续我们可以用这些图片作为训练素材。我们识别这些人脸,获取其人脸数据,然后直接将文件名作为标签,这样我们就知道标签大于 20 的就是小罗伯特唐尼,而标签小于 20 的就是胡歌。

训练数据步骤大致如下:

  1. 获取人脸数据和标签数据
  2. 获取训练器
  3. 训练数据
  4. 保存训练数据

代码如下:

import cv2
import os
import numpy

# 人脸的根目录
root = './face/'

def getFacesAndLables():

    # 用于存储人脸数据
    faces = []
    # 用于存储标签数据
    labels = []

    # 获取人脸检测器
    face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')

    # 获取图片路径
    files = os.listdir(root)

    for file in files:
        # 读取图像
        im = cv2.imread(root + file)
        # 灰度转换
        grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
        # 检测人脸
        face = face_detector.detectMultiScale(grey)
        for x, y, w, h in face:
            # 设置标签
            labels.append(int(file.split('.')[0]))

            # 设置人脸数据
            faces.append(grey[y:y+h, x:x+w])

    return faces, labels

# 获取人脸数据和标签
faces, labels = getFacesAndLables()

# 获取训练对象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 训练数据
recognizer.train(faces, numpy.array(labels))
# 保存训练数据
recognizer.write('./trainer.yml')

这里主要的代码还是获取人脸数据和人脸标签。获取训练对象我们通过 cv2.face.LBPHFaceRecognizer_create() 函数,该函数在 opencv-contrib-python 模块中。训练数据调用 train 函数,然后我们使用 write 保存训练数据。接下来我们就可以进行人脸识别了。

人脸识别

在训练好数据后我们就可以开始识别人脸了,识别人脸的步骤大致如下:

  1. 读取训练数据
  2. 读取图像
  3. 检测人脸
  4. 匹配数据

我们用代码实现:

import cv2

# 获取训练对象
recognizer = cv2.face.LBPHFaceRecognizer_create()
# 加载训练数据
recognizer.read('trainer.yml')

# 读取图像
im = cv2.imread('Tony.jpg')
# 灰度转换
grey = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)

# 获取人脸检测对象
face_detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
# 检测人脸
face = face_detector.detectMultiScale(grey)

for x, y, w, h in face:
    # 匹配人脸
    label, confidence = recognizer.predict(grey[y:y+h, x:x+w])

    # 通过label判断识别结果
    if confidence <= 60:
        if label < 20:
            print('胡歌')
        elif label > 20:
            print('小罗伯特唐尼')
    else:
        print('未匹配到人脸')

我们使用 read 方法加载训练数据,读取图像和检测人脸的操作我们已经说过了,然后我们使用 recognizer.predict 方法匹配人脸。该方法返回两个参数,一个是人脸标签,还有一个是可信度。confidence 的值越低,可信程度越高。然后我们通过获取的标签来判断,识别的人物是谁。

在这里插入图片描述

上面是我用来识别的图片,结果如下:

小罗伯特唐尼

这样我们就实现了人脸识别。因为训练数据比较少,所以识别的准确率也比较低,大家可以多使用一些图片进行进行训练,本文代码连接如下:

github.com/IronSpiderM…