前一段时间一直忙着学校里各种各样的杂事,手头上有着导师返校之前发下来的一个项目。由于涉及人脸识别等问题,同时自己没有过这方面的基础,于是乎就开始了自己的人脸识别入门之旅。学习这方面的内容,离不开学习各种库,其中耳熟能详的就是OpenCV开源库了。手动敲下相关的代码,配合实际的效果可以快速地入门。下面就对前一段时间的学习内容进行一下记录与总结。
人脸识别基本过程
完整的人脸识别流程,一般有如下五个步骤:
- 图像采集:使用摄像机或摄像头采集含有人脸的图像或视频流;
- 人脸检测:检测图片中是否包含人脸;
- 预处理:对人脸图像进行灰度处理、噪声过滤等预处理;
- 特征点提取:提取人脸图片中包含的特征数据;
- 人脸识别:将新的人脸照片与人脸库进行算法匹配,输出识别结果。
OpenCV
OpenCV
是一个开源的跨平台计算机视觉库。跨平台是指,它可以运行在Linux
、Windows
、Android
和Mac OS
等操作系统上。它实现了图像处理和计算机视觉方面的很多通用算法,具有轻量高效的特点。OpenCV
提供了多种语言的编程接口,例如C
、C++
、Python
。
一、图片基本操作
1. 采集图片
原始的图片多数采用各种摄像头采集,再整理为图片数据集。
1 | # 1.如果使用`OpenCV`采集,可以通过`cv2.VideoCapture()`获取摄像头并捕捉画面中的图片。函数声明为: |
2. 读取图片
通常我们使用采集完成的图片。在OpenCV
中,使用cv2.imread()
从文件中加载一张图片。
1 | # 函数声明 |
第一个参数为图片路径,图片应该在当前的工作路径,或在指定的绝对路径下;
第二个参数指定图片被读取的方式:
cv2.IMREAD_COLOR
: 读入彩色图像,默认模式;cv2.IMREAD_GRAYSCALE
: 以灰度模式读入图像;cv2.IMREAD_UNCHANGED
: 加载图像包含alpha
通道。也可以,使用数字简约表示以上三种标记,分别为
1
,0
或者-1
。
示例:
1 | import cv2 |
3. 展示图片
读取图片之后,可以将图片展示到窗口。使用cv2.imshow()
在窗口展示图片。
1 | # 函数声明 |
- 第一个参数传入窗口的名字;
- 第二个参数传入需要展示的图片对象。
当窗口展示完之后,需要再调用cv2.destroyAllWindows()
销毁所有的窗口。
示例:
1 | import cv2 |
4. 保存图片
在完成图像的一系列操作之后,可以使用cv2.imwrite()
将图片保存到本地
1 | # 函数声明 |
- 第一个参数为图片路径,图片应该在当前的工作路径,或在指定的绝对路径下;
- 第二个参数为将要保存的图片对象。
示例:
1 | import cv2 |
二、色彩空间及其转换
OpenCV
中默认的色彩空间是BGR
。BGR
与RGB
的区别只是三个颜色信道的位置发生了变化,实际上原理相同。为什么是
BGR
而不是RGB
呢?原因在于当时主流的摄像头制造商和软件供应商都普遍使用这种BGR
格式,所以所以一开始时OpenCV
采用的就是BGR
,然后沿用至今。
1. HSV与HSL色彩空间
在科学研究一般不采用RGB
色彩空间,它将色调,亮度,饱和度三个量放在一起表示,很难分开,这样难以对其进行数字化的调整。所以为了更好的数字化处理颜色,提出了HSV
,HSL
两个色彩空间。
HSV
色彩空间中,H
是色调(hue)
,S
是饱和度(saturation)
,V
是明度(value)
。HSL
色彩空间中,H
是色调(hue)
,S
是饱和度(saturation)
,L
是亮度(lightness)
。
2. 灰度空间
在OpenCV
的灰度空间中,和一般的色彩空间相同,每一个颜色都有三个量,但是只有第一个亮度有值,所以表示为(亮度,0,0)
。其中,亮度是根据如下灰度公式计算而得:Gray = R*0.299 + G*0.587 + B*0.114
为什么人脸识别需要先对图片进行灰度处理?
识别人脸,最关键的因素是梯度,梯度代表着边缘,用灰度图计算梯度,可以简化矩阵, 提高运算速度。
而颜色信息,很容易受到光照等因素的影响,同类的物体颜色有很多变化,所以颜色本身难以提供关键信息。
3. 色彩空间转换
在OpenCV
中有超过150
种色彩空间转换的方法。但经常用到的是以下两种:
BGR
空间到Gray
空间的转换;BGR
空间到HSV
空间 的转换。
使用的函数为:cv2.cvtColor()
。
1 | # 函数声明 |
其中,转换类型,对于BGR
到Gray
的转换,使cv2.COLOR_BGR2GRAY
类型。同样的,对于BGR
到HSV
的转换,使用cv2.COLOR_BGR2HSV
类型。
示例:
1 | # 将图片的色彩空间由BGR转换为HSV |
三、基于Harr特征的人脸检测分类器
主要思想:
OpenCV
的人脸检测,使用Harr分类器
。该分类器采用的Viola-Jones人脸检测算法
。它是在2001
年由Viola
和Jones
提出的基于机器学习的人脸检测算法。算法首先需要大量的积极图片(包含人脸的图片)和消极图片(不包含人脸的图片)。然后从中提取类
Harr特征( Harr-like features)
,之所以称为Harr
分类器,是正是因为它使用了类Harr
特征。最后,训练出一个级联检测器,用其来检测人脸。
1. 类Harr特征
图像中的特征通常是指,图片的像素点经过一系列的运算之后得到的结果,这些结果可能是向量、矩阵和多维数据等等。类Harr
特征是一种反映图像的灰度变化的,像素分模块求差值的一种特征。
2. Harr特征类别
它分为三类:边缘特征、线性特征、中心特征和对角线特征。用黑色两种矩形框组成为特征模板。
边缘特征
线性特征
中心线特征和对角线特征
3. 特征值计算
特征模板的特征值计算的方式,是用黑色矩形像素总和的均值减去白色矩形像素总和的均值。
例如,对于4x4
的像素块。理想情况下,黑色和白色的像素块分布如下:
符合边缘特征的情况(a
)。但是通常情况,一张灰阶照片的黑白分布并非如此的明显,例如:
根据公式, 第一张图特征值为1
,第二张图特征值为0.75-0.18=0.56
。
一张图中,对于识别人脸,只有部分特征是有效的。例如,用下图中的特征模板可以看出,眉毛区域比额头要亮,鼻梁区域比眼镜区域要亮。嘴唇区域比牙齿区域要暗。这样的类 Harr 特征能很好的识别出人脸。
为简化特征值计算,可以使用积分图算法。得到类 Harr 特征后,使用AdaBoost
的方法选择出有效特征。最后再使用瀑布型级联检测器提高检测速度。其中,瀑布的每一层都是一个由Adaboost算法
训练得到的强分类器。Harr人脸检测一个简单的动画过程如下:
红色的搜索框不断移动,检测出是否包含人脸。一般来说,输入的图片会大于样本,为了检索出不同大小的目标,分类器可以按比例的改变自己的尺寸,对输入图片进行多次的扫描。
4. 训练Harr分类器
训练Harr
分类器的主要步骤如下:
- 搜集制作大量的“消极”图像;
- 搜集制作大量“积极”图像,确保这些图像中包含要检测的对象;
- 创建“积极”向量文件;
- 使用
OpenCV
训练Harr
分类器。
因为训练需要花费较多的资源和时间,所以学习时,先使用OpenCV
中已经训练好的Harr
分类器。
5. 使用Harr分类器检测人脸
OpenCV
中的人脸训练模型格式为XML
,一般在cv2
包中的/data/haarcascades
或者直接在/data
目录下 。在此我们使用Harrcascade_frontalface_default.xml
模型检测人脸。
1 | # 声明分类器 |
参数说明:
图片对象:待识别图片对象;
scaleFactor
:图像缩放比例;minNeighbors
:对特征检测点周边多少有效点同时检测,这样可避免因选取的特征检测点太小而导致遗漏;minSize
:特征检测点的最小尺寸,可选参数。
示例:
1 | import numpy as np |
其中,图片坐标系以左上角为原点,x,y
代表人脸区域左上角坐标,w
代表宽度,h
代表高度。如下图所示:
四、绘制人脸与人眼区域
1. OpenCV绘制矩形
在OpenCV
中,可以使用cv2.rectangle()
在图片中绘制矩形区域。
1 | # 函数声明 |
2. 使用OpenCV绘制图片中人脸区域
使用OpenCV
分类器检测人脸之后,一张图片中可能包含多个人脸,所以我们对每一个识别到的人脸都绘制对应的矩形框。
1 | import cv2 |
3. 使用OpenCV绘制人脸区域中眼睛区域
进一步,==在识别人脸的基础上==,使用官方提供的haarcascade_eye.xml
人眼检测模型,识别出人眼并绘制到图片上。如果单独使用OpenCV
人眼检测模型,来识别出整个图片中的人眼区域,效果不是很好。
1 | import cv2 |