【学习笔记】人脸识别系统(1) —— OpenCV人脸检测


OpenCV是一个开源的跨平台计算机视觉库

学习目标是:

  • 学会使用 OpenCV中一系列的图像操作(采集图片、读取图片、展示图片以及保存图片);
  • 理解色彩空间,并使用 OpenCV进行色彩空间转换;
  • 理解 Harr分类器原理,使用 OpenCV中的 Harr分类器进行人脸检测。

OpenCV是一个开源的跨平台计算机视觉库。跨平台是指,它可以运行在Linux、Windows、Android和Mac OS等操作系统上。它实现了图像处理和计算机视觉方面的很多通用算法,具有轻量高效的特点。OpenCV提供了多种语言的编程接口,例如C、C++、Python。


完整的人脸识别流程,一般有如下五个步骤:

  1. 图像采集:使用摄像机或摄像头采集含有人脸的图像或视频流;
  2. 人脸检测:检测图片中是否包含人脸;
  3. 预处理:对人脸图像进行灰度处理、噪声过滤等预处理;
  4. 特征点提取:提取人脸图片中包含的特征数据;
  5. 人脸识别:将新的人脸照片与人脸库进行算法匹配,输出识别结果。

图片基本操作

1.(摄像头)采集图片

原始的图片多数 采用各种摄像头采集 ,再整理为图片数据集。
如果使用OpenCV采集,可以通过cv2.VideoCapture()获取摄像头并捕捉画面中的图片。函数声明为:

cv2.VideoCapture(摄像头来源)
  • 其中,传入的参数,指定0时为默认计算机默认摄像头,指定1可以更换来源。

然后,获取捕获图像,函数为:

cap.read()
  • cap.read()返回一个布尔值(True/False)和一帧图像。

最后释放捕获对象,函数为:

cap.release()

示例如下:

# 引入OpenCV库
import cv2

# 调用摄像头进行拍照
cap = cv2.VideoCapture(0)

# 获取一帧图片
# 如果捕获成功,代码中ret值为真,img为捕获的图像。
ret, img = cap.read()

# 释放捕获对象
cap.release()

2.读取(已采集)图片

通常我们 使用采集完成的图片。在OpenCV中,使用cv2.imread()从文件中加载一张图片。
函数声明为:

cv2.imread(图片路径, 标记)
  • 第一个参数为图片路径,图片应该在当前的工作路径,或在指定的绝对路径下。

  • 第二个参数指定图片被读取的方式:
    cv2.IMREAD_COLOR : 读入彩色图像,默认模式;
    cv2.IMREAD_GRAYSCALE : 以灰度模式读入图像;
    cv2.IMREAD_UNCHANGED : 加载图像包含alpha通道。(alpha通道:控制透明度)

  • 也可以,使用数字简约表示以上三种标记,分别为 10-1

示例如下:

import cv2
# 加载一张位于当前目录下的`images/girl.jpg`的图片
image_path = "images/girl.jpg"
# 以灰度模式读取图片
img = cv2.imread(image_path,0)

3.展示图片

读取图片之后,可以将图片展示到窗口。使用cv2.imshow()在窗口展示图片。
函数声明为:

imshow(窗口名称, 图片对象)
  • 第一个参数传入窗口的名字;
  • 第二个参数传入需要展示的图片对象。

当窗口展示完之后,需要再调用cv2.destroyAllWindows()销毁所有的窗口。
示例如下:

import cv2

# 读取图片
image_path = "images/girl.jpg"
img = cv2.imread(image_path,1)

# 窗口展示图片
cv2.imshow('cute girl',img)
# 等待用户关闭图片窗口
cv2.waitKey(0)
# 销毁创建的所有窗口
cv2.destroyAllWindows()

运行上面的示例代码会呈现下面的效果:

4.保存图片

在完成图像的一系列操作之后,可以使用cv2.imwrite()将图片保存到本地。
函数声明为:

cv2.imwrite(图片路径, 图片对象)
  • 第一个参数为图片路径,图片应该在当前的工作路径,或在指定的绝对路径下;
  • 第二个参数为将要保存的图片对象。

示例如下:

import cv2

# 读取图片
image_path = "images/girl.jpg"
img = cv2.imread(image_path,1)

# 保存图片为girl-copy.png
cv2.imwrite('images/girl-copy.png',img)

色彩空间及其转换

你需要掌握:

  1. 什么是色彩空间;
  2. 如何转换色彩空间。

色彩空间

  • 色彩空间(Color space)是对色彩的组织方式,是座标系统和子空间的阐述,位于系统的每种颜色都有单个点表示。

  • 目前,色彩空间已经有上百种表示方式,被采用的大多数色彩空间都是面向硬件或面向应用的,大部分只是局部的改变或专用于某一领域。

  • 下面介绍一些常用的色彩空间。

RGB色彩空间

  • 我们知道,可以使用红色、绿色和蓝色这三种原色生成不同的颜色,这些颜色可以组成了一个色彩空间,称为RGB(Red Green Blue)色彩空间。

  • RGB是依据人眼识别的颜色定义出的空间,可表示大部分颜色。它是最通用的面向硬件的色彩空间。该色彩空间用于彩色监视器和一大类彩色视频摄像。

  • 在该色彩空间中,将蓝色的量定义为X座标轴、红色的量定义为Y座标轴、绿色的量定义为Z座标轴,就可以得到一个三维空间。所以每种颜色在这个三维空间中都有唯一的一个点与其对应。

完整的RGB色彩空间图如下:

OpenCV中默认的色彩空间是BGR。BGR与RGB的区别只是三个颜色信道的位置发生了变化,实际上原理相同。

为什么是BGR而不是RGB呢?原因在于当时主流的摄像头制造商和软件供应商都普遍使用这种BGR格式,所以所以一开始时OpenCV采用的就是BGR,然后沿用至今。

HSV与HSL色彩空间

在科学研究一般不采用RGB色彩空间,它将色调,亮度,饱和度三个量放在一起表示,很难分开,这样难以对其进行数字化的调整。所以为了更好的数字化处理颜色,提出了HSV,HSL两个色彩空间。

  • HSV色彩空间中,H是色调(hue),S是饱和度(saturation), V是明度(value)。

  • HSL色彩空间中,H是色调(hue),S是饱和度(saturation),L是亮度(lightness)。

灰度空间

在OpenCV的灰度空间中,和一般的色彩空间相同,每一个颜色都有三个量,但是只有第一个亮度有值,所以表示为(亮度,0,0)。
其中,亮度是根据如下灰度公式计算而得:

Gray = R*0.299 + G*0.587 + B*0.114

为什么人脸识别需要先对图片进行灰度处理?

  • 识别人脸,最关键的因素是梯度,梯度代表着边缘,用灰度图计算梯度,可以简化矩阵, 提高运算速度。

  • 而颜色信息,很容易受到光照等因素的影响,同类的物体颜色有很多变化,所以颜色本身难以提供关键信息。

色彩空间转换

在OpenCV中有超过150种色彩空间转换的方法。但是我们经常用到的是以下两种:

  1. BGR空间到Gray空间 的转换;
  2. BGR空间到HSV空间 的转换。

使用的函数声明为:

cv2.cvtColor(图片对象,转换类型)

转换类型,

  • 对于BGR到Gray的转换,使cv2.COLOR_BGR2GRAY类型。
  • 对于BGR到HSV的转换,使用cv2.COLOR_BGR2HSV类型。

示例如下:

# 将图片的色彩空间由BGR转换为HSV
# 执行后output_img的色彩空间变成了HSV
output_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

我们也可以通过以下代码获取到OpenCV提供的所有转换类型:

import cv2
flags = [i for in dir(cv2) if i startswith('COLOR_')]
print(flags)

基于Harr特征的人脸检测分类器

  • OpenCV的人脸检测,使用Harr分类器。
  • 该分类器采用的Viola-Jones人脸检测算法。它是在2001年由Viola和Jones提出的基于机器学习的人脸检测算法。
  • 算法首先需要大量的积极图片(包含人脸的图片)和消极图片(不包含人脸的图片)。然后从中提取类Harr特征( Harr-like features),之所以称为 Harr分类器,正是因为它使用了类Harr特征。
  • 最后,训练出一个级联检测器,用其来检测人脸。

类Harr特征

  • 图像中的特征 通常是指,图片的像素点经过一系列的运算之后得到的结果,这些结果可能是向量、矩阵和多维数据等等。
  • 类Harr特征 是一种反映图像的灰度变化的,像素分模块求差值的一种特征。

Harr特征类别

它分为三类:边缘特征、线性特征、中心特征和对角线特征。用黑色两种矩形框组成为特征模板。

  • 边缘特征:
  • 线性特征:
  • 中心特征和对角线特征:

特征值计算

例如,对于4x4的像素块。

理想情况下,黑色和白色的像素块分布如下:

符合边缘特征的情况(a)。

但是通常情况,一张灰阶照片的黑白分布并非如此的明显,例如:

根据公式,

第一张图特征值为1,第二张图特征值为0.75-0.18=0.56。

一张图中,对于识别人脸,只有部分特征是有效的。例如,用下图中的特征模板可以看出,眉毛区域比额头要亮,鼻梁区域比眼镜区域要亮。嘴唇区域比牙齿区域要暗。这样的类Harr特征能很好的识别出人脸。

为简化特征值计算,可以使用积分图算法。得到类Harr特征后,使用AdaBoost的方法选择出有效特征。最后再使用瀑布型级联检测器提高检测速度。其中,瀑布的每一层都是一个由Adaboost算法训练得到的强分类器。

Harr人脸检测一个简单的截图程如下:

红色的搜索框不断移动,检测出是否包含人脸。一般来说,输入的图片会大于样本,为了检索出不同大小的目标,分类器可以按比例的改变自己的尺寸,对输入图片进行多次的扫描。

训练Harr分类器

训练 Harr 分类器的主要步骤如下:

  • 搜集制作大量的“消极”图像
  • 搜集制作大量“积极”图像,确保这些图像中包含要检测的对象
  • 创建“积极”向量文件
  • 使用 OpenCV 训练 Harr 分类器

因为训练需要花费较多的资源和时间,所以我们学习时,先使用 OpenCV 中已经训练好的 Harr 分类器。

使用Harr分类器检测人脸

OpenCV 中的人脸训练模型格式为 XML,可以从 官网下载 。在此我们使用Harrcascade_frontalface_default.xml模型检测人脸。

声明分类器:

CascadeClassifier(模型文件路径)

调用分类函数:

detectMultiScale(图片对象,scaleFactor, minNeighbors, minSize)
  • 图片对象:待识别图片对象;
  • scaleFactor:图像缩放比例;
  • minNeighbors:对特征检测点周边多少有效点同时检测,这样可避免因选取的特征检测点太小而导致遗漏;
  • minSize:特征检测点的最小尺寸,可选参数。
    示例如下:
import cv2 as cv
# 读取图片
img = cv.imread('face.jpg')
# 转换为灰度图片
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 人脸检测器
face_cascade = cv.CascadeClassifier('Harrcascade_frontalface_default.xml')
# 识别人脸
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
for (x,y,w,h) in faces:
    print(x,y,w,h)

其中,图片座标系以左上角为原点,x,y代表人脸区域左上角座标,w代表宽度,h代表高度。

如图所示:

绘制人脸与人眼区域

你需要掌握:

  1. 如何用 OpenCV 在图像上绘制矩形;
  2. 如何使用 OpenCV 绘制图片中人脸区域;
  3. 使用 OpenCV 绘制人脸区域中眼睛区域。

OpenCV 绘制矩形

上面我们学习了通过 OpenCV 的 Harr 分类器检测人脸,并输出识别结果(x,y,w,h)。

图片座标以左上角为原点,(x,y)代表人脸区域左上角座标,w代表人脸区域的宽度(width),h代表人脸区域的高度(height)。

例如:

那么,如何使用OpenCV将人脸区域绘制出来呢?

在 OpenCV 中,可以使用cv2.rectangle()在图片中绘制矩形区域。

它的函数声明为:

cv2.rectangle(图片对象,矩形左上角的座标点,矩形右下角的座标点,颜色(B,G,R),边框线的粗度)

对于上图的红色人脸边框,可以指定左上角座标为(x,y),右下角座标为(x+w,y+h),颜色设定红色,边框线粗度为2。

示例代码如下:

cv2.rectangle(img,(x,y),(x+w,y+h)(0,0,255),2)

使用OpenCV绘制图片中人脸区域

使用 OpenCV 分类器检测人脸之后,一张图片中可能包含多个人脸,所以我们对每一个识别到的人脸都绘制对应的矩形框。

示例代码如下:

ort cv2
# 读取图片
img = cv2.imread('images/girl.jpg')
# 转换为灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 人脸检测器
face_cascade = cv2.CascadeClassifier('path-of-haarcascade_frontalface_default.xml')
# 识别人脸
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 绘制人脸区域
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
    #灰度图片的脸部区域
    face_grays = gray[y:y+h, x:x+w]
    #原图像的脸部区域
    face_areas = img[y:y+h, x:x+w]

识别效果如下:

使用OpenCV绘制人脸区域中眼睛区域

进一步,我们在识别人脸的基础上,使用官方提供的path-of-haarcascade_eye.xml人眼检测模型,识别出人眼并绘制到图片上。

如果单独使用OpenCV人眼检测模型,来识别出整个图片中的人眼区域,效果不是很好。

代码如下:

import cv2
# 读取图片
img = cv2.imread('images/girl.jpg')
# 转换为灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 人脸检测器
face_cascade = cv2.CascadeClassifier('path-of-haarcascade_frontalface_default.xml')
# 识别人脸
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 绘制人脸区域
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
    #灰度图片的脸部区域
    face_grays = gray[y:y+h, x:x+w]
    #原图像的脸部区域
    face_areas = img[y:y+h, x:x+w]
    eye_cascade = cv2.CascadeClassifier('path-of-haarcascade_eye.xml')
    # 识别人眼
    eyes = eye_cascade.detectMultiScale(gray)
    for (ex,ey,ew,eh) in eyes:
        # 绘制人眼
        cv2.rectangle(img,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

同样的(ex,ey,ew,eh)中(ex,ey)代表眼睛区域的左上角座标,ew代表宽度,eh代表高度。

识别效果如下:

绿色为识别的人眼框,可以看出有识别错误的地方。

所以,一般情况下,我们会先检测出人脸区域,然后在人脸区域中使用眼睛区域检测模型得到眼睛区域,进而绘制。

示例代码如下:

import cv2
# 读取图片
img = cv2.imread('images/girl.jpg')
# 转换为灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 人脸检测器
face_cascade = cv2.CascadeClassifier('path-of-haarcascade_frontalface_default.xml')
# 识别人脸
faces = face_cascade.detectMultiScale(gray, 1.3, 5)
# 绘制人脸区域
for (x,y,w,h) in faces:
    cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2)
    #灰度图片的脸部区域
    face_grays = gray[y:y+h, x:x+w]
    #原图像的脸部区域
    face_areas = img[y:y+h, x:x+w]
    eye_cascade = cv2.CascadeClassifier('path-of-haarcascade_eye.xml')
    eyes = eye_cascade.detectMultiScale(face_grays)
    for (ex,ey,ew,eh) in eyes:
        # 在原图像的脸部区域绘制眼睛区域
        cv2.rectangle(face_areas,(ex,ey),(ex+ew,ey+eh),(0,255,0),2)

识别效果如下:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章