上篇文章《机器视觉实战2:基于Haar特征的目标检测》中介绍了如何使用Haar特征进行目标检测,本文介绍另外一种目标检测算法:基于HOG特征的目标检测。该算法是在Dalal和Triggs于2005年发表的论文 Histogram of Oriented Gradients for Human Detection 中提出的,他们当时正在研究行人检测。HOG特征和Haar特征类似,都是一种提取特征的算法,其原理都是选择一个窗口,然后使用这个窗口去滑过图片的所有区域(如下图),每滑动一次就会产生一个特征值,相比于Haar,HOG的特征值计算更加复杂一些,要进行投影、计算梯度等操作,细节参见 Wikipedia HOG

sliding-window

注:图片来自这里.

提取出特征之后,就可以使用一些分类算法进行模型训练了。当时论文作者使用线性SVM进行了模型的训练,所以现在HOG特征也都基本是和SVM一起使用的(记得以前有统计称普通机器学习算法中最受欢迎的就是SVM和随机森林了)。完整的流程如下(图片来自HOG的原始论文):

hog-svm

OpenCV也支持基于HOG特征的目标检测,并且预先训练了一些模型,下面我们通过一个例子进行介绍:

import cv2

// 初始化HOG及SVM分类器
hog = cv2.HOGDescriptor()
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())
vs = cv2.VideoCapture("/Users/allan/Downloads/TownCentreXVID.avi")
threshold = 0.7

while True:
    grabbed, frame = vs.read()
    if grabbed:
        frame = cv2.resize(frame, (1280, 720))
        gray_frame = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY)

        rects, weights = hog.detectMultiScale(gray_frame)
        for i, (x, y, w, h) in enumerate(rects):
            if weights[i] < 0.7:
                continue
            else:
                cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

        cv2.imshow("frame", frame)

    k = cv2.waitKey(1) & 0xFF
    if k == ord("q"):
        break

vs.release()
cv2.destroyAllWindows()

代码整体逻辑比较简单,和上篇文章代码非常相似。刚开始初始化HOG Descriptor,并设置SVM检测器为默认的行人检测器。然后从视频读取一帧帧的图片进行处理(文中的测试视频可在公众号回复"机器视觉实战3"获取)。

代码效果如下:

result

这里对检测函数detectMultiScale的返回值稍作说明。我们知道分类算法的结果一般返回的是label,也就是告诉你目标属于哪个类别。而检测类算法要更进一步,不仅要解决图片中有没有目标出现,如果有,还要给出在哪里。所以不论是上节的Haar Cascades,还是这节的HOG,检测函数的返回值都很相似,HOG返回的信息更多,我们以HOG为例介绍。HOG返回了两个列表:rects和weights。检测到多少个目标,列表中就会有多少个值,即列表的大小回答了图片中有没有目标的问题。rects中的每个值是包含四个元素的元组,比如(952, 3, 77, 82),这四个值限定了图片中一个矩形,前两个值是矩形的一个顶点的坐标,后面两个值则是矩形的宽和高。而这个矩形就是检测出来的目标的位置,这些从代码中的cv2.rectangle也能看出来。相比于Haar,HOG还多返回了一个weights列表,这个列表的行和rects是一致的,它指的是识别出来的目标的权重,可以理解为可信度,DNN模型里面一般称为confidence。

对于目标检测来说,还有一个非常重要的知识点,就是NMS(Non Maximum Suppression),一般翻译为非极大值抑制。我们进行检测的时候,是用一个个滑框去获取特征值的,所以会产生大量的重复区域,效果就是最终返回的矩形有很多会产生重复。而NMS就是用来消除这些局部区域的极大值,最终获得最大值,从而消除重复,下面是一张效果图:

NMS

左侧是没有经过NMS处理的,右侧是经过NMS处理。这里推荐一篇文章:非极大值抑制(Non-Maximum Suppression). NMS的算法原理相对简单,需要的时候可以自己实现,也可以使用一些已有实现。这里推荐一个Python的:

# pip install imutils
from imutils.object_detection import non_max_suppression

rects = np.array([[x, y, x + w, y + h] for (x, y, w, h) in rects])
pick = non_max_suppression(rects, probs=None, overlapThresh=0.65)

Haar Cascades和Hog特征检测是DNN没有出来之前主要的目标检测算法,即使现在有很多基于DNN的模型,Haar Cascades和Hog在工业界依旧有很多应用场景。

References