英语原文共 514 页,剩余内容已隐藏,支付完成后下载完整资料
表情识别入门
自动表情识别是一个有趣并有挑战性的问题,并且在许多领域有几个重要的应用,比如人机互动,人类行为理解,以及数字动画。和人脸识别不同的是,表情识别需要判断不同人的相同表情。而且一个人可以用不同的方式表达同一个表情,这个问题就变得更复杂了。
现在的用来衡量表情方法被分为两类:静态图像和图像序列。在静态图像方法中,系统分析每一个单独的图像中的表情。在图像序列方法中,系统尝试捕获图像序列中面部动作和变化的时空模式。最近,热点转移到了图像序列方法。然而,这个方法比静态图像的方法更难计算量更大。在这一章,我们将跟随静态图像方法并比较几种OpenCV 3库中的算法。
自动表情识别的问题包括三个子问题:
- 找到图像中的脸:脸的精确位置对面部分析师非常重要的。在这个问题中,我们希望找到图像中的面部区域。这个问题可以看作探测问题。在我们的方法中,我们将使用OpenCV的objdetect模块中的级联分类器来探测脸。而且这个级联分类器易于矫正错误。因此,我们采用Flandmark库从面部区域中提取面部地标并用这些地标提取精确面部位置。
注意
Flandmark是一个开源C库,用于面部地标探测。你可以在以下部分中获取更多地标的信息。我们将使用这个库来减少复杂性。
- 从面部区域提取特征:给定的面部区域,系统会将表情信息作为特征矢量提取。特征矢量编码出输入数据的相关信息。我们将结合feature2d模块里的特征探测器和核心模块里的k 均值算法来获取特征矢量。
- 把特征分为几类表情:这是个分类问题。这个系统使用分类器算法来把上一步提取出的特征映射到某个表情分类(比如高兴,紧张或悲伤)。这是这一章的重点。我们将评估ml模块中的机器学习算法,包括 神经网络,支持向量机和K临近。
在接下来的部分,我们将展示一个完整的表情系统的过程。在下一部分,你将了解几个提升系统效果以适应需求的方法。
表情数据库
为了简化这一章,我们将使用一个数据库来示范一下过程。我们将使用标准数据库,日本女性表情(JAFFE)。数据库中有10个人214张图片。每个人每个表情有三张图像。数据库包括七种表情(高兴,悲伤,愤怒,恶心,恐惧,惊讶和紧张)如下所示:
JAFFE数据集的几个样本
注意
你需要从链接中下载数据库:http://www.kasrl.org/jaffe.html
从图像中找到面部区域
在这一部分,我们将展示一个基本的探测面部方法。我们将使用OpenCV级联分类器来探测面部区域。这个方法可能算法有错误。为了获取精确的位置,我们会提供其他先进的面部地标方法。我们只用面部区域。然而,许多研究者使用面部地标来提取面部组件,比如(眼,嘴)并单独操作这些组件。
注意
如果你像得出更多,你可以查阅这一章面部地标部分。
使用面部探测算法提取面部区域
我们将使用objdetect模块的基于特征的Haar级联分类器。在OpenCV中,你也可以用LBP提取面部区域。基于LBP的级联比Haar更快。用预先训练过的模型,LBP的级联效果比Haar差。然而,还是有可能把LBP级联训练到和Haar级联一个效果的。
注意
如果你像理解对象探测的细节,可以查阅第5章。对象探测的工业实例。
探测面部的代码非常简单。首先,你需要载入预训练过的级联分类器到你的OpenCV安装目录:
CascadeClassifier face_cascade;
face_cascade.load('haarcascade_frontalface_default.xml');
然后以彩色模式载入输入图像,再转换到灰度图像,并用直方图均一化来加强对比度:
Mat img, img_gray;
img = imread(imgPath[i], CV_LOAD_IMAGE_COLOR);
cvtColor(img, img_gray, CV_RGB2GRAY);
equalizeHist(img_gray, img_gray);
Now, we can find faces in the image. The detectMultiScale function stores all the
detected faces in the vector as Rect(x, y, w, h):
vectorlt;Rectgt; faces;
face_cascade.detectMultiScale( img_gray, faces, 1.1, 3 );
在这段代码中,第三个参数1.1是缩放参数,指定了在每个尺寸图像尺寸要缩放多少。下图展示了缩放参数的缩放金字塔。在我们的案例中,缩放参数是1.1。这表示图像要减小10%。参数越小,越可能发现更多的脸。缩放过程在原始图像的分辨率达到模型维度的X或Y方向。然而,如果你像减小尺寸,增加缩放参数到1.2(20%),1.3(30%),或更多。如果你想增加尺寸,减小缩放参数到1.05(5%)或更多。第四个参数3是最小临近数,每一个候选位置都是面部位置。
图像缩放金字塔
下图是临近数为0时的面部探测的结果:
所有面部候选区域
最后,面部区域的位置可以如下获得:
int bbox[4] = { faces[i].x, faces[i].y, faces[i].x faces[i].width, faces[i].y faces[i].height };
每一个面部矢量的元素是个矩形对象。因此,我们这样得到左上角的位置faces[i].x和faces[i].y。右下角的位置是faces[i].x faces[i].width和faces[i].y faces[i].height。这个信息将会在面部地标处理的初始化位置中用到,见下一部分。
从面部区域提取面部地标
这个面部探测器的坏处是结果可能错位。错位可能在缩放和翻译的时候发生。因此,对全部图像提取的面部区域可能互相不对齐。这个错位可能导致识别效果不好,尤其是DENSE特征。在面部地标的辅助下,我们可以对齐所有提取出的脸,然后数据集每个面部组件都在相同区域。
许多研究者利用面部地标来分类而不需要其他表情识别方法。
我们将使用Flandmark库来定位眼,鼻,口。然后,我们将使用这些面部地标来提取精确的面部范围。
引入Flandmark库
Flandmark是一个开源C库用于面部地标探测。
注意
你可以进入Flandmark库主页:http://cmp.felk.cvut.cz/~uricamic/flandmark/.
给定一个脸部图像,flandmark库的目标是估计一个S形来表示面部组件的位置。一个S中的面部形状是一个(x,y)位置矢量,表达为S = [x0y0x1y1hellip;.xnyn]。
Flandmark里预训练的模型有8个点,如图所示。
8地标模型和相应序号
我们使用flandmark是因为整合到OpenCV工程中简单。此外,flandmark库在许多场合中都效果好,甚至戴眼镜的时候。在下图中,我们用flandmark库展示了戴墨镜的图像的结果。红点表示面部地标。
下载并编译flandmark库
Flandmark用C执行并容易整合到我们的工程中。然而,我们需要更改一些头部信息才能被OpenCV使用。下面是下载和编译库的步骤:
1.进入flandmark主页:http://github.com/uricamic/flandmark
2.用指令下载到本地:git clone http://github.com/uricamic/flandmark
3.复制libflandmark 文件夹到工程文件夹
4.复制landmark_model.dat到工程文件
5.复制liblbp.h文件到libflandmark并把
#include 'msvc-compat.h'
改成
#include lt;stdint.hgt;
6.打开flandmark_detector.h把
#include 'msvc-compat.h'
#include lt;cv.hgt;
#include lt;cvaux.hgt;
改成
#include lt;stdint.hgt;
#include 'opencv2/opencv.hpp'
#include 'opencv2/objdetect/objdetect.hpp'
#include 'opencv2/highgui/highgui.hpp'
#include 'opencv2/imgproc/imgproc.hpp'
#include lt;iostreamgt;
#include lt;stdio.hgt;
using namespace std;
using namespace cv;
7.在工程文件夹中编辑CMakeLists.txt并加入发landmark库:
add_subdirectory(libflandmark)
include_directories('${PROJECT_SOURCE_DIR}/libflandmark')
8.链接可执行文件到flandmark静态库
9.添加flandmark头文件到你的源代码
#include 'flandmark_detector.h'
用flandmark探测面部地标
当你完成上述步骤后,提取面部组件就简单了。
首先,我们来创建一个FLANDMARK_Model变量来载入预训练模型:
FLANDMARK_Model * model = flandmark_init('flandmark_model.dat');
然后,保存地标的数量到num_of_landmark变量并创建一个矢量来存储输出结果:
int num_of_landmark = model-gt;data.options.M;
double *points = new double[2 * num_of_landmark];
最后,对每个面部区域,我们创建一个整数向量来存储面部位置并使用flandmark_detect函数来获取最终结果到点向量:
int bbox[4] = { faces[i].x, faces[i].y, faces[i].x faces[i].width,
faces[i].y faces[i].height };
flandmark_detect(new IplImage(img_gray), bbox, model, points);
flandmark_detect函数的第一个参数是IplImage,所以我们需要把我们的灰度图像转换到IplImage结构。
可视化图像中的地标
这一步是可选的。你也不一定要执行这部分代码。然而我们建议你尝试并理解这个结果。下面的代码在图像的地标的位置上画圆:
for(int j = 0 ; j lt; num_of_landmark; j ){
Point landmark = Point((int)points[2 * j], (int)points[2* j 1]);
circle(img, landmark, 4, Scalar(255, 255, 255), -1);
}
下面的图片展示了几个上面代码的例子:
地标提取结果示例
提取脸部区域
我们现在有眼,鼻,口的位置。提取面部区域就变得很简单。
首先,我们计算左眼的中心也就是点2和点6的中心:
Point centerLeft = Point( (int) (points[2 * 6] points[2 * 2]) / 2, (int)(points[2 * 6 1] points[2 * 2 1]) / 2 );
然后,眼睛区域的宽度和点2和点6的x轴间距是不同的:
int widthLeft = abs(points[2 * 6] - points[2 * 2]);
然后,我们得出右眼的中心和宽度:
Point centerRight = Point( (int) (points[2 *
剩余内容已隐藏,支付完成后下载完整资料
资料编号:[151307],资料为PDF文档或Word文档,PDF文档可免费转换为Word
以上是毕业论文外文翻译,课题毕业论文、任务书、文献综述、开题报告、程序设计、图纸设计等资料可联系客服协助查找。