除了上一篇文章中介绍的 SIFT、SURF 和 ORB 特征描述符之外,方向梯度直方图 (HOG) 也是您可以使用 OpenCV 获得的另一种特征描述符。HOG 是一种强大的特征描述符,在计算机视觉和图像处理中广泛用于目标检测和识别任务。它捕获图像局部区域的梯度方向分布,并提供一种对光照和阴影变化具有不变性的强大表示。
在本文中,您将了解 HOG。具体来说,您将知道
- 什么是 HOG,它与图像的关系如何
- 如何在 OpenCV 中计算它
通过我的书《OpenCV 机器学习》启动您的项目。它提供了带有可用代码的自学教程。
让我们开始吧。

使用 OpenCV 提取梯度直方图
照片来源:Alexas_Fotos。部分权利保留。
概述
这篇文章分为两部分:
- 理解 HOG
- 在 OpenCV 中计算 HOG
- 使用 HOG 进行人脸检测
理解 HOG
HOG 算法背后的概念是在图像的局部区域计算梯度方向的分布。HOG 在一个 **窗口** 上操作,该窗口是图像上固定像素大小的区域。一个窗口被划分为小的空间区域,称为 **块**,一个块进一步被划分为多个 **单元**。HOG 计算每个单元内的梯度幅度和方向,并创建一个梯度方向的直方图。然后,将同一块内的直方图连接起来。
梯度衡量像素的颜色强度与其邻居的比较情况。变化越剧烈,幅度越大。方向则指示最陡梯度所在的方向。通常,这应用于单通道图像(即灰度图),并且每个像素可以有自己的梯度。HOG 收集一个块中的所有梯度并将它们放入直方图。
HOG 中制作直方图的巧妙之处在于,直方图的“桶”(bins)由角度决定,但值在最接近的桶之间进行插值。例如,如果桶的分配值是 0、20、40 等,而梯度在 30 度角处为 10,则会向 20 和 40 的桶添加 5 的值。这样,HOG 就可以有效地捕获图像中目标的纹理和形状。
HOG 在检测具有可区分纹理和图案的物体方面特别有效,使其成为行人检测和其他物体识别任务的热门选择。凭借其捕获梯度方向分布的能力,HOG 提供了一种对光照条件和阴影变化具有不变性的稳健表示。
在 OpenCV 中计算 HOG
OpenCV 提供了一种直接计算 HOG 描述符的方法,使开发人员和研究人员可以轻松使用。让我们通过一个基本示例来看看如何在 OpenCV 中计算 HOG。
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 30 31 32 33 34 35 36 37 |
import cv2 # 加载图像并转换为灰度图 img = cv2.imread('image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 定义每个块为 4x4 个单元,每个单元 64x64 像素 cell_size = (128, 128) # h x w 像素 block_size = (4, 4) # h x w 单元 win_size = (8, 6) # h x w 单元 nbins = 9 # 方向桶的数量 img_size = img.shape[:2] # h x w 像素 # 创建一个 HOG 对象 hog = cv2.HOGDescriptor( _winSize=(win_size[1] * cell_size[1], win_size[0] * cell_size[0]), _blockSize=(block_size[1] * cell_size[1], block_size[0] * cell_size[0]), _blockStride=(cell_size[1], cell_size[0]), _cellSize=(cell_size[1], cell_size[0]), _nbins=nbins ) n_cells = (img_size[0] // cell_size[0], img_size[1] // cell_size[1]) # 将特征作为 1xN 向量查找,然后重塑为空间层次结构 hog_feats = hog.compute(img) hog_feats = hog_feats.reshape( n_cells[1] - win_size[1] + 1, n_cells[0] - win_size[0] + 1, win_size[1] - block_size[1] + 1, win_size[0] - block_size[0] + 1, block_size[1], block_size[0], nbins) print(hog_feats.shape) |
HOG 一次处理一个窗口的特征。一个窗口中有多个块。一个块中有多个“单元”。请参见下图。

假设整个图像是一个窗口。窗口被划分为单元(绿色网格),几个单元组合成一个块(红色和蓝色框)。一个窗口中有许多重叠的块,但所有块的大小都相同。
每个单元的大小固定。在上面,您在单元中使用的是 64x64 像素。每个块包含相同数量的单元。在上面,您在块中使用的是 4x4 单元。同样,一个窗口中的单元数量也相同;您在上面使用的是 8x6 单元。但是,我们在计算 HOG 时并不是将图像划分为块或窗口。而是:
- 将窗口视为图像上的滑动窗口,其中滑动窗口的步长是单元的大小,即它一次滑过一个单元。
- 我们将窗口划分为固定大小的单元。
- 我们设置第二个与块大小匹配的滑动窗口并扫描该窗口。它一次滑过一个单元。
- 在块内,HOG 从每个单元计算。
返回的 HOG 是整个图像的一个向量。在上面的代码中,您将其重塑以清晰地展示窗口、块、单元和直方图桶的层次结构。例如,hog_feats[i][j]
对应于(在 numpy 切片语法中)的窗口:
1 2 |
img[n_cells[1]*i : n_cells[1]*i+(n_cells[1]*win_size[1]), n_cells[0]*j : n_cells[0]*j+(n_cells[0]*win_size[0])] |
或者,等效地说,左上角带有单元格 (i,j) 的窗口。
滑动窗口是目标检测中的一种常用技术,因为您不能确定某个特定目标正好位于哪个网格单元中。创建更小的单元但更大的窗口是一种比仅看到部分目标更好的方法。但是,有一个限制:大于窗口的目标将被忽略。同样,太小的目标可能会被窗口中的其他元素压倒。
通常,您会将 HOG 与一些下游任务相关联,例如对 HOG 特征运行 SVM 分类器以进行目标检测。在这种情况下,您可能希望将 HOG 输出重塑为整个块的向量,而不是像上面那样按单元的层次结构。
使用 HOG 进行人脸检测
上面的代码中的特征提取技术如果您想获取原始特征向量用于其他目的,会很有用。但对于一些常见任务,OpenCV 提供了预先训练好的机器学习模型,您可以轻松使用。
让我们以以下 URL 中的照片为例(将其保存为 people.jpg
)

使用一张照片作为示例,通过 HOG 检测行人。
照片来源:Chris Dickens。部分权利保留。
这是一张行人过马路的图片。OpenCV 有一个 HOG 中的“行人检测器”,它是在 64x128 像素的窗口大小上训练的。用它来检测照片中的行人非常简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
import cv2 # 加载图像并将其转换为灰度图 img = cv2.imread('people.jpg') hog = cv2.HOGDescriptor() hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) # 检测图像中的行人 locations, confidence = hog.detectMultiScale(img) # 在检测到的行人周围绘制矩形 for (x, y, w, h) in locations: cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 5) # 显示带有检测到行人的图像 cv2.imshow('People', img) cv2.waitKey(0) cv2.destroyAllWindows() |
在上面的代码中,您创建了一个 HOG 描述符,其参数来自 cv2.HOGDescriptor_getDefaultPeopleDetector()
,它将初始化一个 SVM 分类器来检测特定目标,在本例中是行人。
您通过 hog.detectMultiScale(img)
在图像上调用描述符并运行 SVM,该函数返回每个检测到的目标的 **边界框**。虽然窗口大小固定,但此检测函数会以多种比例调整图像大小以找到最佳检测结果。即便如此,返回的边界框也不是紧密的。上面的代码还通过在图像上标记边界框来注释检测到的行人。您可以使用检测器报告的置信度分数进一步过滤结果。某些过滤算法,例如非极大值抑制,可能适用但在此不作讨论。以下是输出。

使用 OpenCV 中的 HOG 进行行人检测产生的边界框。
您可以看到,只有当全身可见时,这些检测器才能找到行人。输出存在误报(检测到非行人)和漏报(未检测到行人)。在人群场景中使用它来计数所有行人将是一个挑战。但这是一个很好的起点,可以了解使用 OpenCV 可以多么轻松地完成某些任务。
不幸的是,OpenCV 本身并不提供除行人之外的任何检测器。但是,您可以使用 HOG 作为特征向量来训练自己的 SVM 或其他模型。提供机器学习模型是从图像中提取特征向量的关键点。
想开始学习 OpenCV 机器学习吗?
立即参加我的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
书籍
- 使用 Python 精通 OpenCV 4, 2019.
网站
- OpenCV,https://opencv.ac.cn/
- StackOverflow:OpenCV HOG 特征解释:https://stackoverflow.com/questions/44972099/opencv-hog-features-explanation
总结
在本教程中,您学习了如何在 OpenCV 中使用 HOG 基于滑动窗口提取特征向量。这是一种寻找有助于目标检测的特征的有效方法。
具体来说,你学到了:
- 如何从图像中提取 HOG 特征
- 如何使用 OpenCV 内置的 HOG 行人检测器
如果您有任何疑问,请在下方留言。
暂无评论。