【翻译】HOG, Histogram of Oriented Gradients / 方向梯度直方图 介绍
本文翻译自 SATYA MALLICK 的 "Histogram of Oriented Gradients"
原文链接: https://www.learnopencv.com/histogram-of-oriented-gradients/
翻译:coneypo
在这篇文章中,我们将会学习 HOG (Histogram of Oriented Gradients,方向梯度直方图)特征描述子 的详细内容。
我们将学习 HOG 算法是如何实现的,以及在 OpenCv / MATLAB 或者其他工具里面如何计算特征子。
这篇文章是我正在写的,关于 Image Recognition / 图像识别 和 Object Detection / 目标检测 系列文章中的一部分。
很多事情看起来困难又神秘,但是你一旦花时间去了解,揭开神秘面纱,你就会发现神奇之处。
如果你是一个初学者,觉得计算机视觉又难又神秘,请记住一句话:
问:如何吃掉一个大象?
答:一口一口吃
什么是 Feature Desciptor / 特征描述子
Feature Desciptor / 特征描述子 从图像中提取有用信息,剔除无关信息;
典型的,特征描述子从将一张 宽度 * 高度 * 3 ( 通道数 ) 大小的图像,提取出长度为 n 的 Feature Vector / 特征向量 或者 Feature Array / 特征矩阵;
比如 HOG 特征描述子会从一张 64 * 128 * 3 的图像中提取出长度为 3780 的特征向量;
请记住, HOG 的特征描述子也可以计算其他尺寸,但是这篇文章中,我使用上述尺寸,以便你能够轻松的理解概念。
这些概念听起来都挺不错,但是哪些是“有用的信息”,有些又是“无用的信息"?
定义“有用的信息”,我们需要知道有用的信息用来干什么的;
很明显,通过特征向量用来浏览图像是没用的,但是在图像识别或者目标检测中,特征向量会变得很有用;
在一些图像分类算法中比如 SVM,Support Vector Machine,支持向量机 中,用特征向量进行分类会达到很好的结果。
但是在分类任务中,哪些特征是有用的呢?
我们借助下面的例子来讨论,比如现在我们想通过一个目标检测器,可以检测衬衫和大衣的纽扣;
一个纽扣是一个圆形(图片中也有可能看起来像是椭圆),一般来说有几个孔,用于缝到衣服上面;
你可以在纽扣的图像上使用一个 Edge detector / 边缘检测器,可以轻松通过检测边缘来辨别它是不是一个纽扣;
这个例子中,边缘信息是“有用的”而颜色信息是 ”无用的“;
除此之外,特征也需要有足够特殊的地方。比如一个好的特征,应该能够让你辨别出纽扣和其他圆形的物体,比如硬币和汽车轮胎。
如何计算 Histogram of Oriented Gradients / 方向梯度直方图?
在这一节,我们会继续深入学习如何计算 HOG 特征描述子。
步骤1:预加工
之前提到用于行人检测的 HOG 特征描述子,是基于 64×128 大小的图像。当然,图像可能是任何尺寸的;
对于这些之后用于分析的图像,唯一需要进行的处理是调整纵横比图像大小;
在我们的例子中,需要调整纵横比为1:2,比如图像可以被调整为 100×200, 128×256, 或者 1000×2000,但是不能是 101×205;
原始图像大小是 720×475,我们截切出来 100×200 大小图像用来计算 HOG 特征描述子,然后重新调整大小到 64×128;
现在我们就做完了计算 HOG 特征描述子准备工作。
Dalal 和 Triggs 的论文也提到了 Gamma Correction / 伽马校正 作为预处理步骤,但性能提升很小,因此我们选择预处理中跳过这一步。
步骤 2 :计算梯度图像
为了计算 HOG 特征描述子,我们第一步需要计算水平和垂直方向的梯度。我们通过下面的 Kernel / 核 来处理图像,很容易计算出梯度的直方图。
我们可以使用核大小为 1 的 OpenCv 的 Sobel 算子:
// C++ gradient calculation.
// Read image
Mat img = imread("bolt.png");
img.convertTo(img, CV_32F, /255.0);
// Calculate gradients gx, gy
Mat gx, gy;
Sobel(img, gx, CV_32F, , , );
Sobel(img, gy, CV_32F, , , );
1 # Python gradient calculation
2
3 # Read image
4 im = cv2.imread('bolt.png')
5 im = np.float32(im) / 255.0
6
7 # Calculate gradient
8 gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
9 gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)
接下来,我们通过下面的公式来计算梯度的幅值和方向:
在 OpenCv 中,我们可以使用 cartToPolar 函数来计算上述数值:
// C++ Calculate gradient magnitude and direction (in degrees)
Mat mag, angle;
cartToPolar(gx, gy, mag, angle, );
The same code in python looks like this.
# Python Calculate gradient magnitude and direction ( in degrees )
mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)
下图展示了梯度计算结果:
左边:x 方向梯度的绝对值
中间:y 方向梯度的绝对值
右边:梯度的幅值
注意 x 方向的梯度代表垂直方向的变化趋势,而 y 方向代表的是水平方向的变化;
如果图像像素变换迅速的话,可以在梯度图中明显看出,而当区域内变化缓慢时,不会出现梯度幅值;
梯度图像去除了很多不必要的信息,保留了关键信息。换句话说,你可以看着梯度图,然后轻松的辨别出来照片里的人;
每一个像素点,都有一个 Magnitude / 幅值 和 Direction / 方向;
对于彩色的图像,三种通道的梯度都会被评估计算,取的是最大的梯度。
步骤 3:在 8*8 cells / 网格 中计算梯度直方图
这一步,图像会被分割成 8*8 大小的单独 cells / 小格子,然后对于每个 8*8 的小格子,分别计算梯度直方图;
我们先来了解下为什么要把图像分割为 8*8 的小格子;
有一个重要的原因是使用特征描述子来描述一幅 image / 图像 的一个 patch / 子图像 的话,网格分割会提供了一个 compact / 紧凑 的表示方式;
一个 8*8 的子图像包含 8*8*3 = 192 个像素值。每个像素梯度有两个值( Magnitude / 幅值 和 Direction / 方向 ),所以每个子图像会有 8*8*2=128 个数值;
在这节结束之前,我们会看到这 128 个数值如何使用 9 位的数组来 存储在 9 位的直方图中。经过压缩处理之后的数据具有更好的 抗噪性。
但是为什么取得是 8*8 的子图像而不是 32*32? 这是根据我们所要检测的目标来决定的;
对于 HOG 行人检测, 从 64*128 的行人图像中提取出的 8*8 子图像,已经足够用来提取出有用的信息(比如脸部,头的顶部等等)
直方图有必要是 9 位的向量,与 0,20,40,60… 160 度对应;
让我们来看看在一个 8*8 的子图像中,梯度是什么样的:
中间:用箭头来代表颜色和梯度的变化;
右边:用数字来代表子图像中的梯度;
如果你是一个计算机视觉的初学者,中间的图像会很有帮助很形象;
通过箭头来表示图像中梯度的变化,箭头的方向表示着像素强度变化的方向,幅值表示变化的缓慢;
通过右边的图,我们可以看到 8*8 子图像中提取出来的代表梯度的数值,这些角度从 0~180 度而不是 0~360 度,这些被称之为 unsigned gradients / 无符号梯度,因为一个梯度和它取负之后得到的是同样的数值;
换句话说,一个梯度箭头旋转180度之后被认为是一样的;
但是为什么我们不使用 0-360 度呢?经验告诉我们使用无符号的梯度,比使用有符号的梯度在行人检测中性能更好。不过一些 HOG 的实现中也可以允许你使用有符号的梯度。
接下来就是为这些 8*8 的子图像,建立一个梯度直方图。直方图有 9 位,来与 0, 20, 40…160 度相对应;
下面的图像向我们展示了操作过程,我们关注从 8*8 子图像中提取出来的幅值和方向;
* 根据梯度的方向来选择使用填充到哪一位,然后根据梯度的幅值来填充数值;
我们先来看看 蓝圈的数值,角度为 80,幅值为2,所以在直方图第五位加 2;
再来看看 红圈的数值,角度为 10,幅值为 4,角度 10 的话在 0 和 20 之间,所以将它的幅值 4 被一分为 2 ,分别在直方图的 "0 位" 和 "20 位" 里面放 2 。
还需要注意的一点是,如果 角度比 160 大,在 160 和 180 之间。我们知道在这里 0 度和 180 度一样,所以下面这个例子,角度 165 度被分到了 0 度和 160 度 两个位里面。
8*8 子图像提取出来的数值,经过处理,可以得到一个 9 位的直方图,对于上面的子图像,我们可以得到如下的直方图:
在我们的表示中,y 轴默认为 0 度。你可以从直方图中看到,在 0~180 度之间有很多分布,这也表明子图像中的梯度方向要么朝上要么朝下。
步骤 4:16*16 块归一化
在之前的步骤中,我们根据图像的梯度制作了直方图。但是对于亮度不同的图像,梯度很敏感。
如果你让所有像素点的数值除 2 来让图像变暗,梯度幅值也会相应的减半,因此直方图也会对应着减半。
理想情况下,我们希望我们的描述器是不随着亮度变化而变化的,换句话说,我们想要归一化直方图,所以让它不受亮度影响;
在我说明直方图如何被归一化之前,让我们来看看,一个长度为 3 的向量是如何被归一化的;
比如我们有个 RGB 颜色向量为 [ 128, 64, 32 ],计算出长度为:
这也被称为这个向量的 L2 范数;
对向量的每个元素除以 146.64,得到归一化之后的向量 [ 0.87, 0.43, 0.22 ]。
现在考虑另一个向量,它的数值是之前向量的两倍,2 x [ 128, 64, 32 ] = [ 256, 128, 64 ];
通过同样的计算方式,你可以得到同样的归一化向量 [ 0.87, 0.43, 0.22 ],这就可以解决之前提到的亮度的影响问题。
现在我们知道了如何去归一化向量,也许你会认为,归一化 9*1 的直方图和上面介绍的 3*1 的向量归一化一样。这想法并没有错,但是更好的方式是用一个更大尺寸 16*16 的块去归一化;
也就是 36*1 的直方图可以看成 4 个 9*1 的直方图构成,然后窗口以 8 像素移动(见上图),计算出归一化的 36*1 大小的向量然后重复这个过程遍历图像。
可视化 HOG
通过在 8*8 子图像里面进行 9*1 归一化的直方图,我们可以可视化子图像的 HOG 的描述子。
在下图中你会发现,直方图的 Dominant direction / 主要方向 捕获了这个人的外形,尤其在躯干和腿。
不幸的是,在 OpenCv 中进行 HOG 的特征描述子的可视化比较困难。
# 英文版权 @ SATYA MALLICK
# 翻译中文版权 @ coneypo
# 转载请注明出处
【翻译】HOG, Histogram of Oriented Gradients / 方向梯度直方图 介绍的更多相关文章
- 【笔记】HOG (Histogram of Oriented Gradients, 方向梯度直方图)的开源实现
wiki上的介绍 OpenCV的实现 cv::HOGDescriptor Struct Reference opencv cv::HOGDescriptor 的调用例子 HOGDescriptor h ...
- Histogram of Oriented Gridients(HOG) 方向梯度直方图
Histogram of Oriented Gridients,缩写为HOG,是目前计算机视觉.模式识别领域很常用的一种描述图像局部纹理的特征.这个特征名字起的也很直白,就是说先计算图片某一区域中不同 ...
- 【计算机视觉】Histogram of Oriented Gridients(HOG) 方向梯度直方图
Histogram of Oriented Gridients(HOG) 方向梯度直方图 Histogram of Oriented Gridients,缩写为HOG,是目前计算机视觉.模式识别领域很 ...
- SIFT(Scale-invariant feature transform) & HOG(histogram of oriented gradients)
SIFT :scale invariant feature transform HOG:histogram of oriented gradients 这两种方法都是基于图像中梯度的方向直方图的特征提 ...
- HOG(方向梯度直方图)
结合这周看的论文,我对这周研究的Histogram of oriented gradients(HOG)谈谈自己的理解: HOG descriptors 是应用在计算机视觉和图像处理领域,用于目标检測 ...
- (转)梯度方向直方图HOG(Histograms of Oriented Gradients )
HOG(Histograms of Oriented Gradients )梯度方向直方图 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视 ...
- 机器视觉 Histogram of oriented gradients
Histogram of oriented gradients 简称 HoG, 是计算机视觉和图像处理领域一种非常重要的特征,被广泛地应用于物体检测,人脸检测,人脸表情检测等. HoG 最早是在200 ...
- 特征描述子(feature descriptor) —— HOG(方向梯度直方图)
HOG(Histogram of Oriented Gradients),描述的是图像的局部特征,其命名也暗示了其计算方法,先计算图像中某一区域不同方向上梯度的值,然后累积计算频次,得到直方图,该直方 ...
- (转)matlab练习程序(HOG方向梯度直方图)
matlab练习程序(HOG方向梯度直方图)http://www.cnblogs.com/tiandsp/archive/2013/05/24/3097503.html HOG(Histogram o ...
随机推荐
- Java设计模式16:常用设计模式之观察者模式(行为型模式)
1. Java之观察者模式(Observer Pattern) (1)概述: 生活中我们在使用新闻app,当我们对某一栏比较感兴趣,我们往往会订阅这栏新闻,比如我对军事栏感兴趣,我就会订阅军事栏的新闻 ...
- Spring Boot中使用EhCache实现缓存支持
SpringBoot提供数据缓存功能的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存.,相信非常多人已经用过cache了.因为数据库的IO瓶颈.一般情况下我们都会引入非常多的缓存策略, ...
- virtualbox+vagrant学习-2(command cli)-6-vagrant init命令
Init——创建Vagrantfile文件 格式: vagrant init [options] [name [url]] 通过创建初始的Vagrantfile文件(如果不存在的话),将当前目录初始化 ...
- mongodb的学习-6-命令简单使用
1.创建数据库 use DATABASE_NAME 举例说明: > use another //创建了数据库another switched to db another > db anot ...
- 平台+插件软件设计思想及基于COM的原型实现
引言:我们已经习惯于一个人独立进行软件开发,每个人都使用自己的风格进行程序设计,但随着工程项目变大或者是对时间要求比较紧时,就需要几个人,十几个人,甚至是上百个人协作进行软件开发与设计,这时一个比较棘 ...
- maven错误The JAVA_HOME environment variable is not defined correctly
晚上,当我准备将好的spring boot通过mvn clean package 打包成jar文件上传到linux服务器时,却在打包过程中出现了错误: C:\>mvn -version The ...
- 非const引用参数传入不同类型编译不过的理解(拒绝将临时对象绑定为非const的引用的形参是有道理的)
int f (int & I) { cout<<I<<std::endl; } void main() { long L; f(L); // 编译不过 f((int)L ...
- transform CSS3 2D知识点汇总
transform转换属性的5个值: 1. translate(x值,y值) 移动效果. 2.rotate(45deg) 旋转效果. 3.scale(x轴倍数,y轴倍数) 缩放效果. 4.ske ...
- mac下安装phalcon
PHP版本:7.1.16 1. 安装 brew tap tigerstrikemedia/homebrew-phalconphp brew install php71-phalcon 2.配置php. ...
- C 没得写的水文
引言 - 没得写 最近工作上需要处理事情很多(接手, 维稳, 危机), 还有深入读书计划也提上了日程. 为了每月水经验, 这里带大家写个 C 的多值返回吧 : ) #include <stdio ...