Adaboost
Boosting 指的是通过结合一些精度较低的弱学习器来获得较高精度的方法,弱学习器指的是表现比随即猜测稍微好一些的学习器。
AdaBoost是Adaptive Boosting的缩写。主要思想是维持训练集上的权重分布。最初,所有训练样本的权重均等设置,但每轮之后会增加未被正确分类的示例权重,以使弱学习器不得不将注意力集中在训练困难的样本上。最终的输出结果为所有弱分类器的加权和。
Adaboost的算法的伪代码如下:
输入: 样本
初始化样本权重分布
For :
- 用一个弱分类器在当前权重分布的样本上训练
- 计算错误率 ,是弱分类器的预测结果
- 计算分类器权重
- 更新样本权重:,这里的是一个归一化因子
输出:
Viola-Jones目标检测算法
Viola-Jones目标检测是第一个可以实时处理并有着很好检测率的目标检测算法,主要用于图像中的人脸检测。
这个算法使用正面的面部图像,整个面部必须正对相机,算法是基于眼睛,鼻子的位置来估计人脸图像。
这个算法主要分为四个阶段:
- 选择haar-like的特征
- 创建积分图
- 使用AdaBoost进行训练
- 创建分类器级联
Haar-like的特征是什么东西?
Haar feature人脸上的五官都是有固定位置,额头下面是眉毛和眼睛,鼻子下面是嘴,长成这样的可能不是人,但是人一定是这么长的。
在上面的灰度图中,白色框里的额头部分的亮度总体上来说要比黑色框里的亮度更高,因为黑色框里包括的眉毛和眼珠颜色更深。因此上白下黑的这样一个特征,就可以用于检测当前区域是否是额头和眼睛。当然一张图片里会有许多类似的区域,因此不仅需要检测额头与眼睛,还要它们位于鼻子和嘴的上面,在这些特征的相对位置都是正确的时候,才能判断出是否找到了人脸。
针对不同的区域,有不同的Haar 特征:
Basic Haar-like rectangle features特征值可以被计算为一个数值,只需要计算白色矩形内的像素值和减去黑色矩形的像素之和。这个值越大,说明特征越有可能提供有用的信息。
根据上面的描述应该可以想到,如果想要在图片中找到额头下面是眼睛,眼睛下面是鼻子嘴,需要在很多小的区域内计算特征,计算量会变得很大。为此需要用到一个叫积分图的数据结构,可以在常数时间内计算得到矩阵的特征。
积分图
积分图是一种快速有效的计算图像内一部分的像素总和的方法。
灰度图可以看作是一个二维的矩阵。在积分图中, 每个点储存的都是该点左上方所有像素的总和。
计算当前位置以及左上角的像素和
积分图可以一次性提前算好,当需要求某个子矩阵的和时,只需要查询4个数字,就得以得到子矩阵的和。例如下图中,想要计算矩阵ABCD内像素的和,在积分图内找到A,B,C,D四个位置对应的值,根据公式D-B-C+A就可以得到。
计算区域内像素值的和Adaboost
利用积分图可以很快得到某个特征的值,并判断是否包含人脸。弱学习器将判断一个子区域内是否包含人脸的特征,每个弱学习器只判断一个特征。
Adaboost里,多个弱分类器组合最后会得到的一个强分类器,但当分类器的数量过多时,也会得到使得计算量巨大,为此Viola和Jones又提出了分类器级联。
分类器级联
分类器级联可以理解为将一串弱分类器穿起来,第一个分类器负责检测一个人脸特征,如果检测到了,说明它可能包含一个人脸,将进入下一级的分类器继续检测下一个特征;如果没有,就可以直接判断当前不包括人脸了。下一级的分类器会更加复杂一些。级联序列中的分类器只有当样本经过了前面所有的分类器之和才会被训练到。级联结构本质上是一个退化型的决策树。
在第一级选择眼睛和鼻子的特征,可以达到不到1%的FNR(false negtive rate)和40%的FPR(false positive rate)。因此可以减少超过一半的不必要的最终检测。
分类器级联OpenCV实现
在安装OpenCV的目录下,会有一个叫 haarcascades的文件,我们只需要haarcascade_frontalface_alt.xml 这个文件。
import cv2
# 原始图片
img = cv2.imread("path/he.png")
# 转为灰度图
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 加载分类器
face_cascade = cv2.CascadeClassifier("path/haarcascade_frontalface_alt.xml")
# 在图像上检测,multiscale表示多个比例查看图像子区域,以检测不同大小
detected_faces = face_cascade.detectMultiScale(gray_img)
# 在原图上加上框
for (column, row, width, height) in detected_faces:
cv2.rectangle(
img,
(column, row),
(column + width, row + height),
(0, 255, 0),
2
)
# 显示图片,按0关闭窗口
cv2.imshow('Image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
人脸都被检测到了
Viola-Jones已经是20年前的算法,现在深度学习应用在目标检测上已经取得了非常好的成绩,但不可否认的是二十年前的思想奠定了现在的基础,特征选择,特征组合,分类级联等都与现在的各种神经网络有异曲同工之妙。
网友评论