基于 Adaboost 的人脸检测系统的设计与实现(opencv+Python)

作  者:XJTU_Ironboy
时  间:2018年12月
源码下载:https://pan.baidu.com/s/1JmX-lH2p-H2e8QEBnBJz0Q
联系方式:[email protected]

一、问题描述

  学习和了解基于 OpenCV的人脸检测算法原理,在 C++或者Python环境下基于 OpenCV 实现一个简单的人脸检测和跟踪程序,要求利用笔记本摄像头或其他网络摄像头进行实时检测,最好有良好的人机交互界面(如使用MFC 编程)。在上述基础上,对检测到的人脸进行识别(即能识别不同的人)或对检测到的人脸做一些有趣的处理(例如,仿照QQ2013 版视频通话新功能,给检测到的人脸戴上帽子或画上胡子)。

二、算法原理介绍

  对人脸检测的研究最初可以追溯到 20 世纪 70 年代,早期的研究主要致力于模板匹配、子空间方法,变形模板匹配等。近期人脸检测的研究主要集中在基于数据驱动的学习方法,如统计模型方法,神经网络学习方法,统计知识理论和支持向量机方法,基于马尔可夫随机域的方法,以及基于肤色的人脸检测。目前在实际中应用的人脸检测方法多为基于 Adaboost 学习算法的方法。

  1. 本次实验使用的方法框架
      第一部分:使用Harr-like特征表示人脸,使用“积分图”实现特征数值的快速计算;
      第二部分: 使用Adaboost算法挑选出一些最能代表人脸的矩形特征(弱分类器),按照加权投票的方式将弱分类器构造为强分类器;
      第三部分:使用决策树将各强分类器级联成为一个层叠分类器;
      第四部分:调用电脑摄像头,用该分类器进行人脸检测,人脸标记,戴帽子和戴眼镜处理。
  2. Harr特征
      在人脸检测中,每一个特征的检测都对应于一个矩阵,也可以理解为一个小窗与图像的计算。用这个小窗在一张图片上进行滑动,每滑动一次都进行一次约定的计算,得到一个计算值,该值的大小可以用来判断该处被滑动的区域是否属于人脸。当一个区域通过了所有特征小窗的检测,即认为此处是人脸。
      Harr特征是一种反映图像的灰度变化的,像素分模块求差值的一种特征。它分为三类:边缘特征、线性特征、中心特征和对角线特征。以下是一些Haar特征的示例:
    基于 Adaboost 的人脸检测系统的设计与实现(opencv+Python)_第1张图片
      用黑白两种矩形框组合成特征模板,在特征模板内用黑色矩形像素和减去白色矩形像素和来表示这个模版的特征值。例如:脸部的一些特征能由矩形模块差值特征简单的描述,如:眼睛要比脸颊颜色要深,鼻梁两侧比鼻梁颜色要深,嘴巴比周围颜色要深等。但矩形特征只对一些简单的图形结构,如边缘、线段较敏感,所以只能描述在特定方向(水平、垂直、对角)上有明显像素模块梯度变化的图像结构。
  3. 积分图
      无论是训练还是检测,每遇到一个图片样本,每遇到一个子窗口图像,我们都面临着如何计算当前子图像特征值的问题,一个Harr-like特征在一个窗口中怎样排列能够更好的体现人脸的特征,这是未知的,所以才要训练,而训练之前我们只能通过排列组合穷举所有这样的特征,以上图中最基本四个特征为例,在一个24×24大小的窗口中任意排列至少可以产生数以10万计的特征,对这些特征求值的计算量是非常大的。
      而积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,它是一种能够描述全局信息的矩阵表示方法,大大的提高了图像特征值计算的效率。解释如下:
      只便利一次图像可以得到如下的一个函数信息: g ( u , v ) = ∑ i = 0 u ∑ j = 0 v f ( i , j ) g(u,v)=\sum_{i=0}^{u}\sum_{j=0}^{v}f(i,j) g(u,v)=i=0uj=0vf(i,j)
      g(u,v)函数中,位置(u,v)是原图中位置(u,v)左上方向所有像素的和。由于Harr特征值的计算实际上就是用黑色矩形像素和减去白色矩形像素和来表示这个模版的特征值,借助于这个积分图,任何矩形区域像素值之和的计算都是很快的:
    基于 Adaboost 的人脸检测系统的设计与实现(opencv+Python)_第2张图片
      可知,任何矩形的像素值之和都可以在常数时间内完成,而前提是只需要遍历图像。
  4. Adaboost
       Adaboost是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),然后把这些弱分类器集合起来,构成一个更强的最终分类器(强分类器)。其算法本身是通过改变数据分布来实现的,它根据每次训练集之中每个样本的分类是否正确,以及上次的总体分类的准确率,来确定每个样本的权值。将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。使用Adaboost分类器可以排除一些不必要的训练数据特征,并放在关键的训练数据上面。
      算法简介:
      1. 先通过对N个训练样本的学习得到第一个弱分类器;
      2. 将分错的样本和其他的新数据一起构成一个新的N个的训练样本,通过对这个样本的学习得到第二个弱分类器 ;
      3. 将1和2都分错了的样本加上其他的新样本构成另一个新的N个的训练样本,通过对这个样本的学习得到第三个弱分类器;
      4. 最终经过提升的强分类器。即某个数据被分为哪一类要由各分类器权值决定。
      以上只是对Adaboost算法的一个粗略讲解,如要从算法流程和底层原理方面了解的话建议看周志华老师的《机器学习》第八章 集成学习的8.2 Boosting一节,讲的很清晰。
  5. 层叠分类器
      层叠分类器是一系列强分类器的组合,其中每一层都是Adaboost算法训练得到的一个强分类器。组成强分类器的弱分类器个数随着级数的增加而增加。每层的强分类器经过阈值(分类的界线,每个分类器带一个自己的阈值)调整,使得每一层都能让几乎全部的人脸样本通过,而拒绝很大一部分非人脸样本。构造层叠分类器时要考虑两个平衡:
      a.增加弱分类器个数在降低误识率的同时也增加了计算时间
      b. 降低强分类器的阈值在增加检测率同时也增加了误识率
    高检测率会导致高误识率,这是强分类阈值的划分导致的,要提高强分类器的检测率要降低阈值,要降低强分类器的误识率就要提高阈值
  6. 编程思路
      a. 设置一个死循环(当检测到按空格键立即退出),在循环中调用电脑的摄像头,每次循环获取当前帧的图像frame;
      b. 当前帧图像灰度化的结果赋予img,为了获得更好的检测效果,对该灰度图像进行直方图均衡;
      c. 获取OpenCV中已经训练好的关于检测人脸和眼睛的Adaboost级联分类器(通过解析haarcascade_frontalface_alt.xml和haarcascade_eye.xml文件得到),用该分类器对img进行检测,获取图像中每张人脸的信息(左上角的横纵坐标和长宽值);
      d. 在上述检测结果下将人脸用矩形圈出,并对人脸进行戴帽子处理和带眼镜处理;
      e. 实时显示处理后的frame,detectMultiScale(image , scaleFactor, minNeighbors, flags)是OpenCV中的库函数,它可以检测出图片中所有的人脸,并将人脸用vector保存各个人脸的坐标、大小(用矩形表示),函数由分类器对象调用。

三、程序框图

  程序框图如下所示


基于 Adaboost 的人脸检测系统的设计与实现(opencv+Python)_第3张图片

四、代码实现

  预装库:cv2和numpy
  安装方式:pip install opencvpip install numpy
  Python代码如下(我用的Python3.5版本):
  (注:运行后要关闭的话按下空格键即可)

# coding:utf-8
import cv2
import numpy as np
font = cv2.FONT_HERSHEY_SIMPLEX
# 调用电脑的摄像头
cv2.namedWindow("Face Detection System")
cap=cv2.VideoCapture(0) 
# 读取每帧图片和是否读取成功的success
success,frame = cap.read()
# 获取opencv的分类器——人眼识别和人脸识别
face_Cascade=cv2.CascadeClassifier("haarcascade/haarcascade_frontalface_alt.xml")
eye_cascade = cv2.CascadeClassifier('haarcascade/haarcascade_eye.xml')
[x,y,w,h] = [0,0,0,0]
while success:
    success, frame = cap.read()
    # 将每帧图片灰度化
    size=frame.shape[:2]
    image=np.zeros(size,dtype=np.float16)
    image = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
    # 直方图均衡
    image = cv2.equalizeHist(image)
    im_h,im_w = size
    minSize_1=(im_w//10, im_h//10)
    faceRects = face_Cascade.detectMultiScale(image,1.05,2,cv2.CASCADE_SCALE_IMAGE,minSize_1)
    if len(faceRects)>0: 
        for faceRect in faceRects:
                x,y,w,h = faceRect
                cv2.rectangle(frame,(x,y),(x+w,y+h),[255,255,0],2)
                cv2.rectangle(frame,(int(x+0.25*w),int(y-0.4*h)),(int(x+0.75*w),y),[0,255,0],thickness=-1)
                cv2.putText(frame,'hat', (int(x+0.45*w),int(y-0.2*h)),font,0.6,(255,0,0), 1)
                face_im = np.zeros([w,h],dtype=np.float16)
                temp_image = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
                face_im = temp_image[y:y+h,x:x+w]
                eyeRects = eye_cascade.detectMultiScale(face_im,1.05,2,cv2.CASCADE_SCALE_IMAGE,(w//10,h//10))
                if(len(eyeRects)==2):
                	x1,y1,w1,h1 = eyeRects[0]
                	x2,y2,w2,h2 = eyeRects[1]
                	point_1 = [(2*(x+x1)+w1)//2,(2*(y+y1)+h1)//2]
                	point_2 = [(2*(x+x2)+w2)//2,(2*(y+y2)+h2)//2]
                	r1 = w1//2
                	r2 = w2//2
                	cv2.circle(frame,(point_1[0],point_1[1]),r1,(255,0,255),2)
                	cv2.circle(frame,(point_2[0],point_2[1]),r2,(255,0,255),2)
                	if(x2>x1):
                		cv2.line(frame,(point_1[0]+r1,point_1[1]),(point_2[0]-r2,point_2[1]),(255,0,255),2)
                	else:
                		cv2.line(frame,(point_2[0]+r2,point_2[1]),(point_1[0]-r1,point_1[1]),(255,0,255),2)
    cv2.rectangle(frame,(x, y),(x+w,y+h),[255,255,0],2)
    cv2.imshow("Face Detection System", frame)
    key=cv2.waitKey(5)
    if key==32:
        break
cv2.destroyWindow("Face Detection System")

五、结果分析

  1. 结果展示(后期自己加马赛克辟邪<( ̄▽ ̄)/)
    基于 Adaboost 的人脸检测系统的设计与实现(opencv+Python)_第4张图片
  2. 结果分析
      我在这次实验中加入了两个分类器——人脸检测和人眼检测,在测试中人脸检测效果较好,且符合实时性的要求,标记框也能够做到跟踪;而人眼检测,在带了眼镜的情况下,效果往往不是很好,人眼特征容易被眼镜给影响了,而不带眼镜的时候效果还不错。在移动过程中,检测器的跟踪效果还是不错的,但是分类器也容易将不是人脸的区域误认为是人脸。
      在此次实验中,我的人眼检测和人脸检测不是独立分开的,在编程中一旦检测到人脸,在每张人脸之下,我再进行的人眼检测,保证不会在其他没有人脸的地方误检查出人眼,出现常识性错误。而且之前的测试中,容易出现检测检测丢失的情况,标志矩形框时有时无,效果不是很好,而实际情况是,人脸并没有大幅度变动,只是由于光线原因导致这一帧下图像无法检测出人脸。为了解决这个问题,我让人脸没有检测成功时,矩形框仍然保持上一次的处理,结果显示效果较好。

你可能感兴趣的:(计算机视觉,目标检测算法,源代码,opencv,adaboost,Python,人脸检测,机器学习)