OpenCV人脸识别之一:数据收集和预处理

时间:2022-05-03
本文章向大家介绍OpenCV人脸识别之一:数据收集和预处理,主要内容包括OpenCV之识别自己的脸——C++源码放送、还要再强调的一点是:人脸识别源码运行指南、基本概念、基础应用、原理机制和需要注意的事项等,并结合实例形式分析了其使用技巧,希望通过本文能帮助到大家理解应用这部分内容。

本系列人脸识别文章用的是opencv2,最新版的opencv3.2的代码请参考文章:

《OpenCV之识别自己的脸——C++源码放送》;

《人脸识别源码运行指南》(小编附在文末)

前段时间对人脸检测进行了一些尝试:人脸检测(C++/Python)(http://www.jianshu.com/p/504c081d7397)但是检测和识别是不同的,检测解决的问题是图片中有没有人脸;而识别解决的问题是,如果一张图片中有人脸,这是谁的脸。人脸检测可以利用opencv自带的分类器,但是人脸识别就需要自己收集数据,自己训练分类器了。opencv给出的有人脸识别的教程:Face Recognition with OpenCV(https://docs.opencv.org/2.4/modules/contrib/doc/facerec/facerec_tutorial.html)。网上也可以找到中文版本的。

正所谓自己动手丰衣足食。站在巨人的肩膀上,参考前辈们的经验,终于能够识别出自己了。由于感觉内容较多,而且没有时间一次性写完,所以准备分阶段来写。每一篇博客是一个阶段的工作。初步设想分为数据收集和预处理、训练模型和人脸识别三个部分。今天先写第一部分。

1、背景数据集

本次用的数据集市opencv给出的教程里面的第一个数据集:The AT&T Facedatabase(http://www.cl.cam.ac.uk/research/dtg/attarchive/facedatabase.html)。又称ORL人脸数据库,40个人,每人10张照片。照片在不同时间、不同光照、不同表情(睁眼闭眼、笑或者不笑)、不同人脸细节(戴眼镜或者不戴眼镜)下采集。所有的图像都在一个黑暗均匀的背景下采集的,正面竖直人脸(有些有有轻微旋转)。

下载下来之后是这样的:

可以看到每个人一个文件夹,每个文件夹下是这个人的十张照片,但是不是我们熟悉的BMP或者是PNG或者是JPEG格式的,而是PGM格式的。windows7自带的照片查看器和画图软件都不能打开这种格式的图片。

不过好在我昨天刚对imread()函数研究过:使用imread()函数读取图片的六种正确姿势。所以记得opencv文档里有这样的描述:

imread()还是很强大的,所以写个程序看看那这些人是什么样吧。

2、自己的人脸数据集

1、拍照程序

想要识别自己,单有别人的数据集还是不行的,还需要自己人脸的照片才行。这就需要我们收集自己的照片,然后和上面的那个数据集一起来训练模型。在拿着手机自拍的过程中我想到,问什么不写一个程序用电脑的摄像头自拍呢,随便还能研究下怎么用opencv实现拍照的功能。经过一番实验(其实还是费了好长时间),终于写了一个拍照程序。

程序的功能就是打开电脑摄像头,当P键按下(P是拍照的首字母?还是Photo的首字母?还是Picture的首字母?)的时候,保存当前帧的图像。简单到没朋友(竟然耗费了那么久!)。

while (1)        
 {             
char key = waitKey(100);             
cap >> frame;             
imshow("frame", frame);             
string filename = format("D:\pic\pic%d.jpg", i);              
switch (key)            
 {             
case'p':                 
i++;                 
imwrite(filename, frame);                 
imshow("photo", frame);                
 waitKey(500);                
 destroyWindow("photo");                
 break;             
default:                 
break;            
 }
    }

然后我们就可以运行程序,不停地按下p键对自己一通狂拍了。

2、预处理

在得到自己的人脸照片之后,还需要对这些照片进行一些预处理才能拿去训练模型。所谓预处理,其实就是检测并分割出人脸,并改变人脸的大小与下载的数据集中图片大小一致。

人脸检测在之前的博客中已经做了介绍,这里就不再赘述。详情参考:OpenCV人脸检测(C++/Python)(http://www.jianshu.com/p/504c081d7397)。用ROI分割即可。

检测出人脸之后改变大小使之与ORL人脸数据库人脸大小一致。通过加断点在Locals里面或者是ImageWatch可以看到ORL人脸数据库人脸的大小是92 x 112。

这里只需要对检测后得到的ROI做一次resize即可。

这两步的代码如下:

  std::vector<Rect> faces;             
Mat img_gray;              
cvtColor(img, img_gray, COLOR_BGR2GRAY);             
equalizeHist(img_gray, img_gray);              
//-- Detect faces             
face_cascade.detectMultiScale(img_gray, faces, 1.1, 3, CV_HAAR_DO_ROUGH_SEARCH, Size(50, 50));              
for (size_t j = 0; j < faces.size(); j++)            
 {                 
Mat faceROI = img(faces[j]);                
 Mat MyFace;                
 if (faceROI.cols > 100)                 
{                     
resize(faceROI, MyFace, Size(92, 112));                    
 string  str = format("D:\MyFaces\MyFcae%d.jpg", i);                     
imwrite(str, MyFace);                     
imshow("ii", MyFace);                
 }                 
waitKey(10);

}

至此,我们就得到和ORL人脸数据库人脸大小一致的自己的人脸数据集。然后我们把自己的作为第41个人,在我们下载的人脸文件夹下建立一个s41的子文件夹,把自己的人脸数据放进去。就成了这样下面这样,最后一个文件夹里面是我自己的头像照片:

最后那个at.txt放到下一次再说,训练模型就靠它了。

这里有一点值得注意:我这里保存的图像格式是.jpg的,而不是跟原数据集一样是.pgm的。经测试仍然可以训练出可以正确识别我自己人脸的模型来。但是如果大小不一致会报错。

OpenCV之识别自己的脸——C++源码放送

前言

在将近一年之前,我在CSDN专栏《OpenCV实践之路》中连续发了三篇博客,完整地描述了基于OpenCV进行人脸识别的全过程。三篇都将近一万的阅读量和大量的评论的表明,人脸识别果然是大家在学习OpenCV过程中最感兴趣的课题,之一。当然,也有可能是本科生毕设老师最感兴趣的课题之一。

由于当时写的时候是按照前后流程来的,所以源码比较分散。加之我想当然地认为,很多源码是之前博客中已经放出来的,可以一句带过。这导致了很多同学学习的时候很不方面。但是我由于重装系统,导致当初的源码遗失,也一直没有抽出时间去重新整理一下。这个清明节,没有出门,根据之前的博客基于当下最新的OpenCV3.2重新整理了一遍源码。现在放出来,以飨读者。

小小的区别

当然了,重新整理也不是简单的把源码收集到一起,如果真的那么简单,也就不用去整理了,大家自行收集即可。因为OpenCV3.2人脸识别的内容也是有些小变动。所以现在的代码跟原来的三篇博客仍然是统一的,但是有一些细节不同。

1、自动拍照

之前采集自己的图像的时候,程序设定是运行之后按’p’键拍照并保存图像,然后需要自己手动的去把图像大小转化为跟ORL人脸数据库中的图片大小一样。

现在一切自动,只需要运行即可拍照,变化尺寸,并保存。默认设定拍10张照片,与ORL人脸数据库一致。

2、Python脚本生成at.txt

当时写博客的时候还不会用Python,所以生成的at.txt并不是s1文件夹对应的label就是1,s2就对应2。而是比较混乱的。谁是谁需要自己去记忆。

经过修改后的Python脚本可以是文件夹可label完美对应起来了。

3、训练代码

训练人脸识别模型的代码部分有些改动,主要是因为OpenCV的变动。

头文件和命名空间需要各加一句:

#include<opencv2face.hpp>
using namespace cv::face;

创建模型部分的改变,原来的代码是

Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
Ptr<FaceRecognizer> model1 = createFisherFaceRecognizer();
Ptr<FaceRecognizer> model2 = createLBPHFaceRecognizer();

现在改为:

Ptr<BasicFaceRecognizer> model = createEigenFaceRecognizer(); 
Ptr<BasicFaceRecognizer> model1 = createFisherFaceRecognizer(); 
Ptr<LBPHFaceRecognizer> model2 = createLBPHFaceRecognizer();

其余部分没有太大变化。

下载办法

源码已经分别上传到Github、百度网盘。其中github由于大小限制,不含我训练好的模型。

Github:`https://github.com/LiuXiaolong19920720/recognise-your-own-face

百度网盘:链接:http://pan.baidu.com/s/1nuPFthR 密码:slh8

还要再强调的一点是:人脸识别源码运行指南

人脸识别的源码放出来之后,不少小伙伴下载之后仍然不能运行成功。于是被逼无奈,把源代码改成了我认为最容易运行成功的版本。即使如此,我认为写下这个指南还是有必要的。因为反复回答相同的问题实在是太累人了。

重复一遍,本文环境为win7+vs2015+opencv3.2_with_contrib

源码下载地址

网盘: http://pan.baidu.com/s/1b1J23O 密码:kv1e(谨记此网盘链接与密码,是该系列最新代码下载的地址)

几个问题

首先还是说明几个问题,虽然都说过,但是还是有人问。以后再有人问就直接给他这篇文章。

找不到FaceRecognizer

FaceRecognizer在opencv的contrib模块里的face模块里面。而opencv官方下载的opencv默认是不带contrib的,要实现人脸识别需要用编译了contrib模块的opencv。一般来说需要自己编译。但是自己编译比较麻烦,网上有人分享了编译好的opencv3.2的版本,下载地址如下:

链接:http://pan.baidu.com/s/1qYx3v8S 密码:i0c0

csv文件(也即at.txt)难以自动生成。

源码中我已经写了一个名为add_label.py的python脚本,运行此脚本可以自动生成at.txt。

有时程序崩溃但是黑窗无报错信息。

一个可能的原因是,添加附加依赖项的时候,debug模式最好只添加*d.lib。而release模式最好只添加*.lib。

运行指南

方便起见,下载的源码的文件夹下已经包含了需要用的ORL人脸数据库。在配置好opencv的情况下,需要以下几步。

1、首先用VS打开face-rec.sln。在解决方案管理器中的源文件下添加take_photos.cpp,如果源文件下还有其他cpp文件,请它们排除到项目之外。然后运行此拍照程序。如果拍照效果不好,请自动调整人脸与摄像头之间的距离,或者调节光照条件。拍好的照片会保存在att_facess41文件夹下。

2、生成csv文件。需要电脑上安装有Python2,如果是Python3的话需要把print语句注释掉,没有实际测试过。如果对python有了解,应该不难。在add_label.py所在文件夹下shift+右键然后选择在此处打开命令行窗口。在命令行输入命令:python add_label.py,Enter运行即可。

3、回到VS。把take_photos.cpp排除到项目之外,添加train.cpp到源文件,运行。最后输出3行类似下面的语句表示训练模型成功。此时打开工程文件夹可以看到生成的后缀为xml的模型文件。

Predicted class = 9 / Actual class = 9.

4、回到VS。把train.cpp排除到项目之外,添加rec-your-own-face.cpp到源文件,运行。此时应该会打开摄像头并识别自己的脸。

最后

此人脸识别程序只能做学习研究,因为这个正确率略低。有更高要求的小伙伴请自行探究更好的方法,在这方面我能指点内容的有限。