HOG算法及其改进 (附代码)_hog算法代码-程序员宅基地

技术标签: 算法  学习  笔记  

1.HOG

HOG(Histogram of Oriented Gradients)是一种用于图像处理和计算机视觉中的特征提取方法。它的基本思想是将图像分成小的连通区域,计算每个区域内梯度的方向直方图,然后将这些直方图串联起来形成一个特征向量,用于图像分类和目标检测等任务。HOG特征的提取过程包括以下步骤:

  1. 图像预处理:将图像转换为灰度图像,并进行归一化处理。
  2. 计算梯度:使用Sobel算子计算图像的水平和垂直梯度。
  3. 计算梯度方向和幅值:根据水平和垂直梯度计算每个像素点的梯度方向和幅值。
  4. 划分单元格:将图像分成小的连通区域,称为单元格。
  5. 统计梯度方向直方图:对于每个单元格,统计其内部像素点的梯度方向直方图。
  6. 归一化:对于每个块(由多个单元格组成),将其内部所有直方图进行归一化处理。
  7. 拼接特征向量:将所有块内的特征向量拼接起来,形成最终的特征向量。

代码

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(R'D:\papercode\experiment\2\deep-learning-for-image-processing-master\deep-learning-for-image-processing-master\amusement_0037.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()

 2.MHOG

多尺度HOG特征是指在不同尺度下提取图像的HOG特征,以便于检测不同大小的目标物体。具体步骤如下:

  1. 对图像进行金字塔缩放,得到不同尺度的图像。
  2. 对每个尺度的图像进行颜色空间归一化,梯度计算和梯度方向直方图计算。
  3. 将每个尺度的梯度方向直方图进行插值,得到更加精细的梯度方向直方图。
  4. 将每个尺度的梯度方向直方图进行重叠块直方图归一化,得到HOG特征。

代码

import cv2
import numpy as np

# 读取图像
img = cv2.imread('test.jpg')

# 构建图像金字塔
pyramid = []
for i in range(3):
    scale = 1 / (2 ** i)
    img_scale = cv2.resize(img, None, fx=scale, fy=scale, interpolation=cv2.INTER_LINEAR)
    pyramid.append(img_scale)

# 提取HOG特征
winSize = (64, 128)
blockSize = (16, 16)
blockStride = (8, 8)
cellSize = (8, 8)
nbins = 9
hog = cv2.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nbins)

features = []
for img_scale in pyramid:
    hog_feature = hog.compute(img_scale)
    features.append(hog_feature)

# 将不同尺度的HOG特征拼接在一起
feature = np.concatenate(features, axis=0)

3. HOG-LBP

HOG(Histogram of Oriented Gradient)特征是一种用于图像处理的特征提取方法,它可以有效地描述图像的边缘和纹理信息。LBP(Local Binary Pattern)特征是一种用于图像处理的局部纹理特征描述子,它可以有效地描述图像的纹理信息。HOG-LBP特征是将HOG和LBP特征进行融合,以得到更有效的图像特征。在人体头肩检测中,HOG-LBP特征融合可以提取出更有效的人体头肩的边缘轮廓和纹理特征,从而提高检测的准确率。

代码

import cv2

# 读取图像
img = cv2.imread('test.jpg')

# 提取HOG特征
hog = cv2.HOGDescriptor()
hog_feature = hog.compute(img)

# 提取LBP特征
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
lbp = cv2.LBP()
lbp_feature = lbp.compute(gray)

# 将HOG和LBP特征进行融合
feature = cv2.hconcat([hog_feature, lbp_feature])

# 输出融合后的特征
print(feature)

4.HOG-SIFT

SIFT算法的特征点稳定性很好,而HOG算法则可以提取出图像的纹理特征。因此,将两种算法的特征结合起来可以得到更加丰富的特征描述子,提高图像识别的准确率。

代码

import cv2
import numpy as np

# 读取图像
img = cv2.imread('image.jpg')

# 初始化SIFT特征提取器
sift = cv2.xfeatures2d.SIFT_create()

# 提取SIFT特征点和描述子
kp, des = sift.detectAndCompute(img, None)

# 初始化HOG特征提取器
hog = cv2.HOGDescriptor()

# 计算HOG特征
hist = hog.compute(img)

# 将SIFT和HOG特征描述子拼接在一起
features = np.concatenate((des, hist), axis=1)

# 输出特征向量的维度
print(features.shape)

5.HOG-PCA

HOG-PCA特征是一种常用的图像特征提取方法,主要用于目标检测和识别。其主要步骤如下:

1.方向梯度直方图(HOG)特征提取:将图像分成小的单元格,计算每个单元格内像素的梯度方向和大小,然后将其投影到一个直方图中,得到每个单元格的特征向量。

2.特征白化:对特征向量进行白化处理,即将其转换为零均值和单位方差。

3.尺度统一:对特征向量进行随机下采样,使其具有相同的尺度。

4.主成分分析(PCA)特征映射:将特征向量映射到一个低维空间中,以减少特征向量的维度。

5.最近邻分类:使用最小二阶范数判定进行最近邻分类,即将待分类的特征向量与训练集中的特征向量进行比较,找到最相似的特征向量,并将其分类标签作为待分类样本的标签。

代码

import cv2
import numpy as np

# 读取图像
img = cv2.imread('test.jpg')

# HOG特征提取
winSize = (64, 128)
blockSize = (16, 16)
blockStride = (8, 8)
cellSize = (8, 8)
nbins = 9
hog = cv2.HOGDescriptor(winSize, blockSize, blockStride, cellSize, nbins)
features = hog.compute(img)

# 特征白化
mean, std = cv2.meanStdDev(features)
features -= mean
features /= std

# 尺度统一
features = cv2.resize(features, (64, 128))

# PCA特征映射
pca = cv2.PCA(features, cv2.PCA_DATA_AS_ROW)
features = pca.project(features)

# 最近邻分类
trainData = np.load('trainData.npy')
labels = np.load('labels.npy')
knn = cv2.ml.KNearest_create()
knn.train(trainData, cv2.ml.ROW_SAMPLE, labels)
ret, result, neighbours, dist = knn.findNearest(features, 1)

# 输出分类结果
print('分类结果:', result[0][0])

参考:

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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/PLANTTHESON/article/details/134841951

智能推荐

markdown插入图片_markdom 插图-程序员宅基地

文章浏览阅读83次。markdown插入图片注意事项在markdown插入图片,光标要放在最前面,要不插入的图片不显示_markdom 插图

[WinError 127] 找不到指定的程序。 Error loading “D:\A\lib\site-packages\torch\lib\c10_cuda.dill_error loading "d:\anaconda\lib\site-packages\torch-程序员宅基地

文章浏览阅读7k次,点赞5次,收藏9次。可以参考一下几种解决方法:1、可能由于缺少VC++ Redistributable,在错误中会提示你下载并且提供了下载地址,只需要下载并默认安装即可;2、方法1如果不行,可以更新numpy;参考这个连接3、或者使用pip install intel-openmp,试试,参考这个连接。..._error loading "d:\anaconda\lib\site-packages\torch\lib\c10_cuda.dll" or one

BIOS的基本概念和理解_bios硬件的软件抽象-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏11次。1.基本概念BIOS(Basic Input/Output System)基本输入输出系统。是一种业界标准的固件接口;BIOS是个人电脑启动时候加载的第一个软件;BIOS用于电脑开机时,运行系统各部分的自我检测,并加载引导程序或存储在主存上的作业系统;BIOS向作业系统提供一些系统参数;系统硬件的变化是由BIOS隐藏,程序使用BIOS功能而不是直接控制硬件。现代作业系统会忽_bios硬件的软件抽象

Rockchip之RK3288HDMI接口插拔检测_hpd脚-程序员宅基地

文章浏览阅读5.3k次,点赞11次,收藏29次。Rockchip之RK3288HDMI接口插拔检测任务背景:最近机器的一块屏出现不显示或者白屏现象,这块屏是一块MIPI屏,但它是由3288上的HDMI接口通过一块LPC转接板转成MIPI接口的,所以根源还是HDMI接口,猜想可能是HDMI转MIPI的HDMI插拔检测脚导致的,因此,试着把这个插入检测去掉让HDMI信号直接输出看看结果,首先查看原理图检测脚为HDMI_HPD这个脚,首先介绍..._hpd脚

使用PyQt的QTableWidget来创建表格,并通过设置委托实现选中某个单元格时的背景颜色变化是一种常见的需求。在本文中,我将为您提供详细的代码示例和解释。_pyqt5 tablewidget 设置单元格颜色-程序员宅基地

文章浏览阅读203次。使用PyQt的QTableWidget来创建表格,并通过设置委托实现选中某个单元格时的背景颜色变化是一种常见的需求。在本文中,我将为您提供详细的代码示例和解释。接下来,我们使用双重循环创建了一些示例数据,并将其设置为表格的单元格项。最后,我们将表格设置为主窗口的中央部件,并显示主窗口。接下来,我们将创建一个简单的PyQt应用程序,并在其中添加一个QTableWidget。在上述代码中,我们首先导入了所需的类和模块。方法中,我们检查选中状态,并根据需要设置单元格的背景颜色。实例,并设置了行数和列数。_pyqt5 tablewidget 设置单元格颜色

DPDK — 安装部署(Ubuntu 18.04)_dpdk安装部署-程序员宅基地

文章浏览阅读1.5k次,点赞2次,收藏2次。目录文章目录目录环境参数环境依赖准备安装 DPDK测试附 1:Enable pcap环境参数Intel x86Ubuntu 18.04 LTSPython 3.6DPDK 18.08NICs virtio controller环境依赖准备# 自动解决必要依赖包安装的工具sudo apt-get install build-essential# 更新系统sudo apt-get update -y && sudo apt-get upgrade -y# Kerne_dpdk安装部署

随便推点

文献检索与应用_试述常用的二种医学专业搜索引擎的特色与检索方法?-程序员宅基地

文章浏览阅读3.8k次。信息检索的方法有多种,分别使用于不同的检索目的和检索要求。归纳起来,常用的信息检索方法有常规检索法、回溯检索法、循环检索法。1.常规检索法。又称常用检索法、工具检索法。它以主题、分类、作者等为检索点,利用检索工具获的信息资源的方法。根据检索方式,常规检索法又分为直接检索法和间接检索法;根据检索需求,常规检索法又分为顺查法、倒查法和抽查法。_试述常用的二种医学专业搜索引擎的特色与检索方法?

知识图谱基本概念&工程落地常见问题-程序员宅基地

文章浏览阅读1.1k次。作者:cavities来源:https://zhuanlan.zhihu.com/p/62824358编辑:happyGirl简要说明一下,搞了知识图谱架构一年半,快两年的一些小心得,后..._图谱能做到哪些知关系据库做不到的

关于unity中的update、Lateupdate和FixedUpdate。_unitylateupdate-程序员宅基地

文章浏览阅读1k次。MonoBehaviour.Update 更新 当MonoBehaviour启用时,其Update在每一帧被调用。 MonoBehaviour.FixedUpdate固定更新 当MonoBehaviour启用时,其 FixedUpdate在每一帧被调用。 处理Rigidbody时,需要用FixedUpdate代替Upd_unitylateupdate

PL/SQL Developer连接本地Oracle 11g 64位数据库_oracle11gr2 plsql dev-程序员宅基地

文章浏览阅读283次。登陆PL/SQL假定本地电脑中已经安装了Oracle 11gR2数据库和PL/SQL developer。如果没有安装可以在一下地址下载安装:Oracle 11gR2数据库:https://www.oracle.com/technetwork/database/enterprise-edition/downloads/112010-win64soft-094461.htmlPL/SQL developer(含注册机):https://pan.baidu.com/s/1kUfY8GB 密码: 1ky8_oracle11gr2 plsql dev

HDOJ1015-Safecracker优化版_safecracker hdoj-程序员宅基地

文章浏览阅读125次。纯暴力搜索是可以过的。但要求答案是最大的字典序,显然先排序后搜索可以一遍求出答案后就返回。但新手写回溯会出种种bug,最经典莫过于不知道如何返回而陷入死循环。这里给出一个参考代码:#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<map>#include<queue>#include<string>_safecracker hdoj

蓝桥试题 算法提高 书院主持人 JAVA_蓝桥杯试题 算法提高 书院主持人java-程序员宅基地

文章浏览阅读4.5k次。问题描述  北大附中书院有m个同学,他们每次都很民主地决策很多事情。按罗伯特议事规则,需要一个主持人。同学们民主意识强,积极性高,都想做主持人,当然主持人只有一人。为了选出主持人,他们想到了一个办法并认为很民主。方法是:  大家围成一圈,从1到m为每个同学编号。然后从1开始报数, 数到n的出局。剩下的同学从下位开始再从1开始报数。最后剩下来的就是主持人了。现在已经把同学从1到m编号,并约定报数..._蓝桥杯试题 算法提高 书院主持人java

推荐文章

热门文章

相关标签