一、Haar特征原理综述
Haar特征是一种反映图像的灰度变化的,像素分模块求差值的一种特征。它分为三类:边缘特征、线性特征、中心特征和对角线特征。用黑白两种矩形框组合成特征模板,在特征模板内用 黑色矩形像素和 减去 白色矩形像素和来表示这个模版的特征值。例如:脸部的一些特征能由矩形模块差值特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述在特定方向(水平、垂直、对角)上有明显像素模块梯度变化的图像结构。
如上图A、B、D模块的图像Haar特征为:v=Sum白-Sum黑 C 模块的图像Haar特征为:v=Sum白(左)+Sum白(右)-2*Sum黑 这里要保证白色矩形模块中的像素与黑色矩形的模块的像素数相同,所以乘2
对于一幅图像来说,可以通过通过改变特征模板的大小和位置,可穷举出大量的特征来表示一幅图像。上图的特征模板称为“特征原型”;特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为“矩形特征”;矩形特征的值称为“特征值”。例如在24*24大小的图像中可以以坐标(0,0)开始宽为20高为20矩形模版计算上图A特征,也可以以坐标(0,2)开始宽为20高为20矩形模版计算上图A特征,也可以以坐标(0,0)开始宽为22高为22矩形模版计算上图A特征,这样矩形特征值随着类别、大小和位置的变化,使得很小的一幅很小的图像含有非常多的矩形特征。矩形特征值是矩形模版类别、矩形位置和矩形大小这三个因素的函数。
二、AdaBoost分类器
AdaBoost是典型的Boosting算法,属于Boosting家族的一员。在说AdaBoost之前,先说说Boosting提升算法。
Boosting算法是将“弱学习算法“提升为“强学习算法”的过程,主要思想是“三个臭皮匠顶个诸葛亮”。一般来说,找到弱学习算法要相对容易一些,然后通过反复学习得到一系列弱分类器,组合这些弱分类器得到一个强分类器。Boosting算法要涉及到两个部分,加法模型和前向分步算法。加法模型就是说强分类器由一系列弱分类器线性相加而成。一般组合形式如下:
其中,h(x;am) 就是一个个的弱分类器,am是弱分类器学习到的最优参数,βm就是弱学习在强分类器中所占比重,P是所有am和βm的组合。这些弱分类器线性相加组成强分类器。
前向分步就是说在训练过程中,下一轮迭代产生的分类器是在上一轮的基础上训练得来的。也就是可以写成这样的形式:
由于采用的损失函数不同,Boosting算法也因此有了不同的类型,AdaBoost就是损失函数为指数损失的Boosting算法。
AdaBoost 原理理解 基于Boosting的理解,对于AdaBoost,我们要搞清楚两点:
每一次迭代的弱学习h(x;am)有何不一样,如何学习? 弱分类器权值βm如何确定? 对于第一个问题,AdaBoost改变了训练数据的权值,也就是样本的概率分布,其思想是将关注点放在被错误分类的样本上,减小上一轮被正确分类的样本权值,提高那些被错误分类的样本权值。然后,再根据所采用的一些基本机器学习算法进行学习,比如逻辑回归。
对于第二个问题,AdaBoost采用加权多数表决的方法,加大分类误差率小的弱分类器的权重,减小分类误差率大的弱分类器的权重。这个很好理解,正确率高分得好的弱分类器在强分类器中当然应该有较大的发言权。
实例解释
为了加深理解,我们来举一个例子。
有如下的训练样本,我们需要构建强分类器对其进行分类。x是特征,y是标签。
序号 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
---|---|---|---|---|---|---|---|---|---|---|---|
x | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
y | 1 | 1 | 1 | -1 | -1 | -1 | 1 | 1 | 1 | -1 |
令权值分布D1=(w1,1,w1,2,…,w1,10)
并假设一开始的权值分布是均匀分布:w1,i=0.1,i=1,2,…,10
现在开始训练第一个弱分类器。我们发现阈值取2.5时分类误差率最低,得到弱分类器为:
当然,也可以用别的弱分类器,只要误差率最低即可。这里为了方便,用了分段函数。得到了分类误差率e1=0.3。
第二步计算(G1(x)在强分类器中的系数
这个公式先放在这里,下面再做推导。
第三步更新样本的权值分布,用于下一轮迭代训练。由公式:
得到新的权值分布,从各0.1变成了:
D2=(0.0715,0.0715,0.0715,0.0715,0.0715,0.0715,0.1666,0.1666,0.1666,0.0715)
可以看出,被分类正确的样本权值减小了,被错误分类的样本权值提高了。
第四步得到第一轮迭代的强分类器:
以此类推,经过第二轮……第N轮,迭代多次直至得到最终的强分类器。迭代范围可以自己定义,比如限定收敛阈值,分类误差率小于某一个值就停止迭代,比如限定迭代次数,迭代1000次停止。这里数据简单,在第3轮迭代时,得到强分类器:
的分类误差率为0,结束迭代。
F(x)=sign(F3(x))就是最终的强分类器。
算法流程
总结一下,得到AdaBoost的算法流程:
输入:训练数据集
其中,
1. 初始化训练样本的权值分布:
2.对于m=1,2,…,M
(a)使用具有权值分布Dm的训练数据集进行学习,得到弱分类器Gm(x)
(b)计算Gm(x)在训练数据集上的分类误差率:
(c)计算Gm(x)在强分类器中所占的权重:
(d)更新训练数据集的权值分布(这里,zm是归一化因子,为了使样本的概率分布和为1):
3.得到最终分类器:
公式推导
现在我们来搞清楚上述公式是怎么来的。
假设已经经过m−1轮迭代,得到Fm−1(x),根据前向分步,我们可以得到:
我们已经知道AdaBoost是采用指数损失,由此可以得到损失函数:
这时候,Fm−1(x)是已知的,可以作为常量移到前面去:
其中,
是不是觉得还不够像?那就再化简一下:
现在够像了吧?ok,我们继续化简Loss:
公式变形之后,炒鸡激动!
Ok,这样我们就得到了化简之后的损失函数。接下来就是求导了。
对αm求偏导,令
得到:
AdaBoost分析原文链接:https://www.cnblogs.com/ScorpioLu/p/8295990.html
三、实例
detectMultiScale()
参数
- InputArray image,待检测图片,一般为灰度图像加快检测速度;
- std::vector< Rect > & objects,被检测物体的矩形框向量组;为输出量,如人脸检测矩阵Mat
- double scaleFactor,表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%;一般设置为1.1
- int minNeighbors,表示构成检测目标的相邻矩形的最小个数(默认为3个)。 如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。 如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框, 这种设定值一般用在用户自定义对检测结果的组合程序上;
- int flags,要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因此这些区域通常不会是人脸所在区域;
- Size minSize,最小尺寸,用来限制得到的目标区域的范围。
- Size maxSize,最大尺寸,用来限制得到的目标区域的范围。
import cv2
import numpy as np
face_xml = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_xml = cv2.CascadeClassifier('haarcascade_eye.xml')
# 加载文件
# 文件来源:https://juejin.cn/post/6844903607335124999
img = cv2.imread('timg.jpg')
# 加载图片
cv2.imshow('src',img)
# 打印图片
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 进行灰色处理
faces = face_xml.detectMultiScale(gray,1.3,5)
# 检测出图片的人脸
print('face=',len(faces))
# 打印检测出了多少个人脸
for (x,y,w,h) in faces:
# 绘制每一个人脸
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
# 给人脸绘制矩形
roi_face = gray[y:y+h,x:x+w]
roi_color = img[y:y+h,x:x+w]
# 识别人脸
eyes = eye_xml.detectMultiScale(roi_face)
# 识别眼睛
print('eye=',len(eyes))
# 打印检测出了多少个眼睛
for (e_x,e_y,e_w,e_h) in eyes:
cv2.rectangle(roi_color,(e_x,e_y),(e_x+e_w,e_y+e_h),(0,255,0),2)
# 给眼睛绘制矩形
cv2.imshow('dst',img)
# 打印绘制后图片
cv2.waitKey(0)
复制代码
原图:
face= 4
eye= 2
eye= 2
eye= 1
eye= 2
复制代码