51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

方向梯度直方图算法(HOG)

HOG(Histogram of Oriented Gradients)是一种用于图像处理和计算机视觉任务的特征描述方法,它通常用于目标检测和物体识别。HOG 特征是一种用于描述图像中局部纹理和形状的特征向量,其主要思想是利用图像中局部区域的梯度信息来表示图像的特征。

Paper:http://vision.stanford.edu/teaching/cs231b_spring1213/papers/CVPR05_DalalTriggs.pdf

  1. HOG 图像特征示例 {#title-0} ========================
import cv2
from skimage.feature import hog
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')


def test():
    # (500, 500)
    image = cv2.imread('img.png')
    image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # hog_vector 特征向量用于算法训练
    # hog_image 用于可视化 HOG 特征
    hog_vector, hog_image = hog(image,
                                orientations=9,
                                pixels_per_cell=(50, 50),
                                cells_per_block=(3, 3),
                                block_norm='L2-Hys',
                                visualize=True)

    # (5184,) (5184,)
    print(hog_vector.shape, hog_vector.shape)

    plt.subplot(1, 2, 1)
    plt.axis('off')
    plt.title('Origin')
    plt.imshow(image, cmap='gray')
    plt.subplot(1, 2, 2)
    plt.axis('off')
    plt.title('HOG')
    plt.imshow(hog_image, cmap='gray')
    plt.show()

if __name__ == '__main__':
    test()

  1. HOG 特征计算过程 {#title-1} ========================

2.1 图像预处理 {#title-2}

在进行后续特征提取工作之前,一般会先进行图像的预处理工作。这部分工作包括将图像转换为灰度图、图像的归一化和 gamma 校正。

为什么需要将图像转换为灰度图?

  1. 可以消除物体颜色带来的影响,使得特征提取更加关注于形状和结构信息,有助于区分不同的物体。
  2. 图像的像素较少,可以降低图像的运算难度和复杂度,有利于更快地训练模型。

图像归一化的作用是什么?

  1. 将图像像素值除以 255 进行归一化的将像素值映射到 0 到 1 之间,使得像素值具有相同的比例,避免某些值过大或过小,使图像梯度值在一定的范围内保持稳定
  2. 归一化可以加速模型的收敛速度,并提高模型的泛化能力
  3. 需要注意的是,尽管像素值被归一化,但是归一化后的图像与原图像在视觉上并无差别,这是因为归一化过程并没有改变像素值的本质信息,只是改变了它们的表示范围和分布

gamma 校正的作用是什么?

  1. 校正亮度偏差:通过指数变换,校正图像的亮度,使得图像的亮度符合人眼的特性
  2. 提高对比度:通过改变图像的亮度分布,提高图像的对比度,使得图像的细节更加清晰
  3. gamma值越大,图像的对比度越低,图像整体显得较暗;gamma值越小,对比度越高,图像整体显得较亮

gamma 校正的计算公式如下:

  1. \(l_{out}\) 表示输出像素值
  2. \(l_{in}\) 表示输入像素值

示例代码如下:

import numpy as np
from skimage import io
import cv2
import matplotlib.pyplot as plt
import warnings
warnings.filterwarnings('ignore')


def show_image(image, index, title):
    plt.subplot(3, 2, index)
    plt.title(title)
    plt.axis('off')
    plt.imshow(image)


def test():
    image = io.imread('demo.jpg')
    show_image(image, 1, 'origin')

    # 转换为灰度图
    image = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    show_image(image, 2, 'gray')

    # 图像归一化
    image = image / 255
    show_image(image, 3, 'norm')

    # 伽马校正
    image1 = image ** 0.2
    show_image(image1, 4, 'gamma=0.2')

    image2 = image ** 0.8
    show_image(image2, 5, 'gamma=0.8')

    image3 = image ** 1.5
    show_image(image3, 6, 'gamma=1.5')

    plt.show()


if __name__ == '__main__':
    test()

2.2 计算图像梯度 {#title-3}

使用 kernel size 为 1 的 sobel 算子计算图像两个方向上的梯度,并计算幅度值和方向。

  1. θ 表示梯度方向,请注意,这里的角度θ是以弧度为单位的
  2. G 表示梯度幅值
import cv2
import numpy as np


def test():

    # np.random.seed(0)
    # 灰度图
    image = np.random.randint(0, 255, size=(4, 4), dtype=np.uint8)
    # 归一化
    image = image / 255.0

    # x 方向梯度
    gx = cv2.Sobel(image, -1, dx=1, dy=0, ksize=1)
    # y 方向梯度
    gy = cv2.Sobel(image, -1, dx=0, dy=1, ksize=1)
    # 幅度
    magnitude = np.sqrt(gx ** 2 + gy ** 2)
    # 方向
    direction = np.arctan2(gy, gx)

    print(np.degrees(direction))
    print(magnitude)

if __name__ == '__main__':
    test()

OpenCV Sobel

2.3 计算 Cell 直方图 {#title-4}

Cell 指的是我们将图像划分成一个又一个的子区域,如下图:560×400 的图像,我们以 80×80 为一个 Cell 划分成了 35 个 Cell。

计算每一个 Cell 的 x、y 方向的图像梯度,并根据梯度值计算梯度幅值、梯度方向。有了梯度幅值和方向就可以构建每一个 Cell 的方向梯度直方图了。

每个像素的方向都在 0-180 度之间,我们将这个范围划分出 9 个 bin,分别是:

0 20 40 60 80 100 120 140 160

然后,将每个像素的梯度幅值加权累计到每个 bin 中,得到直方图:

此时,原来每个 Cell 是 80×80=6400 个像素值表示,现在变成 9 个bin 对应的值的表示。

每个像素的幅度值是如何加权到不同的 bin 中的?

上图中,蓝色标注的像素的方向为 80,对应 80 的bin, 直接将其对应的幅度值添加到该 bin 中。对于红色标注像素的方向为 10,其介于 bin 0 ~ 20 之间,正好在中间位置,我们将其对应的幅度值 4 平分到 bin 0 和 bin 20 内。

2.4 标准化 Block 直方图 {#title-5}

以 Cell 为基本单位,组成一个 Block,例如:block=(2, 2) 则表示 4 个 Cell 为一个 block,如下图所示。然后通过滑动窗口的形式来标准化每一个 Block,每次滑动窗口进行标准化时,都会产生的一个 36 维度的数据,最终将所有的 36 维拼接起来得到最终的图像的 HOG 特征表示。

例如:上图中,将所有图像以滑动窗口形式标准化共需要滑动 24 次,每次产生 36 维度特征,将其展开拼接到一起就得到 24 * 36 = 864 维度的图像 HOG 特征。

用于标准化 Block 数据的方法主要有:L1-norm、L1-sqrt、L2-norm、L2-Hys,在 skimage 库中默认使用 L2-Hys 标准化方法。

这一步进行 Block 标准化的作用是可以减少光照等因素的影响,从而更好地提取图像的纹理特征。

赞(0)
未经允许不得转载:工具盒子 » 方向梯度直方图算法(HOG)