HOG算法的笔记与python实现
这两篇[1]【2】博客写的都非常详细。这里做个笔记记录一下。
HOG称为方向梯度直方图(Histogram of Oriented Gradient),主要是为了对图像进行特征提取。所以在传统目标检测算法中经常与SVM结合用于行人识别任务(当前都是基于深度学习来做了,毕竟效果不要太好了,并且省去了繁琐的特征检测过程)。
HOG主要是计算图像中每个像素的梯度值和梯度方向,从而来获得梯度特征,是一种特征描述子[1]。
HOG特点
1.由于计算局部直方图和归一化,所以它对图像几何的和光学的形变都能保持很好的不变性;
2.细微的动作可以被忽略而不影响检测效果。
HOG计算步骤
1.对输入图像进行灰度化
2.利用gamma校正法对图像进行颜色空间归一化;(伽玛校正就是对图像的伽玛曲线进行编辑,以对图像进行非线性色调编辑的方法,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比度效果。主要是为了降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;)
3.计算图像中每个像素的梯度大小和方向;(主要是为了捕获轮廓信息,同时进一步弱化光照的干扰)
4.将图像划分cells,计算每个cell内的梯度直方图;
5.将每几个cell组成一个block,计算每个block内的梯度特征;
6.将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征描述子;
7.将图像image内的所有block的HOG特征描述子串联起来就可以得到该image(你要检测的目标)的HOG特征描述子了。这个就是最终的可供分类使用的特征向量了【2】。

#coding:utf-8
#手敲的hog算法,跑通了,效果还行
import cv2
import numpy as np
import math
import matplotlib.pyplot as plt class Hog_descriptor():
def __init__(self, img, cell_size=16, bin_size=8):
self.img = img
self.img = np.sqrt(img / np.max(img)) # 做完归一化取根号,取值范围[0,1]
self.img = img * 255
self.cell_size = cell_size
self.bin_size = bin_size
self.angle_unit = 360 / self.bin_size def extract(self):
height, width = self.img.shape
# 计算图像的梯度大小和方向
gradient_magnitude, gradient_angle = self.global_gradient()
gradient_magnitude = abs(gradient_magnitude)
cell_gradient_vector = np.zeros((int(height / self.cell_size), int(width / self.cell_size), self.bin_size))
for i in range(cell_gradient_vector.shape[0]):
for j in range(cell_gradient_vector.shape[1]):
# cell内的梯度大小
cell_magnitude = gradient_magnitude[i * self.cell_size:(i + 1) * self.cell_size,
j * self.cell_size:(j + 1) * self.cell_size]
# cell内的梯度方向
cell_angle = gradient_angle[i * self.cell_size:(i + 1) * self.cell_size,
j * self.cell_size:(j + 1) * self.cell_size]
# 转化为梯度直方图格式
cell_gradient_vector[i][j] = self.cell_gradient(cell_magnitude, cell_angle) # 绘制梯度直方图
hog_image = self.render_gradient(np.zeros([height, width]), cell_gradient_vector) # block组合、归一化
hog_vector = []
for i in range(cell_gradient_vector.shape[0] - 1):
for j in range(cell_gradient_vector.shape[1] - 1):
block_vector = []
block_vector.extend(cell_gradient_vector[i][j])
block_vector.extend(cell_gradient_vector[i][j + 1])
block_vector.extend(cell_gradient_vector[i + 1][j])
block_vector.extend(cell_gradient_vector[i + 1][j + 1])
mag = lambda vector: math.sqrt(sum(i ** 2 for i in vector))
magnitude = mag(block_vector)
if magnitude != 0:
normalize = lambda block_vector, magnitude: [element / magnitude for element in block_vector]
block_vector = normalize(block_vector, magnitude)
hog_vector.append(block_vector)
return hog_vector, hog_image def global_gradient(self):
gradient_values_x = cv2.Sobel(self.img, cv2.CV_64F, 1, 0, ksize=5)
gradient_values_y = cv2.Sobel(self.img, cv2.CV_64F, 0, 1, ksize=5)
gradient_magnitude = cv2.addWeighted(gradient_values_x, 0.5, gradient_values_y, 0.5, 0)
gradient_angle = cv2.phase(gradient_values_x, gradient_values_y, angleInDegrees=True)
return gradient_magnitude, gradient_angle def cell_gradient(self, cell_magnitude, cell_angle):
orientation_centers = [0] * self.bin_size
for i in range(cell_magnitude.shape[0]):
for j in range(cell_magnitude.shape[1]):
gradient_strength = cell_magnitude[i][j]
gradient_angle = cell_angle[i][j]
min_angle, max_angle, mod = self.get_closest_bins(gradient_angle)
orientation_centers[min_angle] += (gradient_strength * (1 - (mod / self.angle_unit)))
orientation_centers[max_angle] += (gradient_strength * (mod / self.angle_unit))
return orientation_centers def get_closest_bins(self, gradient_angle):
idx = int(gradient_angle / self.angle_unit)
mod = gradient_angle % self.angle_unit
return idx, (idx + 1) % self.bin_size, mod def render_gradient(self, image, cell_gradient):
cell_width = self.cell_size / 2
max_mag = np.array(cell_gradient).max()
for x in range(cell_gradient.shape[0]):
for y in range(cell_gradient.shape[1]):
cell_grad = cell_gradient[x][y]
cell_grad /= max_mag
angle = 0
angle_gap = self.angle_unit
for magnitude in cell_grad:
angle_radian = math.radians(angle)
x1 = int(x * self.cell_size + magnitude * cell_width * math.cos(angle_radian))
y1 = int(y * self.cell_size + magnitude * cell_width * math.sin(angle_radian))
x2 = int(x * self.cell_size - magnitude * cell_width * math.cos(angle_radian))
y2 = int(y * self.cell_size - magnitude * cell_width * math.sin(angle_radian))
cv2.line(image, (y1, x1), (y2, x2), int(255 * math.sqrt(magnitude)))
angle += angle_gap
return image img = cv2.imread('qiao.jpg', cv2.IMREAD_GRAYSCALE)
# v2.IMREAD_COLOR:读取一副彩色图片,图片的透明度会被忽略,默认为该值,实际取值为1;
# cv2.IMREAD_GRAYSCALE:以灰度模式读取一张图片,实际取值为0
# cv2.IMREAD_UNCHANGED:加载一副彩色图像,透明度不会被忽略。
hog = Hog_descriptor(img, cell_size=8, bin_size=9)
vector, image = hog.extract() # 输出图像的特征向量shape
print(np.array(vector).shape)
plt.imshow(image, cmap=plt.cm.gray)
plt.show()
结果:
| 原图 | 特征 |
|
|
HOG算法的笔记与python实现的更多相关文章
- 笔记之Python网络数据采集
笔记之Python网络数据采集 非原创即采集 一念清净, 烈焰成池, 一念觉醒, 方登彼岸 网络数据采集, 无非就是写一个自动化程序向网络服务器请求数据, 再对数据进行解析, 提取需要的信息 通常, ...
- 机器学习经典算法具体解释及Python实现--线性回归(Linear Regression)算法
(一)认识回归 回归是统计学中最有力的工具之中的一个. 机器学习监督学习算法分为分类算法和回归算法两种,事实上就是依据类别标签分布类型为离散型.连续性而定义的. 顾名思义.分类算法用于离散型分布预測, ...
- 风变编程笔记(二)-Python爬虫精进
第0关 认识爬虫 1. 浏览器的工作原理首先,我们在浏览器输入网址(也可以叫URL),然后浏览器向服务器传达了我们想访问某个网页的需求,这个过程就叫做[请求]紧接着,服务器把你想要的网站数据发送给浏 ...
- 某科学的PID算法学习笔记
最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
- Noah的学习笔记之Python篇:命令行解析
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- Noah的学习笔记之Python篇:函数“可变长参数”
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- Noah的学习笔记之Python篇:装饰器
Noah的学习笔记之Python篇: 1.装饰器 2.函数“可变长参数” 3.命令行解析 注:本文全原创,作者:Noah Zhang (http://www.cnblogs.com/noahzn/) ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
随机推荐
- WordPress基础之基本SEO设置
基础内容,不会涉及过深,在谷歌SEO教程中会做详细的介绍,我这里只简单讲下. 1. SEO介绍 SEO,又名搜索引擎优化(Search Engine Optimization,缩写为SEO)是透过了解 ...
- [春秋云镜] Initial
[春秋云镜] Initial **整套网络环境拓扑:** 一.打进内网 开局一个ip:39.101.184.25,fscan扫一下 存在thinkphp5.0.23的漏洞,可以rce,我们 ...
- windows10使用scp命令
windows10使用scp命令 windows自带scp命令 windows上传文件到linux//使用方法:scp 源文件路径 账户@地址:目的路径scp C:\Users\zbh\Deskt ...
- 【Game】安装EA的Origin(烂橘子)平台太慢 解决办法
情况是购买了Steam上的爹5,本体下载完成之后需要安装烂橘子平台 然后发现走官方提供下载的平台根本装不上来,安装贼慢 折腾什么配置文件,改HOST都是一些乱七八糟的操作,都没说清楚这干嘛用的 解决方 ...
- 灵巧手 —— 智能仿生手 —— 人形机器人(humanoid)
产品主页: https://www.brainco.cn/#/product/brain-robotics 国内销售的一款产品,美国华人生产的,灵巧度非常高的一款仿生手产品.
- 【转载】 介绍具有代表性的CPG控制机器人
原文地址: https://www.cnblogs.com/zhaochenliang/p/10453255.html ---------------------------------------- ...
- 2023 CCPC 女生题解
gym B. 终焉之茧 \(\star\) 显然两个维度分别做 单谷函数,起始点 \(A\) 是一个端点.一个 naive 的想法是三分目标点 \(B\),但交互次数会超.二分关于 \(B\) 对称点 ...
- SPI转can芯片CSM300详解以及Linux驱动移植调试笔记
一.CSM300概述 CSM300(A)系列是一款可以支持 SPI / UART 接口的CAN模块. 1. 简介 CSM300(A)系列隔离 SPI / UART 转 CAN 模块是集成微处理器. C ...
- C#应用 - 破解注入外挂必备神器Harmony
目录 前言 1,快速开始 1.1 SomeGameClass类 1.2 Patch01类 1.3 MyPatcher类 1.4 跑起来 2,破解 2.1 类库项目 2.2 winform项目 3,注入 ...
- CD、VCD、DVD、BD 傻傻分不清楚?
CD 激光唱片(Compact Disk, CD),于 1982 年面世,最初用于存储数字音频.容量约 700 MB(80 分钟音频). 激光唱片 | 维基百科 VCD 影音光盘(Video Comp ...