第七章 原理篇:HOG特征提取

news2024/9/26 3:30:47

之前面试被问到了然后没有讲出来,所以今天复习一下!
气死我了!

参考教程:

What Is a Feature Descriptor in Image Processing?

https://medium.com/analytics-vidhya/a-gentle-introduction-into-the-histogram-of-oriented-gradients-fdee9ed8f2aa


文章目录

  • Feature Descriptors
    • Local Descriptors
    • Global Descriptors
  • HOG feature descriptor
    • steps to calculate HOG features
      • 预处理
      • 计算梯度
      • 获得梯度直方图
      • 归一化
      • 获得特征向量
  • 代码实现

随着机器学习的发展更迭,优化算法很容易北更先进的算法取代。而Histogram of Oriented Gradient方向梯度直方图检测算法,简称HOG则经历了时间的考验,即使在今天也被频繁使用,因为它的效果真的很好。

Feature Descriptors

“The feature descriptor describes an interest point and encodes the description in the form of a multidimensional feature vector in the vector space.” 特征描述子对图像中的感兴趣区域进行描述,并对描述的结果以多维度特征向量的形式进行编码。

那么什么是感兴趣区域interest point呢?这个区域通常是两个或多个区域的边缘段的交集或者物体的边界的方法发生快速改变的区域。这些区域具有一定的稳定性,在缩放、旋转或者光照改变时它们都具有一不变性,不会受到这些变化的影响。

因此,我们能够准确地找到这些区域,对于我们的图像相关的任务都会带来巨大的帮助。

特征描述子是一种提取对整个图像或者其中的感兴趣区域的特征描述的方法。它是对图像的表达,它提取了图像中有用的信息,抛弃了一些没有用的信息。特征描述子就像是一种数字化的指纹,它对重要信息进行编码,使得我们能使用这个编码结果将不同的特征区分开来。特征描述子在数学上的表达方式就是一维或者多维的向量,被称为特征向量。

从应用层面考虑,特征描述子可以简单分为两类。一种是对局部特征的描述,一种是对全局特征的描述。我们在一些low-level的应用上使用全局特征,比如目标检测和分类。我们在high-level的应用上使用局部特征,比如目标识别。

Local Descriptors

局部特征表达了一个图像的纹理。一个局部描述子通常对image中的一部分进行描述。使用多个局部描述子来处理一张图像要比只使用一个单独的描述子效果更好。常见的局部描述子有SIFT,SURF,LBP等。

Global Descriptors

全局特征将整个图片当作一个整体来进行描述,比如contour representation, shape descriptors, texture features。常见的全局描述子有HOG,HOF和MBH等。

HOG feature descriptor

使用HOG描述子,我们会将一个图像转换成一个长度为n的特征向量。虽然这个你很难通过这个向量得到原始图像的样子,但是它能够被应用在图像相关的任务中,并取得非常不错的结果。

在使用时,它只是简单地使用了梯度直方图作为图像的特征,对图像的局部区域梯度方向的次数进行了统计。

steps to calculate HOG features

在最开始的地方进行一下概念的总结:
window: 进行hog计算的区域称为window,要求宽高比1:2,一般使用64*128。
cell: hog中的最小单元,基于cell进行长度为9的梯度直方图的计算。
block: 2*2个cell组成一个block,基于block进行normalization。

预处理

图像大小:

  • 首先对图像进行预处理,使其拥有一个固定的宽高比,通常这个比例是1:2。在实际使用中,一般选择64*128大小的图像,所以你需要先将你的图像转为64x128的大小。
  • 假如你有一张很大的图片,你需要从图片中crop出一张张你想用来特征提取的小图片,并把它们转为指定大小。
  • 这里的64*128,我们称为window

灰度or RGB:

  • 灰度图像和RGB图像都可以用来计算直方图,因此不是必须将图像转成灰度图的格式。假如使用的是彩色图像,就用多通道中最大的梯度代表当前位置的梯度。

色彩校正:
为减少光照因素的影响,可以对图像进行gamma矫正,调节对比度。
f ( x ) = x γ f(x) = x^{\gamma} f(x)=xγ

计算梯度

计算梯度直方图。使用以下的kernal对图像进行卷积操作,可以得到他们的水平和垂直方向的梯度。

用公式的方法表示就是
G x ( r , c ) = I ( r , c + 1 ) − I ( r , c − 1 ) ; G y ( r , c ) = I ( r − 1 , c ) − I ( r + 1 , c ) G_x(r,c) = I(r, c+1) - I(r, c-1) ; G_y(r,c) = I(r-1, c) - I(r+1,c) Gx(r,c)=I(r,c+1)I(r,c1);Gy(r,c)=I(r1,c)I(r+1,c)
获得水平和垂直方向的梯度后,使用笛卡尔坐标都极坐标的映射公式来获得梯度的方向和幅值。
g = g x 2 + g y 2 g = \sqrt{g^2_x + g^2_y} g=gx2+gy2
θ = a r c t a n g y g x \theta = arctan\frac{g_y}{g_x} θ=arctangxgy

获得梯度直方图

在获得每个像素处的梯度后,梯度矩阵会被划分为8*8的小单元,称为cell。每一个cell中存在8*8*2=128个值。对每一个cell,都要计算一个长度为9的数组,也就是我们的直方图。bin值以20度为一个区间进行划分。如下图。
在这里插入图片描述

以下图为例子,对于cell中的第一个位置,方向角度为80,幅值为2,那么就在bin=80的位置加2。对第二个位置,方向角度36,幅值为3,那么这个3会按比例分配给bin=20和bin=40。对于角度大于160的值,图中画圈的位置,方向角度为165,幅值为85,那么它会被按比例分配给bin=0和bin=160.
在这里插入图片描述

归一化

一个8*8的区域是一个cell,2*2个cell组成了一个block。这个block是使用滑动窗口得到的。一个cell中有9个值,那么一个block就有36个值。为了减少光照变化的影响,要对直方图进行归一化。使用L2范式,以block为单位进行归一化。
f b i = f b i ∣ ∣ f b i 2 ∣ ∣ + ϵ f_{bi} = \frac{f_{bi}}{\sqrt{||f_{bi}^2||+\epsilon}} fbi=∣∣fbi2∣∣+ϵ fbi

获得特征向量

对一个block我们可以得到长度36的特征向量。假如图像大小是64*128,划分为8*16个cell,那么得到的block数目为(16-1)*(8-1) = 105。整个图像的特征向量长度为105*36 = 3780。

代码实现

请添加图片描述
我们对这张汽车图进行hog特征提取的运算。

import cv2
import math
import numpy as np
import matplotlib.pyplot as plt

img = cv2.resize(cv2.imread('car.png',0),(64,128))
img = np.power(img/float(np.max(img)), 1.5)

读取图像并进行gamma矫正。虽然hog可以提取彩色图像的特征,但是这里为了方便仍将图像转成了灰度图。

在这里插入图片描述
resize后真的很丑,将就看看。接下来进行图片梯度的计算,我们按照上一章节中提供的公式进行计算,而没有直接使用Sobel算子。

import math
def gradient_calculate(img):
    gradient_x = []
    gradient_y = []
    mag = []
    angle = []
    h,w = img.shape
    for i in range(h):
        for j in range(w):
            
            if j-1<0:
                gx = img[i,j+1]
            elif j+1 >= w:
                gx = 0 - img[i,j-1]
                
            else:
                gx = img[i,j+1] - img[i,j-1]
                
            
            if i-1<0:
                gy = img[i+1,j]
            elif i+1>=h:
                gy = img[i-1,j]
            else:
                gy = img[i-1,j] - img[i+1,j]
                
            gradient_x.append(gx)
            gradient_y.append(gy)
            mag.append(math.sqrt(gx**2 + gy**2))
            if gx ==0:
                angle.append(math.degrees(0))
            else:
                angle.append(math.degrees(abs(math.atan(gy/gx))))
    gradient_x = np.array(gradient_x).reshape(h,w)
    gradient_y = np.array(gradient_y).reshape(h,w)
    mag = np.array(mag).reshape(h,w)
    angle = np.array(angle).reshape(h,w)
    return gradient_x, gradient_y, mag, angle
x, y, mag, ang = gradient_calculate(img)

输入为我们读取的图片,输出为gradient_x, gradient_y, mag 和angle。
看一下我们得到的结果。

接下来对每个8*8的cell进行直方图的计算。我们使用上一步得到的mag和angle作为输入。

def histogram_calculate(mag, angle):
    number_bins = 9
    h, w = mag.shape
    hist_out = []
    for i in range(0,h,8):
        tmp = []
        for j in range(0,w,8):
            patch_mag = mag[i:i+8,j:j+8]
            patch_angle = angle[i:i+8,j:j+8]
            bins = [0 for _ in range(number_bins)]
            for m in range(8):
                for n in range(8):
                    cur_mag = patch_mag[m,n]
                    cur_val = patch_angle[m,n]
                    index = cur_mag//20
                    if index == number_bins-1:
                        left = index * 20
                        right = 0
                    left = index*20
                    right = index*(20+1)
                    left_value = (cur_mag - left)//20 * cur_val
                    right_value = cur_val - left_value
                    
                    bins[int(index)]+=left_value
                    bins[int((index+1)%number_bins)]+=right_value
            tmp.append(bins)
        hist_out.append(tmp)
    return hist_out
hist = histogram_calculate(mag, angle)            

这里返回结果的hist的大小为[16,8,9]。即对全图上所有的cell都进行了直方图的计算。接下来按照2*2的cell组成一个block,block按滑动窗口进行选取的规则,完成特征的计算,和block内部的normalization。

def calculate_feature(hist):
    epsilon = 1e-05
    feature = []
    h, w = len(hist), len(hist[0])
    for i in range(h-1):
        tmp = []
        for j in range(w-1):
            block4 = [hist[m][n] for n in range(j,j+2) for m in range(i,i+2)]
            block = []
            for sample in block4:
                for val in sample:
                    block.append(val)
            summ = math.sqrt(sum([x**2 for x in block]))
            block = [x/(summ+epsilon) for x in block]
            tmp.append(block)
        feature.append(tmp)
    return feature
feature = calculate_feature(hist)

这里得到的feature大小为[15, 7, 36],也就是我们的图片的特征。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/657276.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

scratch lenet(3): 直方图均衡化的C语言实现

文章目录 1. 目的2. 原理3. 实现3.1 获得直方图 int hist[256]3.2 获得累积分布 int cdf[256]3.3 均衡化公式3.4 遍历原图&#xff0c;逐点均衡化&#xff0c;得到结果 4. 完整代码和结果4.1 例子14.2 例子24.3 例子34.4 完整代码 5. References 1. 目的 用 C 语言实现直方图均…

低价618背后,看见品牌营销的「产业新洪流」

如今消费者对于低价与品质的兼得需求&#xff0c;正倒逼一个全新的产业经济模式出现&#xff0c;而企业恰是最直接承载者。只有具备真正“低价”的能力模型&#xff0c;企业才能参与到下一轮的产业经济&#xff0c;甚至是社会经济的发展浪潮中。 作者|皮爷 出品|产业家 成本不…

Elasticsearch设置密码

Elasticsearch设置密码 概述ES开启认证配置密码访问开启安全认证的EScurl浏览器直接访问Kibana 配置 es认证直接配置用户名密码到 kibana.yml以kibana密钥的形式使用命令行启动参数形式指定用户名密码 使用kibana 查看es用户 概述 ES默认没有开启安全组件&#xff0c;如果我们…

简单的Dubbo实验环境搭建

Dubbo-api中定义的UserQueryFacade接口可以发布在私服上&#xff0c;这样子dubbo-consumer和dubbo-provider就可以以maven依赖的形式导入使用。dubbo-provider需要提供接口的实现类&#xff0c;dubbo-consumer需要订阅该实现类&#xff0c;他们的元数据都通过zk进行记录。 许多…

Three.js学习项目--3D抗美援朝数据可视化

文章目录 部分场景体验地址操作说明 视频我做了哪些&#xff08;功能&#xff09;局限源代码地址部分逻辑按需渲染模型加载动画控制器模型纹理条件切换模型加载同时请求部分纹理 生成进度条模型缩放小动画 部分场景 体验地址 https://kmyc.hongbin.xyz/ 操作说明 视频 操作说…

LeetCode——查询后矩阵的和

目录 1、题目 2、题目解读 3、代码 1、题目 2718. 查询后矩阵的和 - 力扣&#xff08;Leetcode&#xff09; 给你一个整数 n 和一个下标从 0 开始的 二维数组 queries &#xff0c;其中 queries[i] [typei, indexi, vali] 。 一开始&#xff0c;给你一个下标从 0 开始的…

数学建模常用模型(一):灰色预测法

数学建模常用模型&#xff08;一&#xff09;&#xff1a;灰色预测法 灰色预测法是一种用于处理少量数据、数据质量较差或者缺乏历史数据的预测方法。它适用于一些非线性、非平稳的系统&#xff0c;尤其在短期预测和趋势分析方面有着广泛的应用。灰色预测法作为一种强大的数学…

基于STM32+OneNet设计的物联网智慧路灯

一、前言 近年来,构筑智慧城市、推动城镇发展被国家列入重要工作范畴。发布的《超级智慧城市报告》显示,全球已启动或在建的智慧城市有1000多个,中国在建500个,远超排名第二的欧洲(90个)。从在建智慧城市的分布来看,我国已初步形成环渤海、长三角、珠三角、中西部四大智…

FreeRTOS 任务优先级 【杂记】

FreeRTOS任务优先级 FreeRTOS任务优先级&#xff1a;任务优先级数值越小&#xff0c;任务优先级越低。 1、 FreeRTOS 中任务的最高优先级是通过 FreeRTOSConfig.h 文件中的configMAX_PRIORITIES 进行配置的&#xff0c;用户实际可以使用的优先级范围是 0 到 configMAX_PRIORIT…

python 第七章 字典dict {}

系列文章目录 第一章 初识python 第二章 变量 第三章 基础语句 第四章 字符串str 第五章 列表list [] 第六章 元组tuple ( ) 文章目录 字典的应用场景创建字典的语法字典常见操作增改删查 字典的循环遍历遍历字典的key遍历字典的value遍历字典的元素遍历字典的键值对&#xff0…

【新款DVR、NVR、直播、录播机单芯片解决方案】

新款DVR、NVR、直播、录播机单芯片解决方案 一、 22AP80或SS522V100是入门级DVR解决方案&#xff0c;能做到4路1080p30fps编码 2路 1080p30fps解码 多路图像分析方法智能算法&#xff1b;可以平替Hi3520DV510 二、 22AP10或SS524V100&#xff0c;这是一款中端的DVR芯片&#…

java语言中方法的多态

文章目录 前言一、多态是什么&#xff1f;二、使用步骤 1.实操展示2.注意事项总结 前言 自然界中&#xff0c;生物是多种形态的&#xff0c;繁殖这一行为也是多样的&#xff0c;细菌是裂殖&#xff0c;禽类是卵生&#xff0c;哺乳动物是胎生......java语言中的一个创建的方法&a…

Nike登录的acw_sc__v2参数逆向详细思路分析(非常简单,建议入手)含AST解混淆代码

分析目录 前言一、分析三、总结四、番外1.AST解混淆 前言 最近周末闲着无事&#xff0c;看了一下Nike的登录&#xff0c;发现连环境都不用补acw_sc__v2这个参数&#xff0c;分享出来给大家趣味性娱乐一下 一、分析 打开F12抓包看看登录 老样子复制curl给抓到Postman里面去…

Qt多线程编程之线程池

QThreadPool与QRunnable 线程的创建及销毁需要与系统交互&#xff0c;会产生很大的开销。若需要频繁的创建线程建议使用线程池&#xff0c;有线程池维护一定数量的线程&#xff0c;当需要进行多线程运算时将运算函数传递给线程池即可。线程池会根据可用线程进行任务安排。 QT…

Android studio自动登录和记住密码的实现

Android studio自动登录和记住密码的实现 文章目录 Android studio自动登录和记住密码的实现前言一、效果二、设计思路三、知识点介绍1. SharedPreferenced2. checkButton就不介绍了 四、自动登录及记住密码实现总结与补充 前言 大家好&#xff0c;我是oy&#xff0c;今天介绍…

浅层神经网络

目录 1、神经网络表示 2、计算神经网络的输出 3、多个样本的向量化 4、激活函数 5、激活函数的导数 6、神经网络的梯度下降法 1、神经网络表示 输入层&#xff1a;有输入特征&#x1d465;1、&#x1d465;2、&#x1d465;3隐藏层&#xff1a;四个结点&#xff0c;表示你…

验证性实验 - 逻辑回归

练习2&#xff1a;逻辑回归 介绍 在本练习中&#xff0c;您将实现逻辑回归并将其应用于两个不同的数据集。还将通过将正则化加入训练算法&#xff0c;来提高算法的鲁棒性&#xff0c;并用更复杂的情形来测试模型算法。 在开始练习前&#xff0c;需要下载如下的文件进行数据上…

前端Vue非常简单实用商品分类展示组件 侧边商品分类组件

前端vue非常简单实用商品分类展示组件 侧边商品分类组件 &#xff0c; 下载完整代码请访问uni-app插件市场址:https://ext.dcloud.net.cn/plugin?id13084 效果图如下&#xff1a; #### 使用方法 使用方法 <!-- flist:第一级数组 slist&#xff1a;第二级数组 tlist&…

JS 介绍 Babel 的使用及 presets plugins 的概念

一、Babel 是什么 Bebal 可以帮助我们将新 JS 语法编译为可执行且兼容旧浏览器版本的一款编译工具。 举个例子&#xff0c;ES6&#xff08;编译前&#xff09;&#xff1a; const fn () > {};ES5&#xff08;编译后&#xff09;&#xff1a; var fn function() {}二、B…

NLP实战:使用Word2vec实现文本分类

目录 一、数据预处理 1、加载数据 2. 构建词典 3.生成数据批次和迭代器 二、模型构建 1.搭建模型 2.初始化模型 3.定义训练与评估函数 三、训练模型 1. 拆分数据集并运行模型 2. 测试指定数据 &#x1f368; 本文为[&#x1f517;365天深度学习训练营]内部限免文章&…