上篇文章《 机器视觉实战 2: 基于 Haar 特征的目标检测 》中介绍了如何使用 Haar 特征进行目标检测, 本文介绍另外一种目标检测算法: 基于 HOG 特征的目标检测. 该算法是在 Dalal 和 Triggs 于 2005 年发表的论文 Histogram of Oriented Gradients for Human Detection 中提出的, 他们当时正在研究行人检测. HOG 特征和 Haar 特征类似, 都是一种提取特征的算法, 其原理都是选择一个窗口, 然后使用这个窗口去滑过图片的所有区域 (如下图), 每滑动一次就会产生一个特征值, 相比于 Haar,HOG 的特征值计算更加复杂一些, 要进行投影, 计算梯度等操作, 细节参见 Wikipedia HOG .
注: 图片来自 这里 .
提取出特征之后, 就可以使用一些分类算法进行模型训练了. 当时论文作者使用线性 SVM 进行了模型的训练, 所以现在 HOG 特征也都基本是和 SVM 一起使用的 (记得以前有统计称普通机器学习算法中最受欢迎的就是 SVM 和随机森林了). 完整的流程如下 ( 图片来自 HOG 的原始论文 ):
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" 获取).
代码效果如下:
这里对检测函数 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 处理. 这里推荐一篇文章: 非极大值抑制 (Non-Maximum Suppression) https://zhuanlan.zhihu.com/p/37489043 . 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
- Pedestrian Detection OpenCV
来源: http://www.tuicool.com/articles/Z7Vrmya