特征描述子(Feature Descriptor)

特征描述子就是图像的表示,抽取了有用的信息,丢掉了不相关的信息。通常特征描述子会把一个w*h*3(宽高3,3个channel)的图像转换成一个长度为n的向量/矩阵。比如一副64*128*3的图像,经过转换后输出的图像向量长度可以是3780。

什么样子的特征是有用的呢?假设我们想要预测一张图片里面衣服上面的扣子,扣子通常是圆的,而且上面有几个洞,那你就可以用边缘检测(edge detector),把图片变成只有边缘的图像,然后就可以很容易的分辨了,那么对于这张图边缘信息就是有用的,颜色信息就是没有用的。而且好的特征应该能够区分纽扣和其它圆形的东西的区别。

方向梯度直方图(HOG)中,梯度的方向分布被用作特征。沿着一张图片X和Y轴的方向上的梯度是很有用的,因为在边缘和角点的梯度值是很大的,我们知道边缘和角点包含了很多物体的形状信息。(HOG特征描述子可以不局限于一个长度,也可以用很多其他的长度,这里只记录一种计算方法。)

怎么计算方向梯度直方图呢?

我们会先用图像的一个patch来解释。

第一步:预处理

Patch可以是任意的尺寸,但是有一个固定的比例,比如当patch长宽比1:2,那patch大小可以是100*200, 128*256或者1000*2000,但不可以是101*205。

这里有张图是720*475的,我们选100*200大小的patch来计算HOG特征,把这个patch从图片里面抠出来,然后再把大小调整成64*128。

第二步:计算梯度图像

首先我们计算水平和垂直方向的梯度,再来计算梯度的直方图。可以用下面的两个kernel来计算,也可以直接用OpenCV里面的kernel大小为1的Sobel算子来计算。

horizontal_vertical_gradient_kernel (水平和垂直梯度)

调用OpenCV代码如下:

// C++ gradient calculation.
// Read image
Mat img = imread("bolt.png");
img.convertTo(img, CV_32F, 1/255.0);

// Calculate gradients gx, gy
Mat gx, gy;
Sobel(img, gx, CV_32F, 1, 0, 1);
Sobel(img, gy, CV_32F, 0, 1, 1);

# Python gradient calculation

# Read imageim = cv2.imread('bolt.png')
im = np.float32(im) / 255.0

# Calculate gradient
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)

接着,用下面的公式来计算梯度的幅值g和方向theta:

gradient_direction_formula(梯度方向计算)

可以用OpenCV的cartToPolar函数来计算:

// C++ Calculate gradient magnitude and direction (in degrees)
Mat mag, angle;
cartToPolar(gx, gy, mag, angle, 1);

# Python Calculate gradient magnitude and direction ( in degrees )
mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)

计算得到的gradient图如下:

左边:x轴的梯度绝对值         中间:y轴的梯度绝对值             右边:梯度幅值

从上面的图像中可以看到x轴方向的梯度主要凸显了垂直方向的线条,y轴方向的梯度凸显了水平方向的梯度,梯度幅值凸显了像素值有剧烈变化的地方。(注意:图像的原点是图片的左上角,x轴是水平的,y轴是垂直的)

图像的梯度去掉了很多不必要的信息(比如不变的背景色),加重了轮廓。换句话说,你可以从梯度的图像中轻而易举的发现有个人。在每个像素点,都有一个幅值(magnitude)和方向,对于有颜色的图片,会在3个channel上都计算梯度那么相应的幅值就是3个channel上最大的幅值,角度(方向)是最大幅值所对应的角

第三步:在8*8的网格中计算梯度直方图

在这一步,我们先把整个图像划分为若干个8x8的小单元,称为cell,并计算每个cell的梯度直方图。这个cell的尺寸也可以是其他值,根据具体的特征而定。

为什么我们要把图像分成若干个8x8的小单元?

这是因为对于一整张梯度图,其中的有效特征是非常稀疏的,不但运算量大,而且效果可能还不好。于是我们就使用特征描述符来表示一个更紧凑(compact)的特征。

一个8*8的图像有8*8*3=192个像素值(彩色图有3个channel),每个像素的梯度包括两个值(幅值magnitude和方向direction,magnitude取3个channel中最大值,然后direction取最大magnitude值对应的direction值),因此一个8x8的小单元(cell)就包含了8*8*2=128个值,因为每个像素包括梯度的大小和方向。

现在我们要把这个8x8的小单元用长度为9的数组来表示,这个数组就是梯度直方图。这种表示方法不仅使得特征更加紧凑,而且对单个像素值的变化不敏感,也就是能够抗噪声干扰。

这个patch的大小是64*128,把它分割成若干个8*8的cell,那么一共有(64/8)*(128/8) = 8*16=128个网格,对于64*128的这幅patch来说,8*8的网格已经足够大来表示有趣的特征比如脸,头等等。

直方图是有9个bin的向量,代表的是角度0,20,40,60.....160。

我们先来看看每个8*8的cell的梯度都是什么样子:

中间这个图的箭头是梯度的方向,长度是梯度的大小,可以发现箭头的指向方向是像素强度变化方向,幅值是强度变化的大小。

右边的梯度方向矩阵中可以看到角度是0-180度,不是0-360度,这种被称之为"无符号"梯度("unsigned" gradients),因为一个梯度和它的负数是用同一个数字表示的,也就是说一个梯度的箭头以及它旋转180度之后的箭头方向被认为是一样的。那为什么不用0-360度的表示呢?在事件中发现unsigned gradients比signed gradients在行人检测任务中效果更好。一些HOG的实现中可以让你指定signed gradients。

下一步就是为这些8*8的网格创建直方图,直方图包含了9个bin来对应0,20,40,...160这些角度。

下面这张图解释了这个过程。我们用了上一张图里面的那个网格的梯度幅值和方向。根据方向选择用哪个bin, 根据幅值来确定这个bin的大小。先来看蓝色圆圈圈出来的像素点,它的角度是80,幅值是2,所以它在第五个bin里面加了2,再来看红色的圈圆圈圈出来的像素点,它的角度是10,幅值是4,因为角度10介于0-20度的中间(正好一半),所以把幅值一分为二地放到0和20两个bin里面去。

这里有个细节要注意,如果一个角度大于160度,也就是在160-180度之间,我们知道这里角度0,180度是一样的,所以在下面这个例子里,像素的角度为165度的时候,要把幅值按照比例放到0和160的bin里面去。

把这8*8的cell里面所有的像素点都分别加到这9个bin里面去,就构建了一个9-bin的直方图,上面的网格对应的直方图如下:

可以看到直方图中,0度和160附近有很大的权重,说明了大多数像素的梯度向上或者向下,也就是这个cell是个横向边缘

现在我们就可以用这9个数的梯度直方图来代替原来很大的三维矩阵,即代替了8x8x2个值。

第四步: 16*16块(block)归一化

hog-16x16-block-normalization

在前面的步骤中,我们基于图像的梯度对每个cell创建了一个直方图。

但是图像的梯度对整体光照非常敏感,比如通过将所有像素值除以2来使图像变暗,那么梯度幅值将减小一半,因此直方图中的值也将减小一半。 理想情况下,我们希望我们的特征描述符不会受到光照变化的影响,那么我们就需要将直方图“归一化” 。

在说明如何归一化直方图之前,先看看长度为3的向量是如何归一化的。

假设我们有一个向量 [128,64,32],向量的长度为,这叫做向量的L2范数。将这个向量的每个元素除以146.64就得到了归一化向量 [0.87, 0.43, 0.22]

现在有一个新向量,是第一个向量的2倍 [128x2, 64x2, 32x2],也就是 [256, 128, 64],我们将这个向量进行归一化,你可以看到归一化后的结果与第一个向量归一化后的结果相同。所以,对向量进行归一化可以消除整体光照的影响。

知道了如何归一化,现在来对block的梯度直方图进行归一化(注意不是cell),一个block有4个直方图,将这4个直方图拼接成长度为36的向量,然后对这个向量进行归一化。

因为使用的是滑动窗口,滑动步长为8个像素,所以每滑动一次,就在这个窗口上进行归一化计算得到长度为36的向量,并重复这个过程

第五步:计算HOG特征向量

为了计算这整个patch的特征向量,需要把36*1的向量全部合并组成一个巨大的向量。向量的大小可以这么计算:

  1. 我们有多少个16*16的块?水平7个,垂直15个,总共有7*15=105次移动。

  2. 每个16*16的块代表了36*1的向量。所以把他们放在一起也就是36*105=3780维向量。

这个得到的长度3780的向量就可以作为整个图像的特征描述符。

通常HOG特征描述子是画出8*8网格中9*1归一化的直方图,见下图。你可以发现直方图的主要方向捕捉了这个人的外形,特别是躯干和腿。

为了显示效果更明显,我把cell的尺寸改为(16, 16),对于每一个cell,画出它归一化后的梯度直方图。如下图所示,我们可以很明显的看出一个人的轮廓。

参考:

HOG特征详解

Histogram of Oriented Gradients

方向梯度直方图(Histogram Of Gradient)详解相关推荐

  1. Histogram of Oriented Gridients(HOG) 方向梯度直方图

    from: Histogram of Oriented Gridients(HOG) 方向梯度直方图 Histogram of Oriented Gridients,缩写为HOG,是目前计算机视觉.模 ...

  2. 【计算机视觉】Histogram of Oriented Gridients(HOG) 方向梯度直方图

    Histogram of Oriented Gridients(HOG) 方向梯度直方图 Histogram of Oriented Gridients,缩写为HOG,是目前计算机视觉.模式识别领域很 ...

  3. OpenCV学习之六: 使用方向梯度直方图估计图像旋转角度

    OpenCV学习之六: 使用方向梯度直方图估计图像旋转角度 原文:http://blog.csdn.net/zhjm07054115/article/details/26964275 下面的代码通过计 ...

  4. OpenCV 使用方向梯度直方图估计图像旋转角度

    人工智能研究网  www.studyai.cn 下面的代码通过计算图像中给定区域的方向梯度直方图来估计图像的旋转角度 主要内容包括: 一.计算局部图像块方向梯度直方图的函数 二.把给定图像按照给定的角 ...

  5. 深度学习----CNN的图像学习之HOG(方向梯度直方图)详解

    一.原理 二.参数的理解 2.1.灰度值 2.2.归一化 2.3.细胞 2.4.窗口 2.5.类型 2.6.Gamma标准化 2.7.图像梯度及梯度算子 2.8.直方图 2.9.高斯空域加窗 三.步骤 ...

  6. 【计算机视觉】方向梯度直方图(Histogram of Oriented Gradient,HOG)

    文章目录 1. HOG 简述 2. HOG 工作流程 第一步.对图像的颜色空间进行归一化 第二步.计算每个像素点的梯度 第三步.为每个单元构建梯度方向直方图 第四步.块内梯度直方图归一化 3. 举个例 ...

  7. 图像学习之如何理解方向梯度直方图HOG(Histogram Of Gradient)

    本文转自:雷锋网,作者:思颖.连接:https://yq.aliyun.com/articles/176607,https://www.leiphone.com/news/201708/ZKsGd2J ...

  8. 图像学习之如何理解方向梯度直方图(Histogram Of Gradient)

    特征描述子(Feature Descriptor) 特征描述子就是图像的表示,抽取了有用的信息,丢掉了不相关的信息.通常特征描述子会把一个w*h*3(宽高3,3个channel)的图像转换成一个长度为 ...

  9. python 方向梯度直方图_手动绘制方向梯度直方图(HOG)

    HOG(Histogram of Oriented Gradients)--方向梯度直方图,是一种表示图像特征量的方法,特征量是表示图像的状态等的向量集合. 在图像识别(图像是什么)和检测(物体在图像 ...

最新文章

  1. 操作系统原理第七章:死锁
  2. 几个复制表结构和表数据的方法
  3. Linux Kernel 3.10内核源码分析--块设备层request plug/unplug机制
  4. Linux 三剑客之SED行天下
  5. Java多线程学习二十二:为什么 Map 桶中超过 8 个才转为红黑树
  6. Android单选中listview中的一项
  7. (day 17 - 快排)剑指 Offer 40. 最小的k个数
  8. Latex绘制三线表
  9. logback日志集成
  10. 分布式定时任务解决方案
  11. 高级运维需要掌握哪些技术?
  12. 计算机类毕业设计评阅书评语,本科毕业论文专家评阅评语
  13. 嵌入式系统开发-麦子学院(10)——arm汇编基础
  14. C++语言99个常见编程错误 常见错误24:晦涩难懂的operator-
  15. 机器学习、计算机视觉神犇/大牛主页
  16. 传统相声台词-太平歌词大实话
  17. batchupdate写法_mybatis执行批量插入insert和批量更新update
  18. 知识图谱介绍-我的学习笔记
  19. 阿里开源项目凤凰架构手册,教你如何涅槃般的构建大型分布式系统
  20. mysql中phpmyadmin安装教程_怎么安装phpMyAdmin?

热门文章

  1. 洛谷P2746 [USACO5.3]校园网Network of Schools
  2. linux下varnish4配置语法(基础)
  3. [经典算法] 河内塔
  4. “2012年度IT博客大赛”获奖感言--梦想、学习、坚持、自信、淡定
  5. Pytorch数据类型转换
  6. Java的代理模式之静态代理和动态代理
  7. Win10下访问linux的ext4分区文件并拷贝
  8. docker报错:OCI runtime create failed...process_linux.go:449: container init caused “write /proc/self/
  9. pythonanywhere使用:进入虚拟机及修改django项目的css样式
  10. eureka服务下线方式