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

2023-05-16

特征描述子(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。

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

hog_preprocess

第二步:计算梯度图像

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

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

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:

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

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图如下:

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

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

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

图像的梯度去掉了很多不必要的信息(比如不变的背景色),加重了轮廓。换句话说,你可以从梯度的图像中轻而易举的发现有个人。

在每个像素点,都有一个幅值(magnitude)和方向,对于有颜色的图片,会在三个channel上都计算梯度。那么相应的幅值就是三个channel上最大的幅值,角度(方向)是最大幅值所对应的角。

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

在这一步,上面的patch图像会被分割成8*8大小的网格(如下图),每个网格都会计算一个梯度直方图。那为什么要分成8*8的呢?用特征描述子的一个主要原因是它提供了一个紧凑(compact)/压缩的表示。一个8*8的图像有8*8*3=192个像素值,每个像素有两个值(幅值magnitude和方向direction,三个channel取最大magnitude那个),加起来就是8*8*2=128,后面我们会看到这128个数如何用一个9个bin的直方图来表示成9个数的数组。不仅仅是可以有紧凑的表示,用直方图来表示一个patch也可以更加抗噪,一个gradient可能会有噪音,但是用直方图来表示后就不会对噪音那么敏感了。

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

这个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的梯度都是什么样子:

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

中间: 一个网格用箭头表示梯度 右边: 这个网格用数字表示的梯度

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

右边的梯度方向矩阵中可以看到角度是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里面去。

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

梯度直方图

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

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

角度大于160的情况

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

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

8*8网格直方图

这里,在我们的表示中,Y轴是0度(从上往下)。你可以看到有很多值分布在0,180的bin里面,这其实也就是说明这个网格中的梯度方向很多都是要么朝上,要么朝下。

第四步: 16*16块归一化

上面的步骤中,我们创建了基于图片的梯度直方图,但是一个图片的梯度对于整张图片的光线会很敏感。如果你把所有的像素点都除以2,那么梯度的幅值也会减半,那么直方图里面的值也会减半,所以这样并不能消除光线的影响。所以理想情况下,我们希望我们的特征描述子可以和光线变换无关,所以我们就想让我们的直方图归一化从而不受光线变化影响。

先考虑对向量用l2归一化的步骤是:
v = [128, 64, 32]
[(128^2) + (64^2) + (32^2) ]^0.5=146.64
把v中每一个元素除以146.64得到[0.87,0.43,0.22]
考虑另一个向量2*v,归一化后可以得到向量依旧是[0.87, 0.43, 0.22]。你可以明白归一化是把scale给移除了。

你也许想到直接在我们得到的9*1的直方图上面做归一化,这也可以,但是更好的方法是从一个16*16的块上做归一化,也就是4个9*1的直方图组合成一个36*1的向量,然后做归一化,接着,窗口再朝后面挪8个像素(看动图)。重复这个过程把整张图遍历一遍。

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

hog-16x16-block-normalization

第五步:计算HOG特征向量

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

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

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

可视化HOG

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

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

visualizing_histogram




====================================分割线================================


本文作者:思颖

本文转自雷锋网禁止二次转载,原文链接

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图像学习之如何理解方向梯度直方图(Histogram Of Gradient) 的相关文章

随机推荐

  • Python爬取网站上面的数据很简单,但是如何爬取APP上面的数据呢

    前言 在我们在爬取手机APP上面的数据的时候 xff0c 都会借助Fidder来爬取 今天就教大家如何爬取手机APP上面的数据 环境配置 1 Fidder的安装和配置 下载Fidder软件地址 xff1a https www telerik
  • linux安装redis教程yum,linux下yum安装redis以及使用

    1 yum install redis 安装redis数据库 2 service redis start Redirecting to bin systemctl start redis service 开启redis服务 方式一 开启re
  • 存储过程:数据的插入和更新

    存储过程的功能非常强大 xff0c 在某种程度上甚至可以替代业务逻辑层 xff0c 接下来就一个小例子来说明 xff0c 用存储过程插入或更新语句 1 数据库表结构 所用数据库为Sql Server2008 2 创建存储过程 xff08 1
  • win10下VS2017配置GSL库

    GSL库 xff1a GNU Scientific Library 1 下载 xff1a 下载Complete package except sources和Sources两个exe文件 2 安装 xff1a 将两个exe安装 xff0c
  • 微信开放平台开发——网页微信扫码登录(OAuth2.0)

    1 OAuth2 0 OAuth xff08 开放授权 xff09 是一个开放标准 xff0c 允许用户让第三方应用访问该用户在某一网站上存储的私密的资源 xff08 如照片 xff0c 视频 xff0c 联系人列表 xff09 xff0c
  • 安全和取证Linux发行版Kali Linux 2018.4 发布

    2019独角兽企业重金招聘Python工程师标准 gt gt gt 公告说 xff0c 欢迎来到2018年的第四个也是最后一个版本 xff0c Kali Linux 2018 4 xff0c 可以立即下载 这个版本将我们的内核升级到4 18
  • 使用Rust + Electron开发跨平台桌面应用 ( 二 )

    前言 在上一篇文章使用Rust 43 Electron开发跨平台桌面应用 一 中 xff0c 我们将Rust 43 Electron结合起来 xff0c 使用Rust编写核心业务逻辑 xff0c 并编译成node库提供给Electron的U
  • linux高级文件系统管理——btrfs

    前几天 xff0c 关于高级文件系统方面也给大家分享过RAID和LVM xff0c 今天给大家分享的这款文件系统可能比这两者更先进 xff0c 可以将其二者合二为一 第一 xff0c 它可以使用磁盘或者分区大小不一样的设备组建RAID xf
  • 字符串 - 字符串排序

    1 字符串排序 对于许多排序应用来说 xff0c 决定顺序的键都是字符串 给定一列字符串 xff0c 需要按一定顺序排列整齐方便后序处理 2 键索引计数法 这个方法名字有点拗口 xff0c 过程有点绕 xff0c 但是每一步其实很简单 举个
  • iOS-高德地图API的定位与搜索功能

    环境 xff1a Xcode10 1 Swift4 2 真机6s xff0c ios11 Demo xff1a https github com cxymq AmapSwift 高德地图API使用 需要 xff08 https lbs am
  • iOS 录音,播放并上传

    1 界面布局 xff0c 以及相关功能 点击中间开始录音 xff0c 点击左上角播放或暂停播放 xff0c 点击右上角移除文件 2 定义相关属性 import 34 SendVoiceController h 34 import impor
  • 【Python基础】request.post()方法

    00 序言 爬取懂che帝的车型信息时 xff0c 没太整明白request post 里面的参数是干什么用的 xff0c 所以写篇学习笔记提醒一下自己 url 61 39 https www dongchedi com motor bra
  • 老虎证券web端PWA实践总结

    历时两个月 xff0c PWA功能终于在web端稳定落地使用 xff0c 网站 web itiger com 从最新研究到落地上线 xff0c 遇到不少坑 xff1b 开发过程中也参考了不少资料 xff0c 但总有那么几个是没有答案 xff
  • 硬盘inode节点简单介绍

    一 inode是什么 xff1f 理解inode xff0c 要从文件储存说起 文件储存在硬盘上 xff0c 硬盘的最小存储单位叫做 34 扇区 34 xff08 Sector xff09 每个扇区储存512字节 xff08 相当于0 5K
  • NoMachine 远程桌面控制

    它是一个基于企业级对比套装的开源的终端服务器 它允许用户在连接速度缓慢或者窄带宽的情况下 xff0c 对X11会话进行远程访问 NX项目提供一整套的运行库文件以及优化的来自X11 xff0c SMB xff0c IPP xff0c HTTP
  • Angular之路--带你来搭建Webpack 2 + Angular 4项目

    上个月Angular发布了4 0 0版本 xff0c 少年们 xff0c 赶快学起来吧 xff0c 这篇文章带领大家搭建一个简单的Angular应用 xff0c 会尽量详细的把每个点都解释到 首先我选择了用webpack2来作为打包工具 x
  • C- unsigned :1之位域分析

    1 首先回忆结构体 我们都知道定义一个结构体可以这样的方式定义 struct Point float x float y point 等价于 struct Point point 除此之外 如果不想声明结构体 只想定义结构体的话 还可以这样
  • ShareSDK自定义UI的方法

    说明 xff1a 我们的分享菜单可以修改背景 xff0c 里面的图标以及文字 xff0c 颜色等 xff0c 另外可以自己自定义UI xff0c 用自己的方法写界面 xff0c 写好了之后可以调用我们以下无UI的分享方法 xff0c 另外我
  • HttpServletRequest & HttpServletResponse 中 Body 的获取

    为什么80 的码农都做不了架构师 xff1f gt gt gt 获取 HttpServletRequest 中的请求体 HttpServletRequest getInputStream 获取到请求的输入流 xff0c 从该输入流中可以读取
  • 图像学习之如何理解方向梯度直方图(Histogram Of Gradient)

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