目标识别的众多方法中,有基于图案结构的人脸识别、基于特征脸的人脸识别、实时人脸识别、已知物体的识别、基于特征的识别、基于区域的识别、同时识别和分割、位置识别、使用上下文信息。
Haar特征是一种用于实现实时人脸跟踪的特征。
对给定的图像,特征可能会因区域大小而有所不同,区域大小也可被称为窗口大小(window sizes)。即使窗口大小不一样,仅在尺度上不同的两幅图像也应该有相似的特征。因此,能为不同大小的窗口生成特征非常有用。这些特征集合称为级联。
Haar级联具有尺度不变性,不具有旋转不变性。
如图1(a)为一部分Haar特征,图1(b)使用该特征计算覆盖范围的特征值,不同的矩形对应特定的权重,计算黑色范围的像素和与白色范围像素和之和,形如
f e a t u r e V a l u e = w e i g h t b l a c k ∑ P i x e l ∈ b l a c k P i x e l + w e i g h t w h i t e ∑ P i x e l ∈ w h i t e P i x e l featureValue = weight_{black}\sum_{Pixel\in black} Pixel + weight_{white}\sum_{Pixel\in white} Pixel featureValue=weightblackPixel∈black∑Pixel+weightwhitePixel∈white∑Pixel人脸区域与非人脸区域的特征值是不一样的,使用Haar特征可以把人脸特征量化。而通过机器学习的AdaBoost算法,把多个Haar特征组合,可以得到一个区分度更大的特征值,从而实现人脸检测。
人脸识别的方法都有类似的过程,即都使用了分好类的训练数据集(人脸数据库,每个人都有很多样本)来进行训练,对图像或视频中检测到的人脸进行分析,并从两方面来确定:是否识别到目标;目标真正被识别到的置信度的度量,这也称为置信度评分。
Eigenfaces 是通过 PCA 来处理的。PCA 是计算机视觉中提到最多的数学概念。PCA 的本质是识别某个训练集上(比如人脸数据库)的主成分,并计算出训练集(图像或帧中检测到的人脸)相对于数据库的发散程度,并输出一个值。该值越小,表明人脸数据库和检测到的人脸之间的差别就越小;0值表示完全匹配。
Fisherfaces 是从 PCA 衍生并发展起来的概念,它采用更复杂的逻辑。尽管计算更加密集,但比 Eigenfaces 更容易得到准确的效果。
LBPH 粗略地(在非常高的层次上)将检测到的人脸分成小单元,并将其与模型中的对应单元进行比较,对每个区域的匹配值产生一个直方图。由于这种方法的灵活性,LBPH 是唯一允许模型样本人脸和检测到的人脸在形状、大小上可以不同的人脸识别算法。
梯度直方图(Histogram of Oriented Gradient, HOG)是一个描述子,它基于梯度来计算直方图。HOG 所得到的特征描述能够为特征匹配和目标识别提供非常重要的信息。
下图是一个卡车图像:
下图为 HOG 对卡车图像所提取的特征:
HOG 将图像分成多个小单元,每个单元都包含了视觉表示,该视觉表示是按八个方向(N, NW, W, SW, S, SE, E, NE)所计算的梯度。每个单元的八个值就为直方图,因此,每个单元都会有唯一的标识。如果你想象一下,会在大脑中“浮现”出下面这幅图:
将直方图外推成描述子是相当复杂的过程。首先计算每个单元的局部直方图,这些单元会合成较大的区域,也称为块。块可以由任意多个单元组成,但 Dalal 和 Triggs(HOG的发明人)发现当进行人检测时,一个块包含 2 × 2 的单元时可以得到最好的效果。不同块之间可以相互重叠。从而得到图像特征。
图像的多尺度表示(或图像金字塔)有助于解决不同尺度下的目标检测问题,可以采用任意尺度的参数来调整(缩小)图像的大小、平滑图像以得到图像金字塔,下图有助于理解这个概念:
一旦建立图像金字塔,为了检测目标,可采用滑动窗口来搜索图像。最后一步就是将检测窗口中所有重叠的块进行HOG特征的收集,并将它们结合成最终的特征向量供 SVM 分类使用,计算各个窗口的置信度评分,得到最高响应的窗口。
在 OpenCV3 源代码的副本中会有一个文件夹 data/haarcascades。该文件夹包含了所有 OpenCV 的人脸检测的 XML 文件,这些文件可用于检测静止图像、视频和摄像头所得到图像中的人脸。这些文件需要正面、直立的人脸图像。
import cv2
img = cv2.imread('img1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
'''
人脸检测
'''
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') # CascadeClassifier对象
faces = face_cascade.detectMultiScale(gray, 1.3, 2) # 传递参数是 scaleFactor 和 minNeighbors,它们分别表示人脸检测过程中每次迭代时图像的压缩率以及每个人脸矩形保留近邻数目的最小值。返回值为人脸矩形数组,数组元素形式为 (x,y,w,h)
for (x,y,w,h) in faces:
img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),2) # 绘制蓝色矩形框
'''
眼睛检测
'''
left_eye_cascade = cv2.CascadeClassifier('haarcascade_lefteye_2splits.xml')
right_eye_cascade = cv2.CascadeClassifier('haarcascade_righteye_2splits.xml')
left_eyes = left_eye_cascade.detectMultiScale(gray, 2, 1)
right_eyes = right_eye_cascade.detectMultiScale(gray, 2, 1)
for (x,y,w,h) in left_eyes:
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,255),2) # 绘制黄色矩形框
for (x,y,w,h) in right_eyes:
img = cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),2) # 绘制青色矩形框
'''
嘴巴检测
'''
smile_cascade = cv2.CascadeClassifier('haarcascade_smile.xml')
smiles = smile_cascade.detectMultiScale(gray, 1.3, 9)
for (x,y,w,h) in smiles:
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,0,255),2) # 绘制红色矩形框
cv2.imwrite('rectangle.jpg', img)
检测人
import cv2
import numpy as np
# o, i 为矩形,形式为 (x,y,w,h)
# 该函数用于检测 矩形i 是否完全包含 矩形o,是返回true
def is_inside(o, i):
ox, oy, ow, oh = o
ix, iy, iw, ih = i
return ox > ix and oy > iy and ox + ow < ix + iw and oy + oh < iy +ih
# 该函数用于绘制最后检测到的矩形
def draw_person(image, person):
x, y, w, h = person
cv2.rectangle(image, (x,y), (x + w, y + h), (0, 255, 255), 2)
img = cv2.imread('img2.jpg')
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
# 返回值found为行人矩形数组,数组元素形式为 (x,y,w,h)
found, w = hog.detectMultiScale(img)
found_filtered = []
for ri, r in enumerate(found):
for qi, q in enumerate(found):
if ri != qi and is_inside(r, q):
# 若is_inside(r, q)为TRUE,表示r完全包含在q中,这说明检测出现了错误
break
else:
found_filtered.append(r)
for person in found_filtered:
draw_person(img, person)
cv2.imwrite('people.jpg', img)
以上全部内容参考书籍如下:
Richard Szeliski《计算机视觉 - 算法与应用》
Joe Minichino、Joseph Howse《OpenCV 3计算机视觉Python语言实现(原书第2版)》