Opencv的使用小教程4——HOG特征及其python代码实现

2023-11-13

好好学习噢!
在这里插入图片描述

hog特征是什么

HOG特征即方向梯度直方图 (Histogram of Oriented Gradient, HOG),源于2005年一篇CVPR论文,使用HOG+SVM做行人检测,由于效果良好而被广泛应用。HOG是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。

该算法能够工作的原因为:

在一副图像中,局部目标的边缘存在梯度特性,而且这个特征梯度可以很好的描述这个目标。

hog的实现步骤

在这里插入图片描述
简略版实现方法:
1、将图像分成小的连通区域,又名分为多个细胞单元。
2、然后采集细胞单元中各像素点的梯度的或边缘的方向直方图。
3、最后把这些直方图组合起来就可以构成特征描述器。

详细版实现方法:
1、灰度化。
2、采用Gamma校正法对输入图像进行颜色空间的标准化,目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;
3、计算图像每个像素的梯度,主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。
4、将图像划分成多个细胞单元
5、统计每个细胞单元的梯度直方图,获得每个细胞单元的特征描述子。
6、将每几个细胞单元组成一个块(例如3*3个细胞/块),一个块内所有细胞的特征描述子串联起来便得到该块的HOG特征描述子。
7、将图像内的所有块的HOG特征描述子串联起来就可以得到该图像的HOG特征描述子了。

梯度直方图的概念:

1、利用任意一种梯度算子,例如:sobel,laplacian等,对一个块进行卷积,计算得到每个像素点处的梯度方向和幅值。具体公式如下:
在这里插入图片描述
其中,Ix和Iy代表水平和垂直方向上的梯度值,M(x,y)代表梯度的幅度值,θ(x,y)代表梯度的方向。

2、将360度(2*PI)根据需要分割成若干个方向,例如:分割成6个方向,每个bin包含60度,整个直方图包含6维,即6个方向的特征描述子。然后根据每个像素点的梯度方向,利用双线性内插法将其幅值累加到直方图中。

python代码实现:

1、使用scikit-image库:

from skimage import feature as ft
img = cv2.imread('timg.jpg', cv2.IMREAD_GRAYSCALE)
features = ft.hog(img,orientations=6,pixels_per_cell=[20,20],cells_per_block=[2,2],visualize=True)
plt.imshow(features[1],cmap=plt.cm.gray)
plt.show()

其中:
1、image:输入图像
2、orientation: 指定块的个数。把所有的方向都转换为0°~180°内,然后按照orientation划分块,如果你选定的orientation= 6, 则bin一共有6个, 每30°有一个。
3、pixels_per_cell : 每个细胞单元的像素数, 是一个tuple类型数据,例如(20,20)
4、cell_per_block : 每个块内有多少个细胞单元, tuple类型, 例如(2,2), 意思是将block均匀划分为2x2的块。

实现效果为:
在这里插入图片描述

2、源码代码实现:

代码源自https://blog.csdn.net/ppp8300885/article/details/71078555

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

class Hog_descriptor():
    #---------------------------#
    #   初始化
    #   cell_size每个细胞单元的像素数
    #   bin_size表示把360分为多少边
    #---------------------------#
    def __init__(self, img, cell_size=16, bin_size=8):
        self.img = img
        self.img = np.sqrt(img / np.max(img))
        self.img = img * 255
        self.cell_size = cell_size
        self.bin_size = bin_size
        self.angle_unit = 360 / self.bin_size
    #---------------------------#
    #   获取hog向量和图片
    #---------------------------#
    def extract(self):
        # 获得原图的shape
        height, width = self.img.shape
        # 计算原图的梯度大小
        gradient_magnitude, gradient_angle = self.global_gradient()
        gradient_magnitude = abs(gradient_magnitude)

        # cell_gradient_vector用来保存每个细胞的梯度向量
        cell_gradient_vector = np.zeros((int(height / self.cell_size), int(width / self.cell_size), self.bin_size))
        height_cell,width_cell,_ = np.shape(cell_gradient_vector)
        #---------------------------#
        #   计算每个细胞的梯度直方图
        #---------------------------#
        for i in range(height_cell):
            for j in range(width_cell):
                # 获取这个细胞内的梯度大小
                cell_magnitude = gradient_magnitude[i * self.cell_size:(i + 1) * self.cell_size,
                                 j * self.cell_size:(j + 1) * self.cell_size]
                # 获得这个细胞内的角度大小
                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图像
        hog_image = self.render_gradient(np.zeros([height, width]), cell_gradient_vector)
        hog_vector = []
        # block为2x2
        for i in range(height_cell - 1):
            for j in range(width_cell - 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('timg.jpg', cv2.IMREAD_GRAYSCALE)
hog = Hog_descriptor(img, cell_size=20, bin_size=12)
vector, image = hog.extract()
plt.imshow(image, cmap=plt.cm.gray)
plt.show()

实现效果为:
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Opencv的使用小教程4——HOG特征及其python代码实现 的相关文章

  • 如何使用一个模型中间层的输出作为另一个模型的输入?

    我训练一个模型A并尝试使用中间层的输出name layer x 作为模型的附加输入B 我尝试像 Keras 文档一样使用中间层的输出https keras io getting started faq how can i obtain th
  • 键入的完整命令行

    我想获得输入时的完整命令行 This join sys argv 在这里不起作用 删除双引号 另外 我不想重新加入已解析和拆分的内容 有任何想法吗 你太迟了 当键入的命令到达 Python 时 您的 shell 已经发挥了它的魔力 例如 引
  • Matplotlib 图例,跨列添加项目而不是向下添加项目

    对于下面的简单绘图 有没有办法让 matplotlib 填充图例 以便它从左到右填充行 而不是第一列然后第二列 gt gt gt from pylab import gt gt gt x arange 2 pi 2 pi 0 1 gt gt
  • 类型错误:“datetime.datetime”和“str”的实例之间不支持“>”

    我是 python 日期和时间类型的新手 我有一个日期值 date 2018 11 10 10 55 31 00 00 我需要检查该日期值是否超过 90 天 我试过 from datetime import datetime from da
  • 使用 NumPy 编写一个函数来计算具有特定公差的积分

    我想编写一个自定义函数来以特定容差对表达式 python 或 lambda 函数 进行数字积分 我知道与scipy integrate quad人们可以简单地改变epsabs但我想使用 numpy 自己编写该函数 From 这篇博文 htt
  • django 模板 - 如何动态访问变量?

    假设我有一个具有以下上下文的 django 模板 data1 this is data1 data2 this is data2 data name data2 现在我知道了data name 假设它是 data2 是否可以用它来访问变量d
  • 带有 mkdocs 的本地 mathjax

    我想在无法访问互联网的计算机上使用 MathJax 和 Mkdocs 因此我不能只调用 Mathjax CDN Config mkdocs yml site name My Docs extra javascript javascripts
  • 在linux上安装python ssl模块,无需重新编译

    是否可以在已经安装了 OpenSSL 的 Linux 机器上安装 python 的 SSL 模块 而无需重新编译 python 我希望它就像复制几个文件并将它们包含在库路径中一样简单 Python版本是2 4 3 谢谢 是否可以在已经安装了
  • Django 多对多关系(类别)

    我的目标是向我的 Post 模型添加类别 我希望以后能够按不同类别 有时是多个类别 查询所有帖子 模型 py class Category models Model categories 1 red 2 blue 3 black title
  • 在 Linux 上使用多处理时,TKinter 窗口不会出现

    我想生成另一个进程来异步显示错误消息 同时应用程序的其余部分继续 我正在使用multiprocessingPython 2 6 中的模块来创建进程 我试图用以下命令显示窗口TKinter 这段代码在Windows上运行良好 但在Linux上
  • 使用 if 语句的网格网格和用户定义函数的真值不明确

    假设我有一个函数f x y 足够光滑 然而 有些值仅在有限的意义上存在 以sin x x的价值x 0只存在于极限 x gt 0 中 在一般情况下 我用一个来处理这个问题if陈述 如果我在情节中使用它meshgrid我收到一条错误消息 Val
  • Python 属性和 Swig

    我正在尝试使用 swig 为一些 C 代码创建 python 绑定 我似乎遇到了一个问题 试图从我拥有的一些访问器函数创建 python 属性 方法如下 class Player public void entity Entity enti
  • 无法使用 python rasterio、gdal 打开 jp2 (来自哨兵)

    我试图在 python 中将 jp2 栅格产品作为栅格打开 但当我们使用 raterio 和 gdal 包时没有成功 我收到此错误 RasterioIOError b4 jp2 not recognized as a supported f
  • 为什么 Collections.counter 这么慢?

    我正在尝试解决罗莎琳德的基本问题 即计算给定序列中的核苷酸 并在列表中返回结果 对于那些不熟悉生物信息学的人来说 它只是计算字符串中 4 个不同字符 A C G T 出现的次数 我期望collections Counter是最快的方法 首先
  • 如何获取分类数据的分组条形图

    I have a big dataset with information about students And I have to build a graph of dependencies between different value
  • 如何在matplotlib中调整x轴

    I have a graph like this x轴上的数据表示小时 所以我希望x轴设置为0 24 48 72 而不是现在的值 很难看到 0 100 之间的数据 fig1 plt figure ax fig1 add subplot 11
  • 无法导入QUERY_TERMS

    我正在运行一个网站Python and Django Django filters 2 1 installed Django 2 1 installed 当我运行时 我收到以下错误 importError Could not import
  • 无需访问 Internet 即可部署 Django 的简单方法?

    我拥有的是使用 Django 开发的 Intranet 站点的开发版本以及放置在 virtualenv 中的一些外部库 它运行良好 我可以在任何具有互联网连接的计算机上使用相同的参数 使用 pip 轻松设置 virtualenv 但是 不幸
  • Python:如何在不先创建整个列表的情况下计算列表的总和?

    通常我们必须 1 声明一个列表 2 使用以下方法计算该列表的总和sum 但现在我希望指定一个以 1 开头 间隔为 4 100 个元素的列表 如下所示 1 5 9 13 17 21 25 29 33 37 我不想涉及数学公式 所以 1 如何在
  • 两种 ODE 求解器之间的差异

    我想知道 两者之间有什么区别ODEINT and solve ivp用于求解微分方程 它们之间有什么优点和缺点 f1 solve ivp f 0 1 y0 y0 is the initial point f2 odeint f y0 0 1

随机推荐

  • 【后端开发】将springboot项目部署到阿里云服务器

    步骤一 拿到一台阿里云的服务器 1 到达阿里云官网 2 有账号的可以直接登录 没有账号的自己注册一个 3 找到搜索框 搜索 云服务器 4 可以购买一台 新用户可以试用 也可以进行学生认证进行免费试用 我这里选择的是 新用户试用 5 选择自己
  • sqlite工具类(不完善只有基本功能)

    提示 sqlite最好单线程操作 多线程写会冲突 单这个工具我一般用于小的程序用 所以是一个连接在重复使用没有进行保活之类操作 新增了单例的读写连接持有 通过队列解决多线程sql执行问题 新增了读线程池 保存每个线程 maven
  • 微信视频不能连接到服务器,微信无法连接到服务器

    微信的使用现在已经是很普遍了 可以通过微信和好友进行更加丰富多彩的方式联系 并且软件也是不收费的 但是在使用的过程中难免会遇到这样或是那样的问题 比如说微信无法连接到服务器这种情况也是时有发生 那么是什么原因导致的呢 要如何来解决呢 下面就
  • Flutter列表组件(ListView,GrideView)

    Flutter列表组件 ListView介绍 ListView参数列表 基本列表 垂直列表 水平列表 动态列表 ListView builder遍历数据生成列表 GrideView组件 参数说明 GrideView builder遍历数据生
  • 多维时序

    多维时序 MATLAB实现GTO CNN LSTM人工大猩猩部队优化卷积长短期记忆神经网络多变量多步时间序列预测 目录 多维时序 MATLAB实现GTO CNN LSTM人工大猩猩部队优化卷积长短期记忆神经网络多变量多步时间序列预测 预测效
  • org.apache.catalina.connector.clientAbortException:java.io.IOException: 你的主机中的软件中止了一个已建立的连接

    开始好好的 突然前端查看图片就这个样子了 127 0 0 1 sent an invalid response 但是后端不报错 前端的网络包也正常 这个错误很奇怪之后手动try catch手动打印才会显示 解决方案 本来代码是这样的 改成下
  • 思维练习题

    逻辑思维训练500题 正文前序 思维训练让你更高 更强 前 言 第一章 假设法 第二章 计算法 第三章 排除法 第四章 分析法 第五章 观察法 一个真实的假设往往可以让事实呈现眼前 让真理浮出水面 一个人如果做什么事都可以让其思维以这些假设
  • 关于GPS、惯导、视觉里程计的几个定义

    1 首先写几个定义 惯性导航系统 Inertial Navigation System INS 全球定位卫星系统 Global Navigation Satellite System GNSS GNSS 包括全球定位系统 Global Po
  • 【c++刷题】——剑指offer21.栈的压入、弹出序列

    剑指offer21 栈的压入 弹出序列 题目链接 剑指offe21 栈的压入 和弹出序列 题目描述 输入两个整数序列 第一个序列表示栈的压入顺序 请判断第二个序列是否可能为该栈的弹出顺序 假设压入栈的所有数字均不相等 例如序列1 2 3 4
  • R语言参数估计课后习题

    R语言参数估计课后习题 实在不知道参数估计该看什么了 做一下习题叭 本书是薛毅版的统计建模与R语言 第一题见这条博客https blog csdn net qq 47876527 article details 111663535 里面有写
  • JAVA--多重循环

    多重循环是循环的嵌套 即一个循环体内包含另一个完整的循环结构 外层循环控行数 内层循环控个数 冒泡排序 如果遇到相等的值不进行交换 那这种排序方式是稳定的排序方式 1 原理 比较两个相邻的元素 将值大的元素交换到右边 2 思路 依次比较相邻
  • Spring框架(二) 底层架构核心概念解析-四万字你值得一看

    感兴趣的话大家可以关注一下公众号 猿人刘先生 欢迎大家一起学习 一起进步 一起来交流吧 本篇文章将对Spring底层的一些概念做一些简单的分析 也是为了方便后续在阅读源码的时候更加的方便 BeanDefintion BeanDefintio
  • QT DICOM医疗影像转换

    时间紧任务重 直接上代码吧 1 引言 借助开源库DCMKT进行转换 2 库文件引用 include dcmtk config osconfig h include dcmtk dcmdata dctk h DcmFileFormat inc
  • 如何通过域名访问服务器里的文件,如何通过域名访问云服务器

    如何通过域名访问云服务器 内容精选 换一换 您既可以通过内网域名访问网站 也可以通过公网域名访问网站 同时 您也可以设置域名使其既支持内网解析也支持公网解析 华为云的内网DNS功能实现VPC内的内网解析 并且会将对公网域名的解析请求转发到公
  • Non-Euclidean geometry

    In mathematics non Euclidean geometry consists of two geometries based on axioms closely related to those that specify E
  • 【Windows基础】Windows基本命令学习

    查看目录帮助 查看命令帮助 命令 例如 cd 可以查看语法和作用 C Users gt cd 显示当前目录名或改变当前目录 CHDIR D drive path CHDIR CD D drive path CD 指定要改成父目录 键入 CD
  • Vue3后台管理系统(十九)路由vue-router

    前言 这一章非常重要 首先我们要思考 路由涉及到了哪些东西 它要生成URL地址与vue组件的路由关系 它要根据当前用户的角色与菜单来决定要生成哪些地址路由 它要把静态路由和后端传来的动态菜单路由结合在一起 有些路由不需要权限控制 白名单 比
  • python调用数据集mnist_MNIST数据集下载训练测试Python,mnist,pytorch

    1 下载 可以使用 train set mnist MNIST data train True download True 但是速度慢一般无法下载 官网下载也较慢 使用方法 MNIST processed test pt training
  • qt界面之设置QPushbutton的大小(代码)

    其实设置Qpushbutton的大小的方式有两种 一种是通过代码的方式 另一种就是通过UI界面的形式进行设置 一 通常比较常见的通过UI界面中来进行设置 一般默认的情况下设置如图所示 修改大小之后 如图所示 这样就固定住了大小 二 通过代码
  • Opencv的使用小教程4——HOG特征及其python代码实现

    Opencv的使用小教程4 HOG特征及其python代码实现 hog特征是什么 hog的实现步骤 梯度直方图的概念 python代码实现 1 使用scikit image库 2 源码代码实现 好好学习噢 hog特征是什么 HOG特征即方向