计算机视觉特征点检测(3) —— Haar特征描述算子


计算机视觉特征点检测(3) —— Haar特征描述算子

  • 理论介绍
    • Haar分类器训练的五大步骤
    • Harr-like 特征
    • Haar-like特征的计算——积分图
    • 计算Haar特征值
    • Haar特征值归一化
    • Adaboost级联分类器
  • OpenCV实现

理论介绍

Haar分类器训练的五大步骤

  1. 准备人脸、非人脸样本集
  2. 计算特征值和积分图
  3. 筛选出T个优秀的特征值(即最优弱分类器)
  4. 把这T个最优弱分类器传给AdaBoost进行训练
  5. 级联,也就是强分类器的强强联手
    以20*20窗口为例,有78460的特征数量,筛选出T个优秀的特征值(最优弱分类器),然后把这T个最优弱分类器传给AdaBoost进行训练得到一个强分类器,最后将强分类器进行级联。

Harr-like 特征

Haar(哈尔)特征分为三类:边缘特征、线性特征、中心特征和对角线特征,组合成特征模板。如下图:
在这里插入图片描述
对于图中A,B,D这类特征,特征数值计算公式为:

v=+v=\sum白 + \sum黑

v=∑白+∑黑,对于C,特征数值为:

v=2?+v=2*\sum白 + \sum黑

v=2?∑白+∑黑。通过改变特征模板的大小和位置,可在图像子窗口中穷举出大量的特征。上图的特征模板称为“特征原型”,特征原型在图像子窗口中扩展(平移伸缩)得到的特征称为“矩形特征”,矩阵特征的值称为“特征值”。
在这里插入图片描述
矩形特征可位于图像任意位置,大小也可以任意改变,所以矩形特征值是矩形模板类别、矩形位置和矩形大小这三个因素的函数。故类别、大小和位置的变化,使得很小的检测窗口含有非常多的矩形特征,如:在24*24像素大小的检测窗口内矩形特征数量可以达到16万个。

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

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

(i,j)(i, j)

(i,j)处的值

ii(i,j)ii(i,j)

ii(i,j)是原图像(i,j)左上角方向所有像素

f(k,l)f(k,l)

f(k,l)的和:

ii(i,j)=ki,ljf(k,l)ii(i,j)=ki,ljf(k,l)
ii(i,j) = \sum_{k\leq i, l\leq j} f(k,l)ii(i,j)=\sum_{k\leq i, l\leq j} f(k,l)

ii(i,j)=k≤i,l≤j∑?f(k,l)ii(i,j)=k≤i,l≤j∑?f(k,l)
积分图构建算法:

s(i,j)s(i,j)

s(i,j)表示行方向的累加和,初始化

s(i,?1)=0s(i,-1)=0

s(i,?1)=0;

ii(i,j)ii(i,j)

ii(i,j)表示一个积分图像,初始化

ii(?1,j)=0ii(-1,j)=0

ii(?1,j)=0;

s(i,j)=s(i,j?1)+f(i,j)ii(i,j)=ii(i?1,j)+s(i,j)
s(i,j) = s(i,j-1)+f(i,j) \\
ii(i,j) = ii(i-1,j) +s(i,j)

s(i,j)=s(i,j?1)+f(i,j)ii(i,j)=ii(i?1,j)+s(i,j)

计算Haar特征值

在这里插入图片描述
如上图:
区域A的像素值:

ii(5)+ii(1)?ii(2)?ii(4)
ii(5) + ii(1) - ii(2) - ii(4)

ii(5)+ii(1)?ii(2)?ii(4)
区域B的像素值:

ii(6)+ii(2)?ii(5)?ii(3)
ii(6) + ii(2) - ii(5) - ii(3)

ii(6)+ii(2)?ii(5)?ii(3)
所以,该矩阵特征的特征值为区域A的像素值减去区域B的像素值:

ii(5)+ii(1)?ii(2)?ii(4)?[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(1)?ii(2)?ii(4)?[ii(6)+ii(2)?ii(5)?ii(3)]

Haar特征值归一化

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

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

sum=∑i(x,y)sqsum?=∑i2(x,y)
计算平均值:

mean=sumw?hsqmean=sqsumw?h
mean = \frac{sum}{w*h} \\
sq_{mean} = \frac{sq_{sum}}{w*h}

mean=w?hsum?sqmean?=w?hsqsum??
计算归一化因子:

varNormFactor=sqmean?mean2
varNormFactor = \sqrt{sq_{mean} - mean^{2}}

varNormFactor=sqmean??mean2?
归一化特征值:

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

normValue=varNormFactorfeatureValue?
之后使用归一化的特征值normValue与阈值对比。

Adaboost级联分类器

级联分类模型是树状结构:
在这里插入图片描述
其中每个stage都代表一级强分类器。当检测窗口通过所有的强分类器时才被认为是正样本,否则拒绝。

OpenCV实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import cv2
import numpy as np
from matplotlib import pyplot as plt
haar_front_face_xml = 'data/haarcascade_frontalface_default.xml'

# 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,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()

if __name__ == '__main__':
    filename = 'picture/face1.png'
    StaticDetect(filename)

原图:
在这里插入图片描述
处理后的图像:
在这里插入图片描述