CV--Haar特征描述算子

Haar特征描述算子--人脸检测

  • 1 算法理论介绍
    • 1.1 Haar-like 特征
    • 1.2 Haar-like特征的计算--积分图
      • 1.2.1 积分图主要思想
      • 1.2.2 积分图构造算法
    • 1.3 案列---计算Haar特征值
    • 1.4 特征值归一化
    • 1.5 Adaboost级联分类器
  • 2 python代码实现
    • 2.1 静态图像中的人脸检测

学习目标:

  • 理解Haar-like特征
  • 理解积分图的计算方法
  • 理解使用积分图来计算Haar特征值算法
  • 理解Haar特征归一化算法
  • 学会使用OpenCV自带的Haar分类器进行人脸检测

1 算法理论介绍

1.1 Haar-like 特征

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

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

通过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为“特征原型”;特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为“矩形特征”;矩形特征的值称为“特征值”。
**解释:**两个矩形特征,表示出人脸的某些特征。比如中间一幅表示眼睛区域的颜色比脸颊区域的颜色深,右边一幅表示鼻梁两侧比鼻梁的颜色要深。
矩形特征值是矩形模版类别、矩形位置和矩形大小这三个因素的函数。因此类别、大小和位置的变化,使得很小的检测窗口含有非常多的矩形特征。例如:在24*24像素大小的检测窗口内矩形特征数量可以达到16万个。
这样就有两个问题需要解决:

  1. 如何快速计算那么多特征?—积分图大显神通
  2. 那些矩形特征才是对分类器分来是最有效的?----通过AdaBoost算法来训练。

1.2 Haar-like特征的计算–积分图

积分图就是只遍历一次图像就可以求出图像中所有区域像素和的快速算法,大大的提高了图像特征值计算的效率。

1.2.1 积分图主要思想

是将图像从起点开始到各个点所形成的矩形区域像素之和作为一个数组的元素保存在内存中,当要计算某个区域的像素和时可以直接索引数组的元素,不用重新计算这个区域的像素和,从而加快了计算(这有个相应的称呼,叫做动态规划算法)。

1.2.2 积分图构造算法

积分图是一种能够描述全局信息的矩阵表示方法。积分图的构造方式是:位置(i,j)处的值ii(i,j)是原图像(i,j)左上角方向所有像素f(k,l)的和: ,其中i(x,y)表示像素点(x,y)的积分图,i(x,y)表示原始图像。

构建算法步骤:

1.3 案列—计算Haar特征值

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

该矩形特征的特征值,由定义可知为区域A的像素值减去区域B的像素值。
区域A的像素值:ii(5)-ii(2)-ii(4)+ii(1),就是相当于多减去ii(1)一次
区域B的像素值:ii(6))-ii(5)-ii(3)+ii(2,相当于多减去ii(2)一次

1.4 特征值归一化

发现仅仅一个128大小的Haar特征计算出的特征值变化范围从-2000~+6000,跨度非常大。这种跨度大的特性不利于量化评定特征值,所以需要进行“归一化”,压缩特征值范围。
归一化方法:

  1. 计算检测窗口中图像的灰度值和灰度值平方和:
  2. 计算平均值:
  3. 计算归一化因子:
  4. 归一化特征值:

1.5 Adaboost级联分类器

2 python代码实现

导入这里XML文件,就是OpenCV自带的检测器。

import cv2
import numpy as np
haar_front_face_xml = './data/haarcascade_frontalface_default.xml'
haar_eye_xml = './data/haarcascade_eye.xml'

2.1 静态图像中的人脸检测

# 1.静态图像中的人脸检测
def StaticDetect(filename):
    # 创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器.
    face_cascade = cv2.CascadeClassifier(haar_front_face_xml)

    # 加载图像
    img = cv2.imread(filename)
    # 转换为灰度图
    gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
  
    # 进行人脸检测,传入scaleFactor:1.3,minNegihbors:5,分别表示人脸检测过程中每次迭代时图像的压缩率以及
 每个人脸矩形保留近似数目的最小值,返回人脸矩阵数组
    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()

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

def DynamicDetect():
    '''
    打开摄像头,读取帧,检测帧中的人脸,扫描检测到的人脸中的眼睛,对人脸绘制蓝色的矩形框,对人眼绘制绿色的矩形框
    '''
    # 创建一个级联分类器 加载一个 .xml 分类器文件. 它既可以是Haar特征也可以是LBP特征的分类器.
    face_cascade = cv2.CascadeClassifier(haar_front_face_xml)
    eye_cascade = cv2.CascadeClassifier(haar_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 = 'test1.jpg'
    StaticDetect(filename)
    # DynamicDetect()

总结一下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:为目标的最大尺寸

你可能感兴趣的:(笔记)