HOG特征提取及应用详解

article/2025/10/29 6:43:18

HOG特征提取及应用详解

  • HOG概述
  • 应用示例

HOG概述

HOG (Histogram of Oriented Gradients),即方向梯度的直方图.它统计某个方向区间内的梯度大小(即 voting vector,投票矢量).核心思想是把每个图像模块划分为固定大小的8X8单元格, 描述梯度的幅度和方向.将每个模块对应的HOG特征描述为重要的跟踪信息,再通过Gamma去高光等处理准确提取的图像的特征信息。
即在所有的64个单元格上单独计算直方图,指定x轴设置的区间数, x轴表示梯度方向,它的范围指定为0~180°.
在这里插入图片描述
图1 梯度方向分割
计算直方图的函数代码实现

''' 
函数名称:calc_hist
功能:计算直方图
输入:
mag    幅值矩阵
angle  角度矩阵,范围在 0-180
bin_size    直方图区间大小
输出:
hist    直方图
'''
def calc_hist(mag, angle, bin_size=9):hist = np.zeros((bin_size,), dtype=np.int32)bin_step = 180 // bin_sizebins = (angle // bin_step).flatten()flat_mag = mag.flatten()for i,m in zip(bins, flat_mag):hist[i] += mreturn hist

之后计算单元格的部分:

# 将图像切成多个cellcell_size = 8bin_size = 9img_h, img_w = gray.shape[:2]cell_h, cell_w = (img_h // cell_size, img_w // cell_size)cells = np.zeros((cell_h, cell_w, bin_size), dtype=np.int32)for i in range(cell_h):cell_row = cell_size * ifor j in range(cell_w):cell_col = cell_size * jcells[i,j] = calc_hist(mag[cell_row:cell_row+cell_size, cell_col:cell_col+cell_size], angle[cell_row:cell_row+cell_size, cell_col:cell_col+cell_size], bin_size)

多个单元格组合成一个块.即图中黄色格子.每个单元格上面有一个9维的表示直方图大小的向量,那么一个块就有2X2X9=36维向量, 块就是要把每次选中的这36维向量做规范化,得到新的36维向量.
在这里插入图片描述
规范化的方法有:
在这里插入图片描述
通常使用L2-Norm,先对整个整个向量的各个元素都求平方然后求和、开根号 作为规范化因子,然后对原向量中每一个元素都除以这个规范化因子。
L2 规范化的函数实现代码:

# 归一化cells
def l2_norm(cells):block = cells.flatten().astype(np.float32)norm_factor = np.sqrt(np.sum(block**2) + 1e-6)block /= norm_factorreturn block

再利用之前得到的单元格和规范化函数就可以写块实现的操作了.

# 多个cell融合成blockblock_size = 2block_h, block_w = (cell_h-block_size+1, cell_w-block_size+1)blocks = np.zeros((block_h, block_w, block_size*block_size*bin_size), dtype=np.float32)for i in range(block_h):for j in range(block_w):blocks[i,j] = l2_norm(cells[i:i+block_size, j:j+block_size])

把这么多个 block 的 36维向量拼起来就是 HOG 特征描述子(descriptor)了,在这里来说就是把 blocks 这个 3 维的矩阵摊平,也只要一行代码:

blocks = blocks.flatten()

我把整个 HOG 的计算过程封成了一个函数,是这样的:

# 计算HOG特征
def calc_hog(gray):''' 计算梯度 '''dx = cv2.Sobel(gray, cv2.CV_16S, 1, 0)dy = cv2.Sobel(gray, cv2.CV_16S, 0, 1)sigma = 1e-3# 计算角度angle = np.int32(np.arctan(dy / (dx + sigma)) * 180 / np.pi) + 90dx = cv2.convertScaleAbs(dx)dy = cv2.convertScaleAbs(dy)# 计算梯度大小mag = cv2.addWeighted(dx, 0.5, dy, 0.5, 0)print('angle\n', angle[:8,:8])print('mag\n', mag[:8,:8])''' end of 计算梯度 '''# 将图像切成多个cellcell_size = 8bin_size = 9img_h, img_w = gray.shape[:2]cell_h, cell_w = (img_h // cell_size, img_w // cell_size)cells = np.zeros((cell_h, cell_w, bin_size), dtype=np.int32)for i in range(cell_h):cell_row = cell_size * ifor j in range(cell_w):cell_col = cell_size * jcells[i,j] = calc_hist(mag[cell_row:cell_row+cell_size, cell_col:cell_col+cell_size], angle[cell_row:cell_row+cell_size, cell_col:cell_col+cell_size], bin_size)# 多个cell融合成blockblock_size = 2block_h, block_w = (cell_h-block_size+1, cell_w-block_size+1)blocks = np.zeros((block_h, block_w, block_size*block_size*bin_size), dtype=np.float32)for i in range(block_h):for j in range(block_w):blocks[i,j] = l2_norm(cells[i:i+block_size, j:j+block_size])return blocks.flatten()

假设输入的图片是 64 x 128 的,cell 就会有 8 x 16 = 128个,block 就有 (8-2+1) x (16 - 2 + 1) = 105 个,每个 block 有 36 维向量,总共就是 105 x 36 = 3780维向量,这个向量就是对应这张图片的 HOG 特征。用其他特征得到的东西也是大同小异,都是不同大小表示不同信息的特征。

特征相当于该物体的 ID,如果同类的物体的特征很相似,我们就说这个特征至少对于该类物体的区分度很好。拿深度神经网络来说,用它做人脸识别的时候,也是输入图片,输出这么一个长长的向量,如果对于同一个人,这些产生的向量的距离很近,而对于不同人的距离则很远,就说这个神经网络精度很高,但本质的流程和这些人工设计的特征没有任何区别。
HOG检测器默认属性,RGB颜色空间,无伽马校正; [−1,0,1]梯度滤波器,无平滑;线性梯度投票在0◦–180◦中的9个方向仓中;四个8×8像素单元的16×16像素块; σ= 8像素的高斯空间窗; L2-Hys(Lowe样式修剪的L2范数)块归一化;块间​​距为8个像素(因此每个单元的覆盖率为4倍); 64×128检测窗口;线性SVM分类器。
图1总结了各种HOG参数对整体检测性能的影响。这些将在下面详细讨论。主要结论是,为了获得良好的性能,应使用精细比例的导数(基本上不进行平滑处理),多个方向框以及中等大小的,高度归一化的重叠描述符块。
图1 .有关详细信息,请参见文本。 (a)使用精细的导数比例可以显着提高性能。 (“ c-cor”是一维三次校正点导数)。 (b)增加定向箱的数量可显着提高性能,直到在0°至180°范围内间隔约9个箱。 (c)不同块归一化方案的影响(见第6.4节)。 (d)使用重叠的描述符块可将丢失率降低约5%。 (e)减少64×128检测窗口周围的16个像素边距会使性能降低约4%。 (f)使用高斯内核SVM exp(-γ?x1-x2?2)将性能提高约3%。
图1 .中 (a)使用精细的导数比例可以显着提高性能。 (“ c-cor”是一维三次校正点导数)。 (b)增加定向箱的数量可显着提高性能,直到在0°至180°范围内间隔约9个箱。 (c)不同块归一化方案的影响。 (d)使用重叠的描述符块可将丢失率降低约5%。 (e)减少64×128检测窗口周围的16个像素边距会使性能降低约4%。 (f)使用高斯内核SVM exp(-γ?x1-x2?2)将性能提高约3%。

应用示例

特征区分度:
首先要介绍一下我使用的公开数据集 INRIA Person,这是一个公开的行人数据集,里面分为正样本和负样本,正样本几乎都是直立的老外行人,负样本是一些风景图片,可以给大家看一眼,这个数据集也能从网上直接下载。
在这里插入图片描述
正样本.png
在这里插入图片描述
负样本.png
我会把所有图片缩放到高度 128 和宽度 64,因此每张图片的 HOG 特征长度是 3780,如果我把所有这些 3780 维的向量都放在 3780 维空间上去看它们的分布,可能正样本会聚集在一堆,负样本聚在另一堆,这样是最好的,但是我们没办法可视化 3780 维的空间,所以我的做法是用 PCA(主成分分析)把它们压到二维,在二维平面上去看。
核心代码是这样的,需要 sklearn 和 scipy,可以通过 pip 安装:

from sklearn.decomposition import PCA
import matplotlib.pyplot as plt# PCA 降维
pca = PCA(n_components=2, copy=True)
data_size = 500
pos_features = pca.fit_transform(pos_features[:data_size])
neg_features = pca.fit_transform(neg_features[:data_size])
# 显示
plt.plot(pos_features[:,0], pos_features[:,1], 'ro')
plt.plot(neg_features[:,0], neg_features[:,1], 'bo')
plt.show()

得到的图形是这样的:
在这里插入图片描述
蓝色点是行人,红色点是背景。
emmmm, 好像打脸了,(逃
打脸的原因可能有两个,一个是降维降太多了,二维信息不足以表达原来的 3000 多维的结构;二是我们看这个图形的角度不对 ,正所谓横看成岭侧成峰。假设这是两坨饼,红色一坨蓝色一坨,现在看起来是红色的饼叠在了蓝色的饼上面,所以正确的看法应该是,我们把红色的饼拿起来,然后从侧面去看,就会变成这样:
在这里插入图片描述
即完成了分类,线性可分.
SVM模型

from sklearn import svm# 合并特征
features = np.concatenate((pos_features[:data_size], neg_features[:data_size]))
labels = np.zeros((data_size*2,), dtype=np.int32)
labels[:data_size] = 1# SVM分类器
lin_clf = svm.LinearSVC()
lin_clf.fit(features, labels)

features 是正样本和负样本的特征合并起来的一个大矩阵,labels 表示的是每个特征对应的是什么类别,这里我设置了 1 对应行人,0 对应背景。为什么需要 labels,因为训练模型要用,训练模型跟老师教学生学习很像,我们要先给学生一吨的题,并且告诉他们背后有答案,自己对,这些题就是 features,答案就是 labels,于是他们做完对完这些题以后我们就希望他们能够举一反三,看到新的题的时候不方。lin_clf 就是 SVM模型,使用 fit 方法训练,稍等几秒就训练完了。
测试代码:

miao = cv2.imread('miao2.jpg')
miao = cv2.resize(miao, (64,128))
miao = cv2.cvtColor(miao, cv2.COLOR_BGR2GRAY)
miao_feature = calc_hog(miao)
pred_result = lin_clf.predict(np.array([miao_feature]))

结果 pred_result 当然是 1 了,如果不是我就不会放上来了。

参考链接::
https://www.jianshu.com/p/ed21c357ec12


http://chatgpt.dhexx.cn/article/I6ndl5Zy.shtml

相关文章

目标检测算法之HOG特征

HOG特征,即方向梯度直方图(Histogram of Oriented Gradient, HOG),是计算机视觉领域中用于目标检测的一种特征描述子。其通过计算图像部分区域的梯度信息,并进行统计梯度信息的直方图来构成特征向量。通常地&#xff0…

目标检测的图像特征提取之(一)HOG特征

目标检测的图像特征提取之(一)HOG特征 zouxy09qq.com http://blog.csdn.net/zouxy09 1、HOG特征: 方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描…

数据库连接池c3p0

简介 c3p0是用于创建和管理连接,利用“池”的方式复用连接减少资源开销,和其他数据源一样,也具有连接数控制、连接可靠性测试、连接泄露控制、缓存语句等功能。目前,hibernate自带的连接池就是c3p0。 本文将包含以下内容(因为篇…

springboot配置C3P0数据库连接池

一、项目基础 参考&#xff1a;Springbootmybatismysql8.0 二、依赖引入 <!--c3p0连接池--><dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency>三、配…

spring配置c3p0连接池

现在对学习spring框架里面的知识进行下记录&#xff0c;本人菜鸡一枚&#xff0c;希望看到的大神不要嘲讽我。 对spring配置c3p0连接池进行操作并使用jdbcTemplate模板进行crud操作&#xff0c;之前使用的时候是导入jar包&#xff0c;常见c3p0-config.xml文件&#xff0c;在里…

Maven下C3P0连接池配置及使用

1.在pom.xml文件中导入jar包同时不要忘记jdbc包&#xff0c;否则会报错 <dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version></dependency> <dependency><groupId…

Java使用C3P0连接池详解

什么是C3P0连接池: 开源的JDBC连接池&#xff0c;C3P0连接池是在程序操作数据库之前预先根据配置文件创建一定数量的连接&#xff0c;当线程需要时直接取走&#xff0c;缩短了创建连接的时间&#xff0c;当使用完毕后&#xff0c;释放连接后放回连接池&#xff0c;以此类推&…

C3P0连接池的配置与使用

一、连接池的作用: 连接池是将已经创建好的连接保存在池中,当有请求来时,直接获取连接池中的有效连接对数据库进行访问,省略了创建连接和销毁连接的过程。这样性能上得到了提高。 基本原理是这样的: (1)建立数据库连接池对象(服务器启动)。 (2)按照事先指定的参数…

java代码c3p0连接池配置,c3p0连接池acquireincrement属性配置详解

一、c3p0数据库连接池介绍 c3p0是应用在Java项目中企业开发中的一个常用的连接池,一般都会配合Java开发框架spring、Hibernate、Mybatis等整合使用,属于开源连接池中性能比较强劲并且受市场比较欢迎的数据库连接池。 之所以项目中会应用连接池,主要是因为我们应用JDBC操作数…

配置springboot使用c3p0连接池

为什么要使用c3p0? 使用springboot默认的数据源配置方式&#xff1a; spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://…

详解C3P0(数据库连接池)

一、基本定义 C3P0是一个开源的JDBC连接池&#xff0c;它实现了数据源与JNDI绑定&#xff0c;支持JDBC3规范和实现了JDBC2的标准扩展说明的Connection和Statement池的DataSources对象。 即将用于连接数据库的连接整合在一起形成一个随取随用的数据库连接池&#xff08;Connecti…

C3P0连接池的使用

C3P0连接池的使用 什么是连接池&#xff1f;C3P0连接池的使用什么是C3P0&#xff1f;环境准备手动配置主要步骤开始编写&#xff01; 采用配置文件的方式主要步骤开始编写&#xff01; 完整代码及运行结果 什么是连接池&#xff1f; 既然叫做池&#xff0c;那么连接池(Connect…

C3P0连接池配置文档

一、导入jar包 下载链接 二、配置文件 配置文件名称&#xff1a;c3p0-config.xml (固定) 配置文件路径&#xff1a;src (类路径) 配置文件内容&#xff1a;命名配置 <c3p0-config><!-- 命名的配置 --><named-config name"test"><!-- 连接数…

C3P0数据库连接池的配置

在pom.xml文件中导入jar包 <dependency><groupId>com.mchange</groupId><artifactId>c3p0</artifactId><version>0.9.5.2</version> </dependency> 在src目录下创建c3p0-config.xml文件 <c3p0-config><named-config …

C3P0连接池的基本配置与使用

上一期我写了一篇Druid连接池的基本配置与使用&#xff0c;今天我要介绍一下C3P0连接池的基本使用。因为是介绍基本使用&#xff0c;所以我打算用一个非常简单的java应用来教大家如何对C3P0连接池进行基本配和使用。所以你只要有jdbc和Java基础就能看懂这篇文章&#xff0c;并学…

Windows API编程(一)最基础的知识介绍:Windows编程基础

主要内容简介&#xff1a; 1. Windows 编程基础&#xff1a;开发环境和开发过程。 2. Windows事件驱动模型和消息机制。 3. Windows的资源&#xff1a;图标、光标、菜单、位图等。 4. Windows绘图&#xff1a;图形和文字的显示。 5. 对话框和控件。 6. 静态库和动态库。 …

通过一个最简单的程序入门Windows编程

一、最简单的程序 我们首先先一个最简单的Windows程序&#xff0c;功能是显示一个消息框&#xff0c;随便提示一些文字就可以了。 看一下代码&#xff1a; #include <Windows.h> int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, in…

windows编程 线程局部存储(TLS)详解

文章目录 一、基本概念二、基本使用三、例子分析&#xff1a; 总结 一、基本概念 线程局部存储&#xff08;TLS&#xff09;&#xff0c;是一种变量的存储方法&#xff0c;这个变量在它所在的线程内是全局可访问的&#xff0c;但是不能被其他线程访问到&#xff0c;这样就保持…

windows编程入门

记录一下windows编程编写一个消息框&#xff0c;算是学习windows编程的入门级程序吧 以下代码来自&#xff1a;《windows游戏编程大师技巧&#xff08;第二版&#xff09;》 #include<Windows.h> #include<windowsx.h> #include<string> #include<sstre…

Windows编程捕获特定窗口及键盘鼠标消息模拟

Windows编程捕获特定窗口及键盘鼠标消息模拟 一、简介二、使用到的API简介三、获取Windows记事本的编辑区窗口的句柄并模拟输入操作1、分析2、代码一3、代码二 四、后记 一、简介 窗口是Windows的核心组件&#xff0c;Windoows下的绝大部分应用都是利用Windows提供的原生窗口&…