第九节、人脸检测之Haar分类器

人脸检测属于计算机视觉的范畴,早期人们的主要研究方向是人脸识别,即根据人脸来识别人物的身份,后来在复杂背景下的人脸检测需求愈来愈大,人脸检测也逐渐做为一个单独的研究方向发展起来。html

目前人脸检测的方法主要有两大类:基于知识和基于统计。算法

基于知识的方法:主要利用先验知识将人脸看做器官特征的组合,根据眼睛、眉毛、嘴巴、鼻子等器官的特征以及相互之间的几何位置关系来检测人脸。主要包括模板匹配、人脸特征、形状与边缘、纹理特性、颜色特征等方法。api

基于统计的方法:将人脸看做一个总体的模式——二维像素矩阵,从统计的观点经过大量人脸图像样本构造人脸模式空间,根据类似度量来判断人脸是否存在。主要包括主成分分析与特征脸、神经网络方法、支持向量机、隐马尔可夫模型、Adaboost算法等。数组

本文中介绍的Haar分类器方法,包含了Adaboost算法,稍候会对这一算法作详细介绍。所谓分类器,在这里就是指对人脸和非人脸进行分类的算法,在机器学习领域,不少算法都是对事物进行分类、聚类的过程缓存

咱们要探讨的Haar分类器其实是Boosting算法的一个应用,Haar分类器用到了Boosting算法中的AdaBoost算法,只是把AdaBoost算法训练出的强分类器进行了级联,而且在底层的特征提取中采用了高效率的矩形特征和积分图方法,这里涉及到的几个名词接下来会具体讨论。网络

2001年,Viola和Jones两位大牛发表了经典的《Rapid Object Detection using a Boosted Cascade of Simple Features》和《Robust Real-Time Face Detection》,在AdaBoost算法的基础上,使用Haar-like小波特征和积分图方法进行人脸检测,他俩不是最先使用提出小波特征的,可是他们设计了针对人脸检测更有效的特征,并对AdaBoost训练出的强分类器进行级联。这能够说是人脸检测史上里程碑式的一笔了,也所以当时提出的这个算法被称为Viola-Jones检测器。又过了一段时间,Rainer Lienhart和Jochen Maydt两位大牛将这个检测器进行了扩展,最终造成了OpenCV如今的Haar分类器。机器学习

AdaBoost是Freund和Schapire在1995年提出的算法,是对传统Boosting算法的一大提高。Boosting算法的核心思想,是将弱学习方法提高成强学习算法,也就是“三个臭皮匠顶一个诸葛亮”。ide

Haar分类器 = Haar-like特征 + 积分图方法 + AdaBoost +级联;函数

Haar分类器算法的要点以下:post

  1. 使用Haar-like特征作检测。
  2. 使用积分图(Integral Image)对Haar-like特征求值进行加速。
  3. 使用AdaBoost算法训练区分人脸和非人脸的强分类器。
  4. 使用筛选式级联把强分类器级联到一块儿,提升准确率。

一 Haar-like特征

Haar(哈尔)特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。特征模板内有白色和黑色两种矩形,并定义该模板的特征值为白色矩形像素和减去黑色矩形像素和Haar特征值反映了图像的灰度变化状况。例如:脸部的一些特征能由矩形特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,因此只能描述特定走向(水平、垂直、对角)的结构。

对于图中的A, B和D这类特征,特征数值计算公式为:v=Σ白-Σ黑,而对于C来讲,计算公式以下:v=Σ白-2*Σ黑;之因此将黑色区域像素和乘以2,是为了使两种矩形区域中像素数目一致。咱们但愿当把矩形放到人脸区域计算出来的特征值和放到非人脸区域计算出来的特征值差异越大越好,这样就能够用来区分人脸和非人脸。

经过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为“特征原型”;特征原型在图像子窗口中扩展(平移伸缩)获得的特征称为“矩形特征”;矩形特征的值称为“特征值”。

上图中两个矩形特征,表示出人脸的某些特征。好比中间一幅表示眼睛区域的颜色比脸颊区域的颜色深,右边一幅表示鼻梁两侧比鼻梁的颜色要深。一样,其余目标,如眼睛等,也能够用一些矩形特征来表示。使用特征比单纯地使用像素点具备很大的优越性,而且速度更快。

矩形特征可位于图像任意位置,大小也能够任意改变,因此矩形特征值是矩形模版类别、矩形位置和矩形大小这三个因素的函数。故类别、大小和位置的变化,使得很小的检测窗口含有很是多的矩形特征,如:在24*24像素大小的检测窗口内矩形特征数量能够达到16万个。这样就有两个问题须要解决了:(1)如何快速计算那么多的特征?---积分图大显神通;(2)哪些矩形特征才是对分类器分类最有效的?---如经过AdaBoost算法来训练。

2、Haar-like特征的计算—积分图

积分图就是只遍历一次图像就能够求出图像中全部区域像素和的快速算法,大大的提升了图像特征值计算的效率。

积分图主要的思想是将图像从起点开始到各个点所造成的矩形区域像素之和做为一个数组的元素保存在内存中,当要计算某个区域的像素和时能够直接索引数组的元素,不用从新计算这个区域的像素和,从而加快了计算(这有个相应的称呼,叫作动态规划算法)。积分图可以在多种尺度下,使用相同的时间(常数时间)来计算不一样的特征,所以大大提升了检测速度。

积分图是一种可以描述全局信息的矩阵表示方法。积分图的构造方式是位置$(i,j)$处的值$ii(i,j)$是原图像$(i,j)$左上角方向全部像素$f(k,l)$的和:$$ii(i,j)=\sum\limits_{k≤i,l≤j}f(k,l)$$

积分图构建算法:

一、用$s(i,j)$表示行方向的累加和,初始化$s(i,-1)=0$;

二、使用$ii(i,j)$表示一个积分图像,初始化$ii(-1,i)$=0;

三、逐行扫描图像,递归计算每一个像素$(i,j)$行方向的累加和$s(i,j)$和积分图像$ii(i,j)$的值:

$$s(i,j)=s(i,j-1)+f(i,j)$$

$$ii(i,j)=ii(i-1,j)+s(i,j)$$

四、扫描图像一遍,当到达图像右下角像素时,积分图像$ii$就构建好了。

积分图构造好以后,图像中任何矩阵区域像素累加和均可以经过简单运算获得如图所示:

设D的四个顶点分别为α,β,γ,δ则D的像素和能够表示位$$D_{sum}=ii(α)+ii(β)-(ii(γ)+ii(δ))$$

而Haar-like特征值无非就是两个矩阵像素和的差,一样能够在常数时间内完成。

 三 计算Haar特征值

上面已经知道,一个区域的像素值的和,能够由该区域的端点的积分图来计算。由前面特征模板的特征值的定义能够推出,矩形特征的特征值能够由特征端点的积分图计算出来。以A矩形特征为例,以下图,使用积分图计算其特征值:

 

该矩形特征的特征值,由定义,为区域A的像素值减去区域B的像素值。

区域A的像素值:$$ii(5)+ii(1)-ii(2)-ii(4)$$

区域B的像素值:$$ii(6)+ii(2)-ii(5)-ii(3)$$

因此:该矩形特征的特征值$$ii(5)+ii(1)-ii(2)-ii(4)-[ii(6)+ii(2)-ii(5)-ii(3)]$$$$=[ii(5)-ii(4)]+[ii(3)-ii(2)]-[ii(2)-ii(1)]-[ii(6)-ii(5)]$$

因此,矩形特征的特征值,只与特征矩形的端点的积分图有关,而与图像的坐标无关。经过计算特征矩形的端点的积分图,再进行简单的加减运算,就能够获得特征值,正由于如此,特征的计算速度大大提升,也提升了目标的检测速度。

了解了特征值的计算以后,咱们来看看不一样的特征值的含义是什么。咱们选取MIT人脸库中2706个大小为20*20的人脸正样本图像,计算以下图所示的Haar特征:

左边对应的人眼区域,右边无具体意义。

能够看到,图中2个不一样Haar特征在同一组样本中具备不一样的特征值分布,左边特征计算出的特征值基本都大于0(对样本的区分度大),而右边特征的特征值基本均匀分布于0两侧(对样本的区分度小)。因此,正是因为样本中Haar特征值分布不均匀,致使了不一样Haar特征分类效果不一样。显而易见,对正负样本区分度越大的特征分类效果越好,即红色曲线对应图中的的左边Haar特征分类效果好于右边Haar特征。

那么看到这里,应该理解了下面2个问题:

(1)在检测窗口经过平移+缩放能够产生一系列Haar特征,这些特征因为位置和大小不一样,分类效果也不一样;

(2)经过计算Haar特征的特征值,能够有将图像矩阵映射为1维特征值,有效实现了降维。

 四 Haar特征值归一化(也能够采用标准归一化)

从上图咱们能够发现,仅仅一个12*8大小的Haar特征计算出的特征值变化范围从-2000~+6000,跨度很是大。这种跨度大的特性不利于量化评定特征值,因此须要进行“归一化”,压缩特征值范围。假设当前检测窗口中的图像像素为$i(x,y)$,当前检测窗口为$w*h$大小(例如上图中为20*20大小),OpenCV采用以下方式“归一化”:

一、计算检测窗口中图像的灰度值和灰度值平方和:

$$sum=\sum i(x,y)$$

$$sq_{sum}=\sum i^2(x,y)$$

 二、计算平均值:

$$mean = \frac{sum}{w*h}$$

$$sq_{mean}=\frac{sq_{sum}}{w*h}$$

三、计算归一化因子:

$$varNormFactor=\sqrt{sq_{mean}-mean^2}$$

四、归一化特征值:

$$normValue=\frac{featureValue}{varNormFactor}$$

以后使用归一化的特征值$normValue$与阈值对比。

 五 Adaboost级联分类器

前面几块内容咱们分析了Haar特征,积分图、特征值计算。这里则主要分析一下2个内容:

(1)OpenCV中的Adaboost级联分类器的结构,包括强分类器和弱分类器的形式;

(2)OpenCV自带的XML分类器中各项参数,如internalNodes和leafValues标签里面的一大堆数字的意义。

一、级联分类器

集成学习值Adaboost算法原理和代码小结(转载)小节中咱们已经介绍过了Adboost分类器,这里咱们会介绍一下Adaboost级联分类器。级联分类模型是树状结构能够用下图表示:

其中每个stage都表明一级强分类器。当检测窗口经过全部的强分类器时才被认为是正样本,不然拒绝。实际上,不只强分类器是树状结构,强分类器中的每个弱分类器也是树状结构。因为每个强分类器对负样本的判别准确度很是高,因此一旦发现检测到的目标位负样本,就不在继续调用下面的强分类器,减小了不少的检测时间。由于一幅图像中待检测的区域不少都是负样本,这样由级联分类器在分类器的初期就抛弃了不少负样本的复杂检测,因此级联分类器的速度是很是快的;只有正样本才会送到下一个强分类器进行再次检验,这样就保证了最后输出的正样本的伪正(false positive)的可能性很是低。

二、级联分类器的训练

级联分类器是如何训练的呢?首先须要训练出每个弱分类器,而后把每一个弱分类器按照必定的组合策略,获得一个强分类器,咱们训练出多个强分类器,而后按照级联的方式把它们组合在一块,就会获得咱们最终想要的Haar分类器。

一个弱分类器就是一个基本和上图相似的决策树,最基本的弱分类器只包含一个Haar-like特征,也就是它的决策树只有一层,被称为树桩(stump)。

以20*20图像为例,78,460个特征,若是直接利用AdaBoost训练,那么工做量是极其极其巨大的。

因此必须有个筛选的过程,筛选出T个优秀的特征值(即最优弱分类器),而后把这个T个最优弱分类器传给AdaBoost进行训练。

如今有人脸样本2000张,非人脸样本4000张,这些样本都通过了归一化,大小都是20x20的图像。那么,对于78,460中的任一特征fi,咱们计算该特征在这2000人脸样本、4000非人脸样本上的值,这样就获得6000个特征值。将这些特征值排序,而后选取一个最佳的特征值,在该特征值下,对于特征$f_i$来讲,样本的加权错误率最低。

在肯定了训练子窗口中(20x20的图像)的矩形特征数量(78,460)和特征值后,须要对每个特征$f$,训练一个弱分类器$h(x,f,ρ,Θ)$。$$h(x,f,ρ,Θ)=\begin{cases}1,   {ρf(x)<ρΘ}\\0,  {other}\end{cases}$$

其中$f$为特征,$Θ$为阈值,$ρ$指示不等号的方向,$x$表明一个检测子窗口。对每一个特征$f$,训练一个弱分类器$h(x,f,ρ,Θ)$,就是肯定$f$的最优阈值,使得这个弱分类器对全部的训练样本分类偏差最低。

在弱分类器训练的过程当中,训练采用的照片通常都是20*20左右的小图片,弱分类器训练的具体步骤

一、对于每一个特征 $f$,计算全部训练样本的特征值,并将其排序:

二、扫描一遍排好序的特征值,对排好序的表中的每一个元素,计算下面四个值:

计算所有正例的权重和$T^+$;

计算所有负例的权重和$T^-$;

计算该元素前以前的正例的权重和$S^+$;

计算该元素前以前的负例的权重和$S^-$;

三、选取当前元素的特征值$F_{k_j}$和它前面的一个特征值$F_{k_{j-1}}$之间的数做为阈值,所获得的弱分类器就在当前元素处把样本分开 —— 也就是说这个阈值对应的弱分类器将当前元素前的全部元素分为人脸(或非人脸),而把当前元素后(含)的全部元素分为非人脸(或人脸)。该阈值的分类偏差为:

$$e=min(S^++(T^--S^-),S^-+(T^+-S^+))$$

因而,经过把这个排序表从头至尾扫描一遍就能够为弱分类器选择使分类偏差最小的阈值(最优阈值),也就是选取了一个最佳弱分类器。

这里写图片描述

 

因为一共有78,460个特征、所以会获得78,460个最优弱分类器,在78,460个特征中,咱们选取错误率最低的特征,用来判断人脸,同时用此分类器对样本进行分类,并更新样本的权重。

强分类器的训练步骤:

1.、给定训练样本集($x_i$,$y_i$),$i=1,2,3,...N$,共N个样本,$y_i$取值为0(负样本)或者1(正样本);设人脸正样本的数量为$n_1$,负样本数量为$n_2$; T为训练的最大循环次数;

2.、初始化样本权重为$\frac{1}{n_1+n_2}$,即为训练样本的初始几率分布;

三、$for  t=1,...T$:
①权重归一化$$ω_{t,i}=\frac{ω_{t,i}}{\sum\limits_{j-1}^{n}ω_{t,j}}$$

②对每一个(种)特征$f_j$,训练一个弱分类器$h_j$(如上),每一个分类器只使用一种Haar特征进行训练。分类偏差为:$$ε_j=\sum\limits_{i}ω_i|h_j(x_i)-y_i|$$
③从②肯定的弱分类器中,找出一个具备最小分类偏差的弱分类器$h_t$;
④更新每一个样本对应的权重:

这里,若是样本$x_i$被正确分类,则$e_i=0$,不然$e_i=1$,而$$\beta_t=\frac{ε_t}{1-ε_t}$$

四、最终造成的强分类器组成为:

其中:$$\alpha_t=log\frac{1}{\beta_t}$$
在使用Adaboost算法训练分类器以前,须要准备好正、负样本,根据样本特色选择和构造特征集。由算法的训练过程可知,当弱分类器对样本分类正确,样本的权重会减少;而分类错误时,样本的权重会增长。这样,后面的分类器会增强对错分样本的训练。最后,组合全部的弱分类器造成强分类器,经过比较这些弱分类器投票的加权和与平均投票结果来检测图像。

 三、级联分类器的检测

训练级联分类器的目的就是为了检测的时候,更加准确,这涉及到Haar分类器的另外一个体系,检测体系,检测体系是以现实中的一幅大图片做为输入,而后对图片中进行多区域,多尺度的检测,所谓多区域,是要对图片划分多块,对每一个块进行检测,因为训练的时候用的照片通常都是20*20左右的小图片,因此对于大的人脸,还须要进行多尺度的检测,多尺度检测机制通常有两种策略:

  • 一种是不改变搜索窗口的大小,而不断缩放图片,这种方法显然须要对每一个缩放后的图片进行区域特征值的运算,效率不高;
  • 另外一种方法,不断扩大搜索窗口,进行搜索,解决了第一种方法的弱势。

在区域放大的过程当中会出现同一我的脸被屡次检测,这须要进行区域的合并,这里不做探讨。

不管哪种搜索方法,都会为输入图片输出大量的子窗口图像,这些子窗口图像通过筛选式级联分类器会不断地被每个节点筛选,抛弃或经过。

 四、总结

从上面所述内容咱们能够总结Haar分类器训练的五大步骤:

一、准备人脸、非人脸样本集;

二、计算特征值和积分图;

三、筛选出T个优秀的特征值(即最优弱分类器);

四、把这个T个最优弱分类器传给AdaBoost进行训练。

五、级联,也就是强分类器的强强联手。

在开始前,必定要记住,以20*20窗口为例,就有78,460的特征数量,筛选出T个优秀的特征值(即最优弱分类器),而后把这个T个最优弱分类器传给AdaBoost进行训练获得一个强分类器,最后将强分类器进行级联。

五、XML文件

OpenCV 自带了训练器和检测器。若是你想本身训练一个分类器来检测汽车,飞机等的话,可使用 OpenCV 构建。其中的细节参考这里:Cascade Classifier Training。这里咱们介绍的XML文件,就是OpenCV自带的检测器,在OpenCV 3的库文件中会包含一个文件夹haarcascades,在个人电脑上路径为D:\Anaconda\pkgs\opencv-3.3.1-py36h20b85fd_1\Library\etc\haarcascades。在这个文件夹下包含了OpenCV的人脸检测的XML文件,这些文件可用于检测静止图像,视频和摄像头所获得图像中的人脸。除此以外还有一个文件夹是lbpcascades,它不是经过Haar特征进行人脸检测,而是采用的LBP特征。

从这些文件名能够知道这些级联适用于检测人脸、眼睛、鼻子和嘴等部位的跟踪,这些文件须要正面、直立的人体图像。

 xml文件主要保存相关的特征矩阵,以及各个弱分类器相关的信息,关于各个节点的具体含义能够参考文章haar+adaboost结合讲解(偏重实际),这里不作过多的介绍。

六 人脸检测

在这里咱们将会学习到使用级联分类器进行人脸检测。在静态图像或视频中检测人脸的操做很是类似。视频人脸检测知识从摄像头读出毎帧图像,而后采用静态图像中的人脸检测方法进行检测,固然,视频人脸检测还涉及其余概念,例如跟踪,而静态图像中人脸检测就没有这样的概念,可是它们的基本理论是一致的。

一、静态图像中的人脸检测

咱们首先把haarcascades文件夹复制到当前项目路径下,而后建立.py文件,代码以下:

# -*- coding: utf-8 -*-
"""
Created on Thu Aug 16 10:32:55 2018

@author: lenovo
"""

'''
人脸检测
'''
import cv2
import numpy as np


#1.静态图像中的人脸检测
def StaticDetect(filename):
    #建立一个级联分类器 加载一个 .xml 分类器文件. 它既能够是Haar特征也能够是LBP特征的分类器.
    face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')
    
    #加载图像
    img = cv2.imread(filename)
    #转换为灰度图
    gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #进行人脸检测,传入scaleFactor,minNegihbors,分别表示人脸检测过程当中每次迭代时图像的压缩率以及
    #每一个人脸矩形保留近似数目的最小值
    #返回人脸矩形数组
    faces = face_cascade.detectMultiScale(gray_img,1.3,5)
    for (x,y,w,h) in faces:
        #在原图像上绘制矩形
        img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    cv2.namedWindow('Face Detected!')
    cv2.imshow('Face Detected!',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    

#二、视频中的人脸检测
def DynamicDetect():
    '''
    打开摄像头,读取帧,检测帧中的人脸,扫描检测到的人脸中的眼睛,对人脸绘制蓝色的矩形框,对人眼绘制绿色的矩形框
    '''
    #建立一个级联分类器 加载一个 .xml 分类器文件. 它既能够是Haar特征也能够是LBP特征的分类器.
    face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')
    eye_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_eye.xml')
    
    #打开摄像头    
    camera = cv2.VideoCapture(0)
    cv2.namedWindow('Dynamic')
    
    while(True):
        #读取一帧图像
        ret,frame = camera.read()
        #判断图片读取成功?
        if ret:
            gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
            #人脸检测
            faces = face_cascade.detectMultiScale(gray_img,1.3,5)
            for (x,y,w,h) in faces:
                #在原图像上绘制矩形
                cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
                roi_gray = gray_img[y:y+h,x:x+w]
                #眼睛检测
                eyes = eye_cascade.detectMultiScale(roi_gray,1.03,5,0,(40,40))
                for (ex,ey,ew,eh) in eyes:
                    cv2.rectangle(frame,(ex+x,ey+y),(x+ex+ew,y+ey+eh),(0,255,0),2)
                    
            cv2.imshow('Dynamic',frame)            
            #若是按下q键则退出
            if cv2.waitKey(100) & 0xff == ord('q') :
                break
            
    camera.release()
    cv2.destroyAllWindows()
            

if __name__=='__main__':
    #filename = './image/img23.jpg'
    #StaticDetect(filename)
    DynamicDetect()

咱们来分析一下StaticDetect函数,首先建立一个级联分类器对象,而后加载xml检测器,用来进行人脸检测。

    #建立一个级联分类器 加载一个 .xml 分类器文件. 它既能够是Haar特征也能够是LBP特征的分类器.
    face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')

而后加载图片文件,并将其转换为灰度图像,由于人脸检测须要这样的色彩空间。

    #加载图像
    img = cv2.imread(filename)
    #转换为灰度图
    gray_img = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

接下来进行人脸检测,须要传入scaleFactor和minNeighbors参数,它们分别表示人脸检测过程当中每次迭代时图像的压缩率以及每一个人脸矩形保留近似数目的最小值。而后函数返回人脸矩阵数组。咱们利用cv2.rectangle函数在原图中把矩形绘制出来。

    #进行人脸检测,传入scaleFactor,minNegihbors,分别表示人脸检测过程当中每次迭代时图像的压缩率以及
    #每一个人脸矩形保留近似数目的最小值
    #返回人脸矩形数组
    faces = face_cascade.detectMultiScale(gray_img,1.3,5)
    for (x,y,w,h) in faces:
        #在原图像上绘制矩形
        img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2)
    cv2.namedWindow('Face Detected!')
    cv2.imshow('Face Detected!',img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

运行结果以下,咱们能够看到全部的人脸都检测出来了,可是其中还有一个误检测:

二、视频中的人脸检测

上面已经介绍了在静态图像上进行人脸检测,在视频帧上重复进行这个过程就能完成视频中的人脸检测。DynamicDetect函数主要包括:打开摄像头、读取帧、检测人脸、扫描检测到的人脸中的眼睛,并使用不一样颜色绘制出矩形框。

#二、视频中的人脸检测
def DynamicDetect():
    '''
    打开摄像头,读取帧,检测帧中的人脸,扫描检测到的人脸中的眼睛,对人脸绘制蓝色的矩形框,对人眼绘制绿色的矩形框
    '''
    #建立一个级联分类器 加载一个 .xml 分类器文件. 它既能够是Haar特征也能够是LBP特征的分类器.
    face_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_frontalface_default.xml')
    eye_cascade = cv2.CascadeClassifier('./haarcascades/haarcascade_eye.xml')
    
    #打开摄像头    
    camera = cv2.VideoCapture(0)
    cv2.namedWindow('Dynamic')
    
    while(True):
        #读取一帧图像
        ret,frame = camera.read()
        #判断图片读取成功?
        if ret:
            gray_img = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
            #人脸检测
            faces = face_cascade.detectMultiScale(gray_img,1.3,5)
            for (x,y,w,h) in faces:
                #在原图像上绘制矩形
                cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
                roi_gray = gray_img[y:y+h,x:x+w]
                #眼睛检测
                eyes = eye_cascade.detectMultiScale(roi_gray,1.03,5,0,(40,40))
                for (ex,ey,ew,eh) in eyes:
                    cv2.rectangle(frame,(ex+x,ey+y),(x+ex+ew,y+ey+eh),(0,255,0),2)
                    
            cv2.imshow('Dynamic',frame)            
            #若是按下q键则退出
            if cv2.waitKey(100) & 0xff == ord('q') :
                break
            
    camera.release()
    cv2.destroyAllWindows()

这里和上面有些相似,只是在进行眼睛检测的时候多了几个参数。detectMultiScale有许多可选参数;在人脸检测时,默认选项足以检测人脸,可是眼睛是一个比较小的人脸特征,而且胡子或者鼻子的自己阴影以及帧的随机阴影都会产生假阳性。经过限制对眼睛搜索的最小尺寸为40x40像素,能够去掉假阳性。而后测试这些参数,直至应用程序能够知足预期(例如能够尝试指定特征的最大尺寸,或增长比例因子以及近邻的数量)。

下面咱们来总结一下detectMultiScale函数:

detectMultiScale(image[,scaleFactor[,minNeighbors[,flags[,minSize[,maxSize]]]]])
  • image:表示的是要检测的输入图像
  • scaleFactor:为每个图像尺度中的尺度参数,默认值为1.1。scaleFactor参数能够决定两个不一样大小的窗口扫描之间有多大的跳跃,这个参数设置的大,则意味着计算会变快,但若是窗口错过了某个大小的人脸,则可能丢失物体。
  • minNeighbors:参数为每个级联矩形应该保留的邻近个数,默认为3。minNeighbors控制着误检测,默认值为3代表至少有3次重叠检测,咱们才认为人脸确实存。
  • flags:对于新的分类器没有用(但目前的haar分类器都是旧版的,CV_HAAR_DO_CANNY_PRUNING,这个值告诉分类器跳过平滑(无边缘区域)。利用Canny边缘检测器来排除一些边缘不多或者不少的图像区域;CV_HAAR_SCALE_IMAGE,这个值告诉分类器不要缩放分类器。而是缩放图像(处理好内存和缓存的使用问题,这能够提升性能。)就是按比例正常检测;CV_HAAR_FIND_BIGGEST_OBJECTS,告诉分类器只返回最大的目标(这样返回的物体个数只多是0或1)只检测最大的物,CV_HAAR_DO_ROUGH_SEARCH,他只可与CV_HAAR_FIND_BIGGEST_OBJECTS一块儿使用,这个标志告诉分类器在任何窗口,只要第一个候选者被发现则结束寻找(固然须要足够的相邻的区域来讲明真正找到了。),只作初略检测.
  • minSize:为目标的最小尺寸
  • maxSize:为目标的最大尺寸

参考文献:

[1]浅析人脸检测之Haar分类器方法:Haar特征、积分图、 AdaBoost 、级联

[2]浅析人脸检测之Haar分类器方法

[3]Haar+cascade AdaBoost分类器学习训练总结

[4]OpenCV中的Haar+Adaboost(一):Haar特征详细介绍

[5]Adaboost算法结合Haar-like特征

[6]ADABOOST作人脸检测程序与原理

[7]AdaBoost 人脸检测介绍(3) : AdaBoost算法流程

[8]Haar特征与积分图(推荐)

[9]haar+adaboost结合讲解(偏重原理)

[10]haar+adaboost结合讲解(偏重实际)

相关文章
相关标签/搜索