pythonopencv人脸相似度_一起学python-opencv二十九(实战:人脸检测)

人脸检测

实现人脸检测不是一件简单的事情,因为人脸的特征其实不好提取,你说用颜色吧,但是首先有黄种人,白种人,黑种人,并且图片中出现了和肉色相近的物体怎么办呢?人脸检测一般用的还是CNN(卷积神经网络),没错,这个卷积的意思就是前面说的图像的卷积。

我先来简单介绍一下CNN,参考了https://www.cnblogs.com/skyfsm/p/6790245.html

这个是一个传统的神经网络结构:

CNN的输入就是图像了,可以是灰度图像也可以是彩色图像。一般输入都要做一些预处理:

卷积层就用到了我们前面说的核或者模板。

图像的深度就图像通道的数目,灰度是1,RBG是3,RGBA是4,还有一个卷积层的深度,如图所示。

这里做的就是边界扩充。

和前面说的不一样的是,这里的卷积不一定是一个一个像素滑动的,这个步长可以不是1,这样可以显著减少计算量。

参考https://www.cnblogs.com/nsnow/p/4562308.html

而图像的特性其实是和卷积模板相关联的,不同的模板可以检测出不同的特性,这靠的是模板里每个位置的参数。而模板里每个位置的参数正是我们要学习或者说优化的对象。我觉得把卷积引入图像的原因有两个:一个是卷积确实可以有效得到图像的某些特征,二是卷积可以减少计算量,加入一个图片是512*512的,如果全部用全连接层感觉就太恐怖了。其实可以说二是建立在一基础上的。

关于为什么需要用激活函数或者激励函数,我在

里面有过说明。

池化也可以说是一种卷积操作,我们其实可以有很多方法,比如取均值啊,取中值啊,取众数啊,取最值等,它的目的就是为了压缩数据量,当然这一层其实可以没有的,过拟合我们可以用正则化(一种防止过拟合方法)来一定程度上解决。

神经网络本身就是个黑箱啊,但是我们还是有办法去控制它的趋向的,因为数据集是我们给的啊,假如你给一个机器人学习一个好的data set,那么它就会朝着好的方向学习,最后学出来会是一个比较好的机器人(如果训练结果不是很差的话),如果数据集是说脏话的数据集,那么机器人学习出来就是一个可能满嘴脏话的机器人。也就是说,神经网络虽然是黑箱,但是我们还是可以通过输入来控制输出的嘛。

初值对神经网络来说还是挺重要的,因为最后优化cost函数的时候,函数往往有很多局部最优解,我们训练神经网络用的数值算法都不能保证收敛到全局最优解,有些进化优化算法(遗传算法等)通过调整参数倒是可以,不过速度会比数值算法慢。如果选的初值在一个比较大的局部最小值附近,那么训练出来的结果可能不会很好,比如正确率可能低于百分之60。当然正确率太高也不见得就是好事,可能是过拟合的结果,在欠拟合和过拟合中我们总是需要找到一种权衡,所以说,没有哪个人训练出来的神经网络敢说自己是100%正确的,一是因为本身就不可能,从理论上说,二是你用的数据集即使再大,也不能代表全部,你能把所有情况都涵盖到?

构建一个CNN其实不是什么难事,其实难的是:1.找有标记的数据集,2.训练方法,3.高性能计算机。1我们可以到网上去搜,我推荐一个国内的网站:http://www.dataju.cn/Dataju/web/home

其它数据集请看:http://mt.sohu.com/20180209/n530607148.shtml

训练方法,也就是参数优化方法,我们可以用别人的方法或者直接用整段代码,那么最后一个问题就是训练了,训练一般要用好几万个数据,训练时间一般会很长,可能要几天。我们一般的pc机是不能连续工作那么长时间的,所以选云主机可能是个不错的选择,我听说做美赛的时候,中科大有的大学生去用了中科大超级计算机平台。所以说我们还是借用别人训练好的CNN模型吧。那么哪里有我们这一讲要用的人脸检测的数据呢?在https://github.com/opencv/opencv/tree/master/data

里面有两个我们可以用,反别是HAAR和LBP。

里面的文件都是xml格式的,这里说一下,不要用校园网下github上的东西,太慢了,我这里的校园网反正就是很慢。HAAR的可以检测的东西多一点,笑脸都可以检测。

这个LBP和HAAR都还可以检测猫脸。这个HAAR和LBP是特征的提取方法,是结合CNN来使用的。参考了https://www.cnblogs.com/zhehan54/p/6723956.html

所谓gamma校正法,在冈萨雷斯的数字图像处理里面也有说明:

那几个白点是电子版的问题,我看的纸质版没有。

总结一下gamma变换的规律:

γ>1的时候,增强后的图像会比原图像更暗,可以使高灰度值区域分级更明显,低灰度之间的分层基本消失,反之,输出图像会更亮,可以更好的区分低灰度的层次,而使较高灰度的层次几乎消失。从下图可以很好的理解,γ>1的时候输出的灰度值在输入灰度的下方,所以更暗,还可以看到在输入灰度比较高的地方,输出灰度以很陡的斜率增长,而在输入灰度级比较低的地方,斜率很小,因此,低灰度会出现一定程度的输出合并,而高灰度会有输出分层更细的现象。

这一步计算梯度我们可以应用很多卷积核,sobel啊,prewitt啊等,常用的还是sobel。

顺便说一句,这个怎么得到人脸的特征呢,当然还是通过有人脸区域标记的数据集来训练啊,不过这个和上面说的CNN其实就有点不同了,这个等会再说。

文中给的一个链接我觉得很不错:https://blog.csdn.net/zouxy09/article/details/7922923

AdaBoost是集成学习的一种方式,这个以后有时间我们再来细说,先简单看一下这个吧:

如果想看c++代码请到原文中看。原文中后续也写得十分精彩,有兴趣的可以去看一看,这里我就到此为止了。这些特征提取方法可以和CNN结合起来,并且有一点好处就是,CNN卷积模板的权值是固定的或者说有一个范围而不再是盲目的,这就好比大海捞针变成了从一杯水里面捞针,有的卷积模板不一定可以用数字形式写出来,比如求最大值,不过还是可以给出描述的。卷积层完毕以后,我们得到了特征值,然后把它们和之前用数据集训练出来的特征值比较,这里其实就是一个分类器(可以用神经网络或者决策树等)。看了上面的介绍,感觉HAAR和LBP用的其实不是CNN,就是普通的神经网络而已,因为特征值这一步不是机器学习来的(卷积模板的权值不是学习得来的)而是通过一些数学处理统计得到的。然后我们只需要把这些得到的值输入一个神经网络去训练,其实就是分类或者说划一个边界,什么样的特征值是人脸,什么样的不是。还有其它特征提取方法,以后再补充。

前面下载的分类器都是xml的,xml是个什么格式?参考http://www.w3school.com.cn/xml/xml_intro.asp

我们来稍微看一段:

enmm,这里面应该是包含了最后CNN训练出来的结果特征参数,不过实在是有点看不太懂。不过这并不妨碍我们来应用。载入分类器的函数是:

cascade是串联的意思,这里其实说的是用AdaBoost算法,所以是级联的分类器。

这里导入级联分类器的时候需要注意的是路径里面要么是斜杠要么是双反斜杠,不然的话会把\当作转义处理。然后我们要如何检测呢?参考:https://blog.csdn.net/qq_30155503/article/details/79475461

用的是

为什么会出现miniNei***ors呢?这是因为检测的结果可能是这样的:

很有可能会有些地方分类出错,如何提高正确率呢?那么就应该看一看这个矩形附近有没有矩形,有几个,如果这个参数设置为2,那么就要求矩形附近得有两个矩形才认为这个是人脸,不过这个附近如何定义就不太清楚了。我还有一种想法,就是取矩形重合部分作为最后结果也不错啊,不过这样确实有的时候得到的没有完整包含人脸。

上面写路径的时候忘了文件名,这个scaleFactor还要大于1,也就是必须要有缩放才行。

我们直接来看看,上面路径用的还是错的,用成猫脸的了。不过搞笑的是这个居然也能检测到人脸:

那么试试真正的猫脸呢:

反而效果居然还有点差。挺奇怪的,我们换到人脸的。

用人脸的分类器来识别猫脸的,效果更差,其实我感觉上面这几种特征提取方法都一定程度上丢弃了空间信息,就像直方图一样,所以有些地方看似和人脸差别很大,但是经过特征提取之后反而在某些统计特征上很相似,这个就是因为一定程度上丢失了空间位置信息而只保留了灰度信息。那么识别人脸呢?

效果很不错啊,增大scaleFactor试一试:

这个找到的其实和上面比小了一点,继续增大:

就找不到了。不过调整第三个参数还是可以找到的:

感觉这个scaleFactor越大,似乎错检的概率越小。

这个我暂时不太会解释这个是为什么。缩小图片是会破坏原来图像的特征的,可能缩小的程度合适的时候,只有真正的脸部的特征还能保留一部分,而其它原来会误检出来的区域的特征就会被完全破坏,因为它们其实只是碰巧在原来的大小上特征提取得到的统计特征和人脸的特征相似。不过这个参数也不能太大了。

缩小倍数太大的化就会变得太模糊了,特征就会被完全破坏了,就检测不到了。我们来换一个人种:

这个出来的矩形区域比较多,加大第三个参数:

后面其实还有一个人,不过因为i不是正脸,所以检测不到。这个分类器是frontal的,只能检测正脸,检测不到侧脸。

接着来试一试能不能检测多个人脸:

增大第三个参数:

效果也不好,这个时候就考虑增大第二个参数了,同时有必要的话,减小第三个参数,最后的结果:

其实是有检测侧脸的程序的:

就是那个profileface,是可以检测侧脸的。

总之呢,增大第二个参数和第三个参数都有助于精确定位人脸,但是不能过大。

我们再试一下LBP的:

调整好参数:

我的建议是增大第二个参数,而不是增大第三个参数,因为增大第三个参数会增加处理的时间,因为每次根据积分图统计计算的结果,还要满足minNei***or才能输出,如果这个参数很大,条件很难满足,或者要计算很多数据才能满足,时间就会长,如果这个参数小,前几次积分图计算的结果说不定就能满足,很快就可以输出。

上面有些minNei***or写成了miniNei***or,多了一个i。最后再说一句,人脸检测和人脸识别区别挺大的,这个以前也提到过。人脸检测是在一张图片中找到人脸的区域,但是至于这个是谁,我们不知道,人脸识别是要识别出来这个是谁,而且人脸识别的输入是比较好的,无论是火车站还是哪里的系统,一般都是要求人脸正好在那个框内,如果是这样,那么就可以说是省略了人脸检测这一步,因为已经得到的就是比较好的人脸的区域了。人脸识别怎么识别呢?可能是每个人的脸的某些统计特征会不一样,可以借助这些来识别,然后放进神经网络来分类,如果精度不高,甚至可以直接和事先录入的照片进行对比,可以是直方图对比或者定义一种距离方式,然后定义阈值,和xxx存进去的照片相似度达到阈值,就认为现在是xxx。如果要求精度很高,我觉得用CNN是一个好的办法。

你可能感兴趣的:(pythonopencv人脸相似度_一起学python-opencv二十九(实战:人脸检测))