【导读】本文是专栏《计算机视觉40例简介》的第28个案例《表情识别》。该专栏简要介绍李立宗主编《计算机视觉40例——从入门到深度学习(OpenCV-Python)》一书的40个案例。 目前,该书已经在电子工业出版社出版,大家可以在京东、淘宝、当当等平台购买。 大家可以在公众号“计算机视觉之光”回复关键字【案例28】获取本文案例的源代码及使用的测试图片等资料。 针对本书40个案例的每一个案例,分别录制了介绍视频。如果嫌看文字版麻烦,可以关注公众号“计算机视觉之光”直接观看视频介绍版。 本文简要介绍了本案例的一些基础知识,更详细的理论介绍、代码实现等内容请参考《计算机视觉40例简介》第25章《人脸检测》以获取更详细信息。 |
当我们预测的是离散值时,进行的是“分类”。例如,预测一个孩子能否成为一名优秀的运动员,其实就是看他是被划分为“好苗子”还是“普通孩子”的分类。对于只涉及两个类别的“二分类”任务,我们通常将其中一个类称为“正类”(正样本),另一个类称为“负类”(反类、负样本)。
例如,在人脸检测中,主要任务是构造能够区分包含人脸实例和不包含人脸实例的分类器。这些实例分别被称为“正类”(包含人脸图像)和“负类”(不包含人脸图像)。
本节介绍分类器的基本构造方法,以及如何调用OpenCV中训练好的分类器实现人脸检测。
OpenCV提供了三种不同的训练好的级联分类器,下面简单介绍其中涉及的一些基本概念。
1. 级联分类器
通常情况下,分类器需要对图像的多个特征进行识别。例如,识别一个动物到底是狗(正类)还是其他动物(负类)时,如果我们直接根据多个条件进行判断,这样比较下来是非常烦琐的。但是,如果首先就判断它们有几条腿:
这样,仅仅通过比较腿的数目这个判断就能排除样本集中大量的负类(例如鸡、鸭、鹅等不是狗的其他动物的实例)。
级联分类器就是基于这种思路,将多个简单的分类器按照一定的顺序级联而成的。
级联分类器的基本原理如图1所示。
图1 级联分类器示意图
级联分类器的优势是,在开始阶段仅进行非常简单的判断,就能够排除明显不符合要求的实例。在开始阶段被排除的负类,不再参与后续分类,这样能极大地提高后面分类的速度。这有点像我们经常收到的骗子短信,大多数人通常一眼就能识别出这些短信是骗人的,也不可能上当受骗。骗子们随机大量发送大多数人明显不会上当受骗的短信,这种做法虽然看起来非常愚蠢,但总还是有人会上当。这些短信,在最开始的阶段经过简单的筛选过滤就能够将完全不可能上当的人排除在外。不回复短信的人,是不可能上当的;而回复短信的人,才是目标人群。这样,骗子轻易地就识别并找到了目标人群,能够更专注地“服务”于他们的“最终目标人群”(不断地进行短信互动),从而有效地避免了与“非目标人群”(不回复短信的人群)发生进一步的接触而“浪费”时间和精力。除此以外,生活中还存在着大量的应用。例如,我们在拨打服务电话时,通常也是通过不断地拨不同的数字键进行选择(普通话请按1,英语请按0;查询话费请按……),从而得到最终的服务。
OpenCV提供了用于训练级联分类器的工具,也提供了训练好的用于人脸定位的级联分类器,都可以作为现成的资源使用。
2. Haar级联分类器
OpenCV提供了已经训练好的Haar级联分类器用于人脸定位。
下面,用一个简单的例子来叙述Haar级联分类器的基本原理。假设有两幅4×4大小的图像,如图2所示。针对这两幅图像,我们可以通过简单的计算来判断它们在左右关系这个维度是否具有相关性。
图2 图像示例
用两幅图像左侧像素值之和减去右侧像素值之和:
这两幅图像中,“左侧像素值之和”减去“右侧像素值之和”都是40。所以,可以认为在“左侧像素值之和”减去“右侧像素值之和”这个角度(左侧比右侧稍亮),这两幅图像具有一定的相关性。
进一步扩展,我们可以从更多的角度考虑图像的特征。学者Papageorgiou等人提出了如图3所示的Haar特征,这些特征包含垂直特征、水平特征和对角特征。他们利用这些特征分别实现了行人检测(Pedestrian Detection Using Wavelet Templates)和人脸检测(A General Framework For Object Detection)。
图3 Haar特征
Haar特征反映的是图像的灰度变化,它将像素划分为模块后求差值。Haar特征用黑白两种矩形框组合成特征模板,在特征模板内,用白色矩形像素块的像素和减去黑色矩形像素块的像素和,应用该差值来表示该模板的特征。经过上述处理后,人脸部的一些特征就可以使用矩形框的差值简单地表示了。比如,眼睛的颜色比脸颊的颜色要深,鼻梁两侧的颜色比鼻梁的颜色深,唇部的颜色比唇部周围的颜色深。
关于Harr特征中的矩形框,有如下3个变量。
上述3个变量保证了能够细致全面地获取图像的特征信息。但是,变量的个数越多,特征的数量也会越多。例如,仅一个24×24大小的检测窗口内的特征数量就接近20万个。由于计算量过大,该方案并不实用,除非能够进一步简化特征。
后来,Viola和Jones两位学者在论文Rapid Object Detection Using A Boosted Cascade Of Simple Features和Robust Real-time Face Detection中提出了使用积分图像快速计算Haar特征的方法。他们提出通过构造“积分图(Integral Image)”,让Haar特征能够通过查表法和有限次简单运算快速获取,极大地减少了运算量。同时,在这两篇文章中,他们提出了通过构造级联分类器让不符合条件的背景图像(负样本)被快速地抛弃,从而能够将算力运用在可能包含人脸的对象上。
为了进一步提高效率,Lienhart 和Maydt两位学者,在论文An Extended Set Of Haar-Like Features For Rapid Object Detection中提出对Haar特征库进行扩展。他们将Haar特征进一步划分为如图4所示的4类:
图4 Haar扩展特征
Lienhart 和Maydt两位学者认为在实际使用中,对角特征(见图4底部)和线特征中的“e”和“g”(见图4的第2行,(e)图和(g)图)是相近的,因此通常情况下无须重复计算。同时,该论文还给出了计算Haar特征数的方法、快速计算方法,以及级联分类器的构造方法等内容。
OpenCV在上述研究的基础上,实现了将Haar级联分类器用于人脸部特征的定位。我们可以直接调用OpenCV自带的Haar级联特征分类器来实现人脸定位。
在OpenCV中,人脸检测使用的是cv2.CascadeClassifier.detectMultiScale()函数,它可以检测出图片中所有的人脸。
级联分类器的功能十分强大,提供了诸多实用功能。例如,通过harrcascade_smile.xml可以实现微笑的表情检测。
检测笑脸的核心代码如下:
# -*- coding: utf-8 -*-
"""
Created on Tue Sep 14 20:55:14 2021
@author: 李立宗 lilizong【at】gmail.com
微信公众号:计算机视觉之光(微信号cvlight)
计算机视觉40例——从入门到深度学习(OpenCV-Python)
李立宗 著 电子工业出版社
"""
# ================1 加载分类器========================
faceCascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
smile=cv2.CascadeClassifier("haarcascade_smile.xml")
# ================2 处理摄像头视频========================
# 初始化摄像头
cap=cv2.VideoCapture(0,cv2.CAP_DSHOW)
# 处理每一帧
while True:
# 读取一帧
ret,image=cap.read()
image=cv2.flip(image,1)
# 没有读到,直接退出
if ret is None:
break
# 灰度化(彩色BGR-->灰度Gray)
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
# 人脸检测
faces = faceCascade.detectMultiScale(gray,
scaleFactor = 1.1,
minNeighbors = 5,
minSize = (5,5))
# ==================处理每个人脸=======================
for(x,y,w,h) in faces:
cv2.rectangle(image,(x,y),(x+w,y+h),(0,255,0),2)
# 提取人脸所在区域,多通道形式
# roiColorFace=image[y:y+h,x:x+w]
# 提取人脸所在区域,单通道形式
roi_gray_face=gray[y:y+h,x:x+w]
# 微笑检测,仅在人脸区域内检测
smiles=smile.detectMultiScale(roi_gray_face,
scaleFactor = 1.5,
minNeighbors = 25,
minSize = (50,50))
for (sx,sy,sw,sh) in smiles:
# 如果显示smiles,会有很多反馈
# cv2.rectangle(roiColorFace,(sx,sy),(sx+sw,sy+sh),
# color=(0,255,255),
# thickness=2)
# 显示文字“smile”表示微笑了
cv2.putText(image,"smile",(x,y),cv2.FONT_HERSHEY_COMPLEX_SMALL,1,
(0,255,255),thickness=2)
# 显示结果
cv2.imshow("dect",image)
key=cv2.waitKey(25)
if key==27:
break
运行程序,程序运行结果如图5所示。
图5 人脸检测结果
在《计算机视觉40例——从入门到深度学习(OpenCV-Python)》一书中,从算法原理、实现流程等角度系统深入地介绍了该案例的理论基础和实现过程,并对具体的代码实现进行了细致的介绍与解释。欢迎大家阅读第25章《人脸检测》获取详细内容。
《计算机视觉40例——从入门到深度学习(OpenCV-Python)》在介绍Python基础、OpenCV基础、计算机视觉理论基础、深度学习理论的基础上,介绍了计算机视觉领域内具有代表性的40个典型案例。这些案例中,既有传统的案例(数字识别、答题卡识别、物体计数、缺陷检测、手势识别、隐身术、以图搜图、车牌识别、图像加密、指纹识别等),也有深度学习案例(图像分类、风格迁移、姿势识别、实例分割等),还有人脸识别方面的案例(表情识别、驾驶员疲劳监测、识别性别与年龄等)。