广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >Python与C++中梯度方向直方图的实现
  • 482
分享到

Python与C++中梯度方向直方图的实现

2024-04-02 19:04:59 482人浏览 泡泡鱼
摘要

目录什么是特征描述子如何计算梯度方向直方图Step 1: 预处理Step 2: 计算梯度图Step 3: 在8×8的cell中计算梯度直方图Step 4: 16&time

原文链接:Histogram of Oriented Gradients

(文中的图片均来自翻译原文)

什么是特征描述子

特征描述子一张图片或者一个图片块的一种表示,通过提取有用信息并扔掉多余的信息来简化图像。

通常,特征描述子将一张大小为width×height×3 (通道数)的图片化成一个长度为n的特征向量/数组。以HOG特征为例,输入图像的大小是64×128×3,输出是一个长度为3780的特征向量。

注意一点,HOG特征也可以是其它大小,但这里我使用原文献中使用的大小,这样你可以更容易地通过一个具体的例子来理解这个概念。

上面这些听起来不错,但是对于一张图片的信息,哪些是有用的哪些是冗余的呢?为了定义这个有用信息,我们需要知道它对什么有用。显然,特征向量对于我们看一张图像没什么用。但是,它对图像识别和目标检测这样的任务很有用。将由这些算法生成的特征向量作为支持向量机等分类算法的输入往往可以得到不错的结果。

但是,对于分类任务来说,哪类特征是有用的呢?让我们先用一个例子讨论一下。假设我们想设计一个目标检测器来检测衬衫或者外套上的纽扣。通常纽扣是圆的(可能在图片上会是椭圆)而且一般会有一些孔用于缝纫。你可以在一张纽扣的图片上执行边缘检测,仅仅通过观察边缘图像就可以判断它是不是一个纽扣。在这个例子中,边缘信息是有用的而颜色信息是无用的。此外,特征也需要有区分能力。例如,从某一张图片中提取的一个好的特征应具备区分纽扣和其他圆心物体(如硬币和车轮)的能力。

对于HOG特征描述子,选用梯度方向的分布作为特征。一张图像的梯度(x和y方向的导数)很有用因为在边缘和拐角(强度变化剧烈的区域)处的梯度幅值很大。而且我们知道边缘和拐角比其他平坦的区域包含更多关于物体形状的信息。

如何计算梯度方向直方图

在这一节,我们将详细介绍HOG描述子的计算。为了解释计算的每个步骤,我们使用一个图片块进行分析。

Step 1: 预处理

正像之前提到的那样,HOG特征通过在一张64×128的图片块上计算得到以用于行人检测。当然完整的图片可以是任意的尺寸。通常我们会在图片的不同位置分析多尺度图片块。唯一的要求就是图片块需要有固定的长宽比。在我们的例子中,图片块需要保持1:2 的纵横比。比如:100×200, 128×256或者1000×2000都可以,但101×205就不满足要求。

为了解释这一点,我在下面选用了一张720×475的图片。我们在图上选择一个图片块来计算HOG特征。这个小块是从原图像上裁剪下来的并且纵横比调整为64×128。这样我们就准备好计算这个图片块的HOG特征了。

Hog preprocess

原始文献中Dalal和Triggs也将 γ γ 矫正放在预处理步骤中,但是带来的增益很小因此这里我们忽略这一步。

Step 2: 计算梯度图

为了计算HOG特征,我们需要先计算图像水平和竖直方向的梯度。毕竟我们想要计算梯度直方图。这一步可以很容易通过的核对对原图像进行滤波实现。

gradient kernel

我们也可以使用OpenCV中的Sobel算子(kernel size设为1)得到相同的结果。


// 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 image
im = 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)

下一步我们可以用下面的公式来计算梯度的幅值和方向。

formula

如果你使用OpenCV,可以通过下面的cartToPolar函数实现。


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

Python中实现如下:


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

下图显示了计算得到的梯度:

gradients

左:X方向梯度幅值图;中:Y方向梯度幅值图;右:梯度幅值图

X方向的梯度凸显竖直的线而Y方向的梯度凸显水平的线。梯度的幅值出现在强度变化剧烈的地方。在强度平坦的区域几乎没有梯度。我故意忽略了梯度方向图,因为在图像上显示梯度方向没有传递太多的信息。

梯度图像移除了很多不必要的信息(比如不变的背景),突出了轮廓信息。也就是说,你仅仅通过看梯度图像还是可以辨认出图像有有一个人。

对于每一个像素,梯度都会有幅值和方向。对于彩色图像,需要分别计算3个通道的梯度(如上图所示)。而该像素点的幅值是这3个通道梯度幅值的最大值,方向是最大梯度幅值对应的角度。

Step 3: 在8×8的cell中计算梯度直方图

在这一步,图像被分成8×8的很多cell,而梯度直方图是在这些cell中计算出来的。

hog-cells

我们一会儿将学习直方图,但在那之前,我们先理解一下为什么将图像切分成很多8×8的cell。使用特征描述子来描述图像中的一小块的一个重要原因是它用更为紧凑的表示方法刻画了原图像。一个8×8的图片块包含了8×8×3=192个像素值。而这个图像块的每个像素点梯度信息包含梯度幅值和方向两个值,一共是8×8×2=128个值,这128个值可以通过用包含9个bin的直方图表示成一个一维数组(包含9个值)。这样做不仅可以使图像表示更紧凑,而且在一个图片块中计算直方图可以让这种表示方法对噪声有更强的鲁棒性。单个像素的梯度信息可能包含噪声,而一个8×8的图片块中的直方图让这种表示方法对噪声更不敏感。

但是为什么要用8×8的图片块呢?为什么不是32×32?这是由我们需要寻找的特征比例决定的。HOG特征起初是被用来检测行人的。8×8的cell在一张64×128的行人图片块中的足以捕捉感兴趣的特征(如人脸、头顶等)。

上述梯度直方图本质上是一个包含9个数字的向量(或数组),这9个数字分别对应0°、20°、40°、… 160°。

我们来看一下图片块中的一个8×8 cell的梯度是什么样子。

这里写图片描述

中:一个RGB cell及其梯度(用箭头表示);右:cell中的梯度大小和方向(数字表示)

如果你是一个计算机视觉领域新手,中间的这幅图为你提供了很多信息。它展示了用箭头表示的梯度信息的梯度图——箭头的指向表示了梯度的方向而箭头的长度表示了梯度的大小。需要注意到的一点是箭头的方向指向了图像强度变化的方向,而梯度大小表示了强度的变化有多大。

在右边的图上,我们发现8×8的cell中表示梯度的数字有一点细微的差别——角度实在0°到180°之间的而不是0°到360°之间。这些叫做“无符号梯度”,因为因为一个正负方向的两个梯度由同一个数字表示。换句话说,某一个梯度箭头和它对应的另一个值(加上180°对应的那个值)被当作是同一个梯度。根据经验,无符号梯度被证明比有符号梯度效果更好。一些HOG特征的实现代码会允许你选择是否使用有符号梯度。

下一步就是在这些8×8的cells上创建梯度直方图。直方图包含9个bins分别对应着0°、20°、40°、… 160°。

下图解释了具体的过程。我们在和上面那个图一样的8×8的cells上查看梯度的大小和方向。每个bin是基于梯度方向选出来的,对应的票数(加在当前bin上的值)对应着梯度的大小。我们先来看看用蓝色圆圈出来的像素,它的梯度的角度是80°,大小为2。因此它在第5个bin上加2。下图中用红色圈出来的梯度的角度是10°,大小是4。由于10°是在0°和20°的中间位置, 因此改位置梯度对应票数被一分为二加到相邻的两个bin上。

这里写图片描述

还有一个细节需要注意。如果梯度方向大于160°。此时梯度的角度位于160°和180°之间。我们知道0°和180°是一样的(无符号梯度),因此在下面的例子中,梯度方向为165°的像素按比例将梯度大小分配到0°和160°的bin中。

这里写图片描述

8×8的cell中所有像素处的梯度按照方向将梯度大小累加到9个bin以创建最后的梯度直方图。上图中的cell对应的梯度直方图如下:

这里写图片描述

在我们的表示结果中,y轴对应0°。你可以发现上面的直方图中有大量的权重(梯度大小的投票结果)在0°和180°附近,这从另外一个角度说明了在这个cell中大部分梯度方向要么朝上要么朝下。

Step 4: 16×16 Block标准化

这里写图片描述

在上述步骤中,我们基于图像的梯度创建直方图。一张图片的梯度对整体的光线的光线比较敏感。如果你把图像所有的像素值除以2使整张图像变暗,梯度的大小也会变为原来的一半,从而梯度直方图的值也会将为原来的一半。理想情况下,我们想让特征描述子独立于光线变化。换句话说,我们想要“标准化”这个直方图使它不受光线变化的影响。

在我讲梯度直方图如何标准化之前,我们先来看看一个长度为3的向量如何标准化。

假设我们有一个RGB颜色向量[128, 64, 32]。这个向量的长度是

。这也叫做向量的L2范数。将这个向量的所有元素除以向量长度146.64就可以得到一个标准化的向量[0.87, 0.43, 0.22],现在考虑另外一个向量,这个向量的元素是第一个向量的两倍即2×[128, 64, 32]=[256, 128, 64]。你可以自己计算一下它对应的标准化结果,发现结果仍然是[0.87, 0.43, 0.22],这个值和第一个RGB向量的标准化向量相同。你可以发现标准化一个向量移除了这个向量的尺度信息。

现在我们知道如何标准化一个向量,你可能想到当计算HOG特征的时候你可以像之前标准化一个3×1向量一样去标准化9×1的直方图。这的确是个不错的想法,但是更好的做法是标准化一个更大的16×16的block。一个16×16的block包含4个直方图,这4个直方图可以连接成一个36×1的向量,而且这个向量仍然可以像那个3×1的向量一样进行标准化。每次标准化后,整个窗口移动8个像素并再次计算得到一个36×1的标准化向量,就这样一直重复这个过程。

Step 5: 计算HOG特征向量

为了计算整个图片块最终的特征向量所有的36×1的向量被连接成一个大向量。这个大向量的维度是多少大呢?

我们来计算:

- 1. 我们有多少个不同位置的16×16的block?一共有 (64-8)/8=7 个水平的位置和 (128-8)/8=15 个竖直的位置,所以总计7×15=105个。

- 2. 每一个16×16的block被表示成一个36×1的向量。因此,当我们把他们连接成一个大向量的时候会得到一个36×105=3780维度的向量。

梯度直方图可视化

一个图像块梯度特征的可视化通常通过在所有8×8的cell里画出对应的标准化的9×1向量(直方图)。如下图所示。你会注意到直方图的主要方向捕捉了人的形状,尤其是在躯干和腿附近。

不幸的是,目前在OpenCV中并没有一个简单的方法方法来可视化HOG特征。

到此这篇关于Python与C++中梯度方向直方图的实现的文章就介绍到这了,更多相关Python 梯度方向直方图内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Python与C++中梯度方向直方图的实现

本文链接: https://www.lsjlt.com/news/142846.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Python与C++中梯度方向直方图的实现
    目录什么是特征描述子如何计算梯度方向直方图Step 1: 预处理Step 2: 计算梯度图Step 3: 在8×8的cell中计算梯度直方图Step 4: 16&time...
    99+
    2022-11-13
  • OpenCV 图像梯度的实现方法
    目录概述梯度运算礼帽黑帽Sobel 算子计算 x计算 y计算 x+y融合概述 OpenCV 是一个跨平台的计算机视觉库, 支持多语言, 功能强大. 今天小白就带大家一起携手走进 Op...
    99+
    2022-11-12
  • C++怎么实现直方图中最大的矩形
    这篇文章主要介绍“C++怎么实现直方图中最大的矩形”,在日常操作中,相信很多人在C++怎么实现直方图中最大的矩形问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C++怎么实现直方图中最大的矩形”的疑惑有所帮助!...
    99+
    2023-06-19
  • C++实现LeetCode(84.直方图中最大的矩形)
    [LeetCode] 84. Largest Rectangle in Histogram 直方图中最大的矩形 Given n non-negative inte...
    99+
    2022-11-12
  • Matlab实现二维散点主方向直方图的绘制详解
    目录工具函数基本使用多组数据修改配色精细修饰简简单单画个二维散点图主方向上的直方图: 工具函数 输入nx2大小的数组,返回以下四个图形对象: H1: ‘数据点&rsqu...
    99+
    2022-11-13
  • 基于Python+Matplotlib实现直方图的绘制
    目录1.关于直方图2.plt.hist()3. 绘制一幅简单的 频数 分布直方图4. 绘制一幅 频率 分布直方图5. 累积分布直方图(水平方向)1.关于直方图 直...
    99+
    2022-11-10
  • Python实现向PPT中插入表格与图片的方法详解
    目录插入表格插入图片上一章节学习了如何在 PPT 中添加段落以及自定义段落(书写段落的内容以及样式的调整),今天的章节将学习在 PPT 中插入表格与图片以及在表格中插入内容。 废话不...
    99+
    2022-11-11
  • C++位图的实现原理与方法
    概念 位图就是bitmap的缩写,所谓bitmap,就是用每一位来存放某种状态,适用于大规模数据,该数据都是不重复的简单数据。通常是用来判断某个数据存不存在的 例如:给40亿个不重...
    99+
    2022-11-12
  • 基于Python+Matplotlib怎么实现直方图的绘制
    今天小编给大家分享一下基于Python+Matplotlib怎么实现直方图的绘制的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧...
    99+
    2023-06-30
  • Node与Python双向通信的实现方法
    这篇文章主要介绍“Node与Python双向通信的实现方法”,在日常操作中,相信很多人在Node与Python双向通信的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Node与Python双向通信的实...
    99+
    2023-06-20
  • Python中OpenCV彩色与灰度图像转换的方法
    这篇文章主要介绍Python中OpenCV彩色与灰度图像转换的方法,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!彩色图像转换为灰度图像第一种方式通过 imread 读取图像的时候直接设置参数为 0 ,自动转换彩色图像...
    99+
    2023-06-15
  • Python实现批量绘制遥感影像数据的直方图
    本文介绍基于Python中gdal模块,实现对大量栅格图像批量绘制直方图的方法。 首先,明确一下本文需要实现的需求:现需对多幅栅格数据文件进行依据其像元数值的直方图绘制,具体绘制内容...
    99+
    2023-02-27
    Python批量绘制直方图 Python绘制直方图 Python直方图
  • Matplotlib直方图绘制中的参数bins和rwidth的实现
    目录情景引入bins 参数stacked参数rwidth 参数引用情景引入 我们在做机器学习相关项目时,常常会分析数据集的样本分布,而这就需要用到直方图的绘制。 在Python中可以...
    99+
    2022-11-13
  • Python如何实现批量绘制遥感影像数据的直方图
    这篇文章主要介绍“Python如何实现批量绘制遥感影像数据的直方图”,在日常操作中,相信很多人在Python如何实现批量绘制遥感影像数据的直方图问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python如何实...
    99+
    2023-07-05
  • css实现任意图片垂直居中的方法有哪些
    这篇文章主要讲解了“css实现任意图片垂直居中的方法有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“css实现任意图片垂直居中的方法有哪些”吧!方法一:...
    99+
    2022-10-19
  • C#中委托的基础入门与实现方法
    目录前言关于委托委托的实现一、基本实现方式二、使用委托时的一些特殊方式1、委托实例对象的创建多元化:2、事件绑定的多种方式三、委托的几种特殊实现方式1,使用Action方法2,使用F...
    99+
    2022-11-12
  • C#中委托的基础介绍与实现方法
    这篇文章主要讲解了“C#中委托的基础介绍与实现方法”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C#中委托的基础介绍与实现方法”吧!目录前言关于委托委托的实现一、基本实现方式二、使用委托时的...
    99+
    2023-06-20
  • python 阿里云oss实现直传签名与回调验证的示例方法
    签名 import base64 import json import time from datetime import datetime import hmac from ...
    99+
    2022-11-12
  • C++中线程的原理与实现方法是什么
    这篇文章主要介绍“C++中线程的原理与实现方法是什么”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“C++中线程的原理与实现方法是什么”文章能帮助大家解决问题。在C++中有多种实现线程的方式C++11...
    99+
    2023-07-05
  • C#进度条在弹出窗口中显示的实现方法
    这篇文章主要介绍“C#进度条在弹出窗口中显示的实现方法”,在日常操作中,相信很多人在C#进度条在弹出窗口中显示的实现方法问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”C#进度条在弹出窗口中显示的实现方法”的疑...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作