百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

深入浅出理解HOG特征——梯度方向直方图

bigegpt 2024-08-19 12:05 3 浏览

原文地址:https://learnopencv.com/histogram-of-oriented-gradients/


最近在搞车牌识别的时候,训练样本去识别车牌的时候用到HOG特征。国外一篇文章让我受益良多


  • 什么是特征描述符?

特征描述符是指通过提取有用的信息并抛弃无关的信息来表示这一张图片或者一张图片的一部分


典型地,特征描述符将大小宽度x高度x 3(通道)的图像转换为特征向量数组,长度n。例如:在HOG特征描述器的情况下,输入图像大小为64×128×3,输出特征向量长度为3780。


中间有一个循环装箱的过程
划分为8x8大小的图像补丁块处理,装到9个箱子(其中8x8、9 这些参数都是不固定的,但是是推荐的)
移动步伐:8个像素
width:64 /8 == 8 份
Height:128 /8 ==16份
用一个16x16的窗口来处理,可以包含4个8X8的图像补丁,那么处理一次会有得到4*9个箱子数据。循环处理
最后能循环 7*15=105次
105*36=3780个箱子数据,存储的是每个像素的梯度大小和梯度方向


记住,HOG特征描述符能够用其他的尺寸大小来计算,但是在下面的具体例子里为了让你更加容易理解相关概念,选择使用图像宽高:64×128,图像补丁 8x8 窗口 16X16 移动步长 8个像素


首先来了解什么是“有用的信息”、什么是“无关的信息”?我们需要明确知道“有用”是指对什么有用。


特征向量对查看图像是没有用的,但是,对于图像识别和目标检测这些任务是非常有用的。将这些算法生成的特征向量引入到支持向量机(SVM)等图像分类算法中,可以取得不错的效果。


但是,哪一种“特征”对分类任务才是真正有用的呢?让我们用一个例子来讨论这一点。假设我们要建立一个物体检测仪,用来检测衬衫和大衣的纽扣。按钮是圆形的(在图像中可能看起来是椭圆的),通常有几个洞用于缝纫。你可以在一个按钮的图像上运行一个边缘检测器,只需简单地观察边缘图像就可以很容易地判断它是否是一个按钮。在这种情况下,边缘信息是“有用的”,而颜色信息不是。此外,该功能还需要有鉴别能力。例如,从图像中提取的良好特征应该能够分辨按钮和其他圆形物体,如硬币和汽车轮胎的区别。


在HOG特征描述器中,梯度方向(梯度)的分布(直方图)作为特征。图像的梯度(x和y导数)是有用的,因为梯度的大小在边缘和拐角处(突然强度变化的区域)很大,而且我们知道边和角在物体形状上的信息比平面区域要多得多。


怎么去计算方向梯度直方图?
在这一节中,我们将深入研究计算HOG特征描述符的细节。为了说明每一步,我们将使用一个图像块。



步骤1:预处理

如前所述的HOG特征描述符用于行人检测,是在64×128的图像计算。当然,图像可能是任意大小的。通常在多个尺度上分析多个图像位置,唯一的限制是被分析的补丁具有固定的长宽比(纵横比)。在我们的例子中,补丁需要有一个长宽比为1:2。例如,他们可以100×200, 128×256,或1000×2000而不是101×205。


为了说明这一点,下面展示了一个大尺寸的720×475图像。我们计算我们的HOG特征描述符选择一块大小100×200。这个补丁被裁剪的图像并调整其大小以64×128。现在已经准备好计算这个图像补丁的HOG描述符了。


还有一个预处理步骤就是“伽玛校正”,但性能提升非常小,所以这里跳过该步骤。




步骤2:计算图像梯度


要计算一个HOG描述符,我们首先需要计算水平和垂直梯度;毕竟,我们要计算梯度直方图。通过用以下内核过滤图像很容易做到这一点。


我们可以在opencv中使用内核大小为1的Sobel算子实现同样的结果。


// Read image
    Mat img = imread("F:/data/car/test1.jpg");
    img.convertTo(img, CV_32F, 1 / 255.0);


// Calculate gradients gx, gy
    Mat gx, gy;
//对X梯度绝对值
    Sobel(img, gx, CV_32F, 1, 0, 1);
//对Y梯度绝对值
    Sobel(img, gy, CV_32F, 0, 1, 1);


接下来,我们可以用下面的公式找到梯度的大小和方向


如果你是使用opencv,计算梯度的大小和方向可以使用函数carttopolar,如下所示。


   Mat mag, angle;
//mag 坡度梯度 大小
//mag就是大小 
//angle就是方向
    cartToPolar(gx, gy, mag, angle, 1);


下图显示了梯度

注意,图x梯度在垂直线方向延伸,图y-梯度在水平线方向延伸。图坡度梯度在强度上有急剧的变化。当图片区域光滑时,都没有延伸。我故意遗漏了显示渐变方向的图像,因为作为图像显示的方向不能传达太多信息。


注意看图像的变化渐变图像去除了许多非必要的信息(例如恒定的彩色背景),但突出显示了轮廓。换句话说,你可以看到渐变图像,并且很容易地辨别出图片中有一个人。


图x梯度 注意水平方向基本没有延伸

图y梯度 注意垂直方向基本没有延伸




步骤3:计算在8×8细胞梯度直方图

在这一步中,图像被分为8×8细胞和梯度直方图计算每个8×8细胞。


我们将学习了解在一瞬间的直方图,但是在我们去之前就让我们先了解为什么我们把图像分为8×8细胞。使用特征描述符描述图像补丁的一个重要原因是它提供了一个紧凑的表示。8×8图像补丁包含8x8x3 = 192像素值。这个补丁梯度每像素包含2个值(大小和方向),那就变成8x8x2 = 128个数。通过这一部分的最后我们会看到这128个数字是用9-bin直方图(可存储为长度9的数组,通俗地说是分别装到9个箱子里)表示。不仅是表示更简洁,计算在补丁直方图具有更强的健壮性。个别的颜色梯度可能有噪音,但用一个8x8图像补丁来表示梯度直方图对噪声不敏感,换句话说,就是受噪音影响不大。


但是什么是8x8图像补丁?为什么不是32x32?这是我们通过特征缩放来寻找到的明确的选择。HOG最初用于检测行人。在一张行人照片缩放到64×128,使用8×8细胞足以捕捉有趣的功能(如面部、头部的等)。


让我们看一个8×8补丁在图像梯度的面貌




中间的图像信息量是非常大的。它显示了用箭头表示梯度的图像的贴片,箭头显示梯度的方向,其长度显示大小。注意箭头的方向如何指向强度的变化方向,其大小表示差异的大小。


在右边,我们看到原始的数字表示在8×8细胞有一个小的差异,那就是角度是0度和180度的梯度,而不是0到360度之间。这些被称为“无符号”渐变,因为梯度正值和它的负值用相同的数字表示。换句话说,梯度箭头和与之相对的180度箭头被认为是相同的。但是,为什么不使用0 - 360度呢?经验表明,无符号梯度比签名梯度更好地用于行人检测。HOG的一些实现将允许您指定是否使用带符号的渐变。


下一步是创建一个8×8细胞梯度直方图。直方图包含9个箱子对应角度0, 20, 40…160。


下图说明了这个过程。我们正在前面的图寻找在同8×8补丁梯度的幅值和方向。根据方向选择箱子,并根据大小选择投票(进入箱子的值)。让我们首先关注环绕在蓝色中的像素。它的角度(方向)为80度,大小为2。所以它放入到第五个箱子。用红色包围的像素的梯度方向为10度,大小为4。由于10度是0和20之间的一半,所以像素的也是均匀地分成两个箱子。




还有一个细节需要注意。如果角度大于160度,则在160到180之间,我们知道角度绕成0和180相等。因此,在下面的例子中,角度为165度的像素正比于0度的箱子和160度的箱子。


从160-180

180-165/165-160=3
所以0箱子分4/1,160箱子分4/3


在8×8细胞中所有像素的贡献加起来创造9-bin直方图。对于上面的补丁,它看起来像这样



在我们的表示中,y轴是0度。你可以看到直方图在0度和180度附近占很大比重。




步骤4:16x16步块归一化

在前面的步骤中,我们根据图像的梯度创建了一个直方图。图像的梯度对整体亮度是敏感的。如果通过将所有像素值除以2来使图像变暗,则渐变幅度将改变一半,因此直方图值将改变一半。理想情况下,我们希望描述符不受光照变化的影响。换句话说,我们希望使直方图正常化(归一化),这样它们不会受到光照变化的影响。


在解释直方图是如何规范化之前,让我们看看长度为3的向量是如何规范化的。



例如:一个像素向量RGB【128,64,32】,向量的长度则为:sqrt{128^2 + 64^2 + 32^2} = 146.64
这也被称为向量的L2范数。将向量的每一个元素除以146.64得到归一化向量【0.87,0.43,0.22】,可以看到,归一化后的【256,128,32】将得到【0.87,0.43,0.22】可以看到归一化向量消除了规模。


现在我们知道了如何归一化一个矢量,你可能会认为在计算HOG特征时可以将9x1的直方图以上述的3×1矢量的方式归一化。可以是可以,但更好的办法是归一化一个更大尺寸的16×16块。16×16块用4个直方图可能联成一个36×1元矢量,使用3×1矢量归一化的方法。然后通过8像素的窗口移动(见动画)重复计算,归一化的36×1向量。



步骤5:计算HOG特征向量

计算整个图像补丁最终的特征向量,36×1载体连接成一个巨大的载体。这个向量的大小是多少?
原图截取

100*200—>resize—>64*128
64/8=8
128/8=16


1、我们有多少个16×16块吗?有7个水平和15个垂直位置,总共7×15=105个块。


2、每16×16块由36×1矢量表示。所以当我们连接成一个巨大的载体,他们都得到了36×105 = 3780维向量。

定向梯度直方图的可视化


一个图像块的HOG特征描述符通常是通过在8×8组织的9×1归一化直方图可视化。见上图像。你会注意到,直方图的主导方向捕捉人的形状,特别是围绕躯干和腿。


不幸的是,没有简单的方法来可视化OpenCV的HOG描述符。

相关推荐

悠悠万事,吃饭为大(悠悠万事吃饭为大,什么意思)

新媒体编辑:杜岷赵蕾初审:程秀娟审核:汤小俊审签:周星...

高铁扒门事件升级版!婚宴上‘冲喜’老人团:我们抢的是社会资源

凌晨两点改方案时,突然收到婚庆团队发来的视频——胶东某酒店宴会厅,三个穿大红棉袄的中年妇女跟敢死队似的往前冲,眼瞅着就要扑到新娘的高额钻石项链上。要不是门口小伙及时阻拦,这婚礼造型团队熬了三个月的方案...

微服务架构实战:商家管理后台与sso设计,SSO客户端设计

SSO客户端设计下面通过模块merchant-security对SSO客户端安全认证部分的实现进行封装,以便各个接入SSO的客户端应用进行引用。安全认证的项目管理配置SSO客户端安全认证的项目管理使...

还在为 Spring Boot 配置类加载机制困惑?一文为你彻底解惑

在当今微服务架构盛行、项目复杂度不断攀升的开发环境下,SpringBoot作为Java后端开发的主流框架,无疑是我们手中的得力武器。然而,当我们在享受其自动配置带来的便捷时,是否曾被配置类加载...

Seata源码—6.Seata AT模式的数据源代理二

大纲1.Seata的Resource资源接口源码2.Seata数据源连接池代理的实现源码3.Client向Server发起注册RM的源码4.Client向Server注册RM时的交互源码5.数据源连接...

30分钟了解K8S(30分钟了解微积分)

微服务演进方向o面向分布式设计(Distribution):容器、微服务、API驱动的开发;o面向配置设计(Configuration):一个镜像,多个环境配置;o面向韧性设计(Resista...

SpringBoot条件化配置(@Conditional)全面解析与实战指南

一、条件化配置基础概念1.1什么是条件化配置条件化配置是Spring框架提供的一种基于特定条件来决定是否注册Bean或加载配置的机制。在SpringBoot中,这一机制通过@Conditional...

一招解决所有依赖冲突(克服依赖)

背景介绍最近遇到了这样一个问题,我们有一个jar包common-tool,作为基础工具包,被各个项目在引用。突然某一天发现日志很多报错。一看是NoSuchMethodError,意思是Dis...

你读过Mybatis的源码?说说它用到了几种设计模式

学习设计模式时,很多人都有类似的困扰——明明概念背得滚瓜烂熟,一到写代码就完全想不起来怎么用。就像学了一堆游泳技巧,却从没下过水实践,很难真正掌握。其实理解一个知识点,就像看立体模型,单角度观察总...

golang对接阿里云私有Bucket上传图片、授权访问图片

1、为什么要设置私有bucket公共读写:互联网上任何用户都可以对该Bucket内的文件进行访问,并且向该Bucket写入数据。这有可能造成您数据的外泄以及费用激增,若被人恶意写入违法信息还可...

spring中的资源的加载(spring加载原理)

最近在网上看到有人问@ContextConfiguration("classpath:/bean.xml")中除了classpath这种还有其他的写法么,看他的意思是想从本地文件...

Android资源使用(android资源文件)

Android资源管理机制在Android的开发中,需要使用到各式各样的资源,这些资源往往是一些静态资源,比如位图,颜色,布局定义,用户界面使用到的字符串,动画等。这些资源统统放在项目的res/独立子...

如何深度理解mybatis?(如何深度理解康乐服务质量管理的5个维度)

深度自定义mybatis回顾mybatis的操作的核心步骤编写核心类SqlSessionFacotryBuild进行解析配置文件深度分析解析SqlSessionFacotryBuild干的核心工作编写...

@Autowired与@Resource原理知识点详解

springIOCAOP的不多做赘述了,说下IOC:SpringIOC解决的是对象管理和对象依赖的问题,IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂管理这些对象的创建以及依赖关系...

java的redis连接工具篇(java redis client)

在Java里,有不少用于连接Redis的工具,下面为你介绍一些主流的工具及其特点:JedisJedis是Redis官方推荐的Java连接工具,它提供了全面的Redis命令支持,且...