分享

OpenCV人脸检测原理

 mediatv 2020-07-23

效果图

闲扯:公司鼓励创新,做了个皮肤检测器,本来的想法是用手机外接wifi摄像头,用摄像头来拍摄皮肤图像的,后来找了几个wifi摄像头的厂家,因价格没谈拢,就不用wifi摄像头了,只用手机自带的相机来获取图像。

下面我写了个 demo 测试,如下图

me

目前实现了皱纹,油份,水份的检测算法,以后还想实现更多功能,比如痘痘数量,色斑检测,年龄预测等等。


人脸检测原理

人脸检测就是要判断一张图像是不是人脸,以及人脸的位置。
一张大图像由他的一张很小的子图像窗口,以一定的倍数扩大(比如每次扩大 1.2 倍)暴力搜索,最终能确定位置。

判断一张图像是不是人脸,先提取图像的 haar-like 特征值,交给 adaboost 算法,它能判断是不是人脸。

提取图片的 haar 特征

  • 为什么要提取 haar 特征?
    因为要用 adaboost 做分类,整张图塞进去计算量太大,提取一些主要的特征,能区分人脸非人脸就行。

  • 怎么提取 haar 特征?
    有大牛已经给出方法了,看下面的模板,把模板放在图像上,用 白色区域的灰度和 减去 黑色区域的灰度和,得到的数值就是其中一个 haar 特征,把模板在图像上滑动,能计算出一组数值,例如(123, 234, -134, ...),这就是图像的 haar 特征了。

  • 拓展:
    图像区域快速求和,用积分图,对原图像进行一次积分,就能在O(1)时间算出区域像素和,大概写一下。

假设积分图是 F(x, y),求 Rect(x, y, w, h) 区域和。
sum = F(x+w, y+h) - F(x+w, y) - F(x, y+h) + F(x, y)

// F(x, y) 表示 Rect(0, 0, x, y) 的区域和,f(x, y) 表示 (x, y) 灰度级
// 后面加上 + F(x, y) 是因为发现 - F(x+w, y) - F(x, y+h) 减多了重叠的区域,所以就加回来。
// 生成积分图的状态转移方程:
F(x, y) = f(x, y) + F(x-1, y) + F(x, y-1) - F(x-1, y-1)


AdaBoost 算法

先来一个感性的认识。

每来一张图片,提取其特征值 X,用 AdaBoost 算法能判断出 X 是不是人脸。
AdaBoost 里面有很多个分类器对特征值 X 进行打分,分数有正有负,每个分类器还有个权值,最终把多个分类器给出的分数乘上他们自身的权值,全部累加起来,得到一个数值,如果是正数,表示属于 1 类,负数表示属于 -1 类。

假设 1 类是人脸类,-1 类是非人脸类,就能分出一张图是不是人脸了。

分类器可以理解为一个函数 G(x),输入特征值 x,返回数值 G(x)

AdaBoost 里面有多个弱分类器 (假设3个),组合成一个强分类器,像这样

每个弱分类器有权重

再来个sign(n)函数,sign 返回 n 前面的正负号,0和正数返回 1,负数返回 -1

拓展到 n,最终的判断公式为

输入一个图像的特征值 x,看看返回是 1 还是 -1,就可以判断出是人脸还是非人脸。

其他:w1, w2, w3 一开始不知道是多少,需要训练数据进行多轮的迭代后算出,训练过程就是调整权值的过程。训练完了后,就用这些权值组成的模型,对未知的图像进行分类。


具体的例子

有8组包含各种情况的特征值,作为训练数据。

特征值 x 1 2 3 4 5 6 7 8
类别 1 1 -1 -1 -1 1 1 1

1.初始化 n 组训练数据的权值为 D(i) = 1 / n
所以 1 到 8 的权值为 1 / 8 = 0.125
D = (0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125)

2.多轮迭代
看训练数据
1, 2 属于 1 类
3, 4, 5 属于 -1 类
6, 7, 8 属于 1 类

2 到 3 的时候,由 1 变为 -1,是一个变化的地方,设定 x = 2.5,意思是在 2.5 的地方切一刀。
5 到 6 由 -1 变为 1,又是一个变化点,设定 x = 5.5

下面对 2.5,5.5 进行迭代

规则:有一个常数 c,先认为 x <= c 的元素为 1 类,x > c 的为 -1 类,然后计算有多少个数据被分错的。
误差率 e = 分错的元素的权值和
如果误差率 e > 0.5,则反过来,认为 x <= c 的为 -1,x > c 的为 1。

误差率写成公式有点晦涩了,用文字描述比较直观,就是把被分类器分错的元素的和权值全部加起来,就是误差率了。


  • 第一轮迭代

x = 2.5 时,先认为 x <= 2.5 为 1 类,x > 2.5 的为 -1 类
那么 6, 7, 8 三个元素被分错了,每个元素的权值为 0.125。
误差率为 6, 7, 8 的权值和:0.125 + 0,125 + 0.125 = 0.375

x = 5.5 时,先认为 x <= 5.5 为 1,x > 5.5 为 -1
那么 3, 4, 5, 6, 7, 8 六个元素被分错。
误差率为 6 乘 0.125 = 0.75 大于 0.5 了。
那么反过来 x <= 5.5 为 -1,x > 5.5 为 1,此时只有 1, 2 被分错。
误差率为 1, 2 的权值和:0.125 + 0.125 = 0.25

选个误差小的 0.25,得出第一个分类器 G1


计算 G1 权重公式:(e 是误差率)

该函数图像:

由图像可知误差率 e 越小,w 权值越大。

G1 的误差率 e1 = 2 / 8 = 0.25
G1 权重 w1 = 1 / 2 * log (0.75 / 0.25) = 0.23856

w1 就描述了 G1 的重要程度,或者说对一个特征值被分成哪一类的话语权的大小。

接下来要更新以下元素权重:
第一轮:D = (0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125, 0.125)
假设第一轮的 D = (d1, d2, d3, ..., dn),是已知的
下一轮的 D = (k1, k2, k3, ..., kn),是要计算的

权重更新公式:

其中常数 Z 是

ki 本轮要计算的元素的权重
di 上一轮已经计算出的权重
w 上一轮分类器的权重
G(xi) 上一轮分类器对第 i 个特征的分类结果
yi 第 i 个元素的类别,1 或者 -1
e 自然常数,约 2.71828
Z 归一化用的常数

按照上面方式,算出新的权重为

D = (0.174721, 0.174721, 0.108426, 0.108426, 0.108426, 0.108426, 0.108426, 0.108426)

可以看出 1, 2 被分错后,它的权值增大了,那么如果后面的分类器再把 1, 2 分错,产生的误差率会更大,因为误差率根据权值和算出的,所以权值大的,会被重点考虑。

  • 第二轮迭代

x = 2.5 时,误差率为 6, 7, 8 权值和:0.325278
x = 5.5 时,误差率为 1, 2 的权值和:0.349442

选个误差率小的,即 0.325278,x = 2.5 的,得出第二个分类器 G2

G2 的误差率 e2 = 0.325278
G2 权重 w2 = 0.15844

此时,已经得到两个弱分类器,代入 adaboost 算法的公式中

得到模型:


  • 测试该模型
特征值 x 1 2 3 4 5 6 7 8
类别 1 1 -1 -1 -1 1 1 1
G(x) -1 -1 -1 -1 -1 1 1 1

分析 G(x) 得出的结果,发现 1,2 被分错了,还是有误差,说明本例子迭代两次是不够的,还需要更多轮的迭代,减小误差,直到模型 G(x) 在训练数据上的误差为0,再继续迭代下去误差会收敛于一个常数。(详见最后的参考文献)

训练好了一个误差很小的模型 G(x),就可以用该模型去对未知的图像进行分类,分为人脸类和非人脸类,即可检测出一张图像是不是人脸。


推荐一个在线公式编辑在线函数绘图

参考文献:July 的《Adaboost 算法的原理与推导》

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多