使用机器学习的方法进行人脸检测的第一步需要训练人脸分类器,这是一个耗时耗力的过程,需要收集大量的正负样本,并且样本质量的好坏对结果影响巨大,如果样本没有处理好,再优秀的机器学习分类算法都是零。
今年3月23日,微软公司在推特(Twitter)社交平台上推出了一个基于机器学习的智能聊天机器人Tay,Tay被设定为一个年龄为十几岁的女孩,主要目标受众是18岁至24岁的青少年。人们只需要@一下Tay,Tay就会追踪该用户的网名、性别、喜欢的食物、邮编、感情状况等个人信息。除了聊天,Tay还可以说笑话,讲故事等,让人感觉这就是一个知道你很多小秘密,嘴甜心暖的“小闺蜜”。Tay会在与人们的交流中不断学习,随着时间积累,她的理解能力将逐步提升,变得愈发“智能”。
然而比较戏剧性的是在Tay推出24小时不到,这个人工智能机器人就被人类彻底“教坏”,成为一个集反犹太人、性别歧视、种族歧视于一身的“不良少女”。逼得微软不得不让Tay暂时“下岗”。
微软在一项声明中表示,“人工智能机器人Tay属于机器学习项目,设计它的目的就是让它与人类进行互动。在学习的过程中,它把人类的好坏言论都学了。因此,它发表了一些不恰当的言论。我们正在纠偏,对Tay进行调整。”
微软的机器学习算法不可谓不先进,但是为什么会出现这种情况呢,比较合理的解释就是Tay是被人们输入的“不良”样本带坏的。
一个好消息是,OpenCV安装包里自带有已经训练好的人脸分类器“haarcascade_frontalface_alt.xml”,位置在“XX\opencv\sources\data\haarcascades”里,我们可以直接拿来使用,检测效果还可以接受。这个文件夹下还有其他一些分类器,像左右眼、上身、笑脸检测等等。
下边就使用OpenCV自带的基于Haar特征的级联分类器实现人脸检测,使用的版本是VS2012+OpenCV2.4.10,本来我的机器上安装的是OpenCV2.4.13版本,但是发现13版本的加载分类器的函数cvLoad总是报错,换成10版本就没问题了(包括之前在训练决策树的时候,也发现2.4.13版本的训练结果总是不对)。
程序涉及到Mat和IplImage指针的一个转换,还有一个比较关键的函数cvHaarDetectObjects,函数原型是:
cvHaarDetectObjects( const CvArr* image,
CvHaarClassifierCascade* cascade, CvMemStorage* storage,
double scale_factor CV_DEFAULT(1.1),
int min_neighbors CV_DEFAULT(3), int flags CV_DEFAULT(0),
CvSize min_size CV_DEFAULT(cvSize(0,0)), CvSize max_size CV_DEFAULT(cvSize(0,0)));
#include
#include "highgui/highgui.hpp"
#include
using namespace std;
using namespace cv;
int main()
{
// 加载Haar特征检测分类器
const char *pstrCascadeFileName = "D:\\ProgramFilesD\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml";
CvHaarClassifierCascade *pHaarCascade = NULL;
pHaarCascade = (CvHaarClassifierCascade*)cvLoad(pstrCascadeFileName);
// 载入图像并转换为灰度图像
const char *pstrImageName = "E:\\Picture\\Face03.jpg";
Mat image=imread(pstrImageName);
Mat imageGray;
cvtColor(image,imageGray,CV_RGB2GRAY);
// 人脸识别与标记
if (pHaarCascade != NULL)
{
MemStorage mStorage=cvCreateMemStorage(0);
cvClearMemStorage(mStorage);
// 识别
DWORD dwTimeBegin, dwTimeEnd;
dwTimeBegin = GetTickCount();
//Mat转换为IplImage
IplImage IimageGray(imageGray);
CvSeq *pcvSeqFaces = cvHaarDetectObjects(&IimageGray, pHaarCascade, mStorage);
dwTimeEnd = GetTickCount();
cout<<"检测到的人脸总数:\n"<total<total; i++)
{
CvRect* r = (CvRect*)cvGetSeqElem(pcvSeqFaces, i);
Point2f p1=Point2f(r->x,r->y); //矩形左上角点位
Point2f p2=Point2f(r->x+r->height,r->y+r->width); //矩形右下角点位
rectangle(image,p1,p2,Scalar(255,0,0),2); //矩形框标注人脸位置
}
}
namedWindow("人脸检测",0);
imshow("人脸检测", image);
waitKey(0);
return 0;
}
标准脸:
艺术照:
多人合照:
这个是专门针对正面人脸的,检测效果还可以,有时候会有误检,通过调整参数一般可以消除掉。