HOG(Histogram of Oriented Gridients)即方向梯度直方图,是一种图像特征提取的方法。其最早由法国研究员Dalal等人在CVPR-2005上提出,通过图像局部梯度方向的分布描述图像中的物体边缘。

算法主要分为以下几个步骤:

  • 预处理
  • 计算梯度
  • 计算梯度方向直方图
  • 重叠直方图归一化
  • 获取HOG特征向量

预处理

在这一步中,可以对图像进行裁剪与缩放以及调整图像亮度,以便后续对图像处理。

例如:

  • 幂次变换
  • 对数变换

计算梯度

通过Sobel算子计算水平与竖直梯度,并计算合梯度的幅值与方向:

$$ g=\sqrt{g^2_{x}+g^2_{y}} $$

$$ \theta=\arctan\frac{g_y}{g_x} $$

因为梯度方向取绝对值,所以$\theta\in[0, \pi]$,方向相反的两个梯度会被认为是同一个。

计算梯度方向直方图

将图像划分为$n\times m$的cell,对每个cell计算方向梯度强度直方图。在这一步中,我们需要对梯度方向进行离散化,例如可以将数据分为9个深度为20的箱,从而形成一个长度为9向量。

重叠直方图归一化

将$x\times x$的cell划分为一个block,采用滑动窗口的策略,对block内每一个cell拼接而成的向量进行归一化操作。

获取HOG特征向量

在上一步中,对于每一个block,我们都得到了一个长度为$bin_{depth}\times x^2$的向量,共计$(n-1)\times(m-1)$个。将这些向量拼接起来,就得到了我们需要求的HOG特征向量


参考:

import cv2
import os
import numpy as np
from skimage import io
import matplotlib.pyplot as plt
from skimage.feature import hog
from sklearn.svm import SVC
from sklearn.metrics import precision_score,recall_score

TRAIN_COUNT = 500
TEST_COUNT = 100

def get_features(object_detect, count, test=False):
    if test:
        img_path = f"data/test_set/{object_detect}s/{object_detect}.%d.jpg"
        start = 4001
    else:
        img_path = f"data/training_set/{object_detect}s/{object_detect}.%d.jpg"
        start = 1


    if object_detect == "cat":
        labels = np.array([0 for _ in range(count)]).reshape(-1, 1)
    else:
        labels = np.array([1 for _ in range(count)]).reshape(-1, 1)


    features = list()
    for i in range(start, start+count):
        print(img_path % i)
        # 读取图片
        gray = cv2.imread(img_path % i, cv2.IMREAD_GRAYSCALE)
        # 尺寸缩放
        gray = cv2.resize(gray, (128, 128))
        # 中值滤波
        gray = cv2.medianBlur(gray, 3)
        # HOG特征提取
        hog_image = hog(gray, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(8, 8))
        features.append(hog_image.flatten())
    features = np.array(features)
    return features, labels


def get_predict_img(img_path):
    gray = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)
    # 尺寸缩放
    gray = cv2.resize(gray, (128, 128))
    # 中值滤波
    gray = cv2.medianBlur(gray, 3)
    normalised_blocks, hog_image = hog(gray, orientations=9, pixels_per_cell=( 8, 8), cells_per_block=(8, 8), visualise=True)
    return hog_image.reshape(1, -1)

cat, cat_labels  = get_features(object_detect="cat", count=TRAIN_COUNT)
dog, dog_labels = get_features(object_detect="dog", count=TRAIN_COUNT)
img = np.vstack([cat, dog])
labels = np.vstack([cat_labels, dog_labels])
res = np.hstack([img, labels])

clf = SVC(probability=True)
data = res[:, :-1]
labels = res[:, -1]
clf.fit(data, labels)


# ----------- 预测单张图片 ---------------------------------
# test_img = get_predict_img("training_set/cats/cat.38.jpg")
# pred = clf.predict(test_img)
# print(pred)
# ----------- 预测单张图片 ---------------------------------

test_cat, test_cat_labels = get_features(object_detect="cat", count=TEST_COUNT, test=True)
test_dog, test_dog_labels = get_features(object_detect="dog", count=TEST_COUNT, test=True)

test_img = np.vstack([test_cat, test_dog])
test_labels = np.vstack([test_cat_labels, test_dog_labels])

pred = clf.predict(test_img)

precision = precision_score(pred,test_labels)
recall = recall_score(pred,test_labels)
print("实际类别:",test_labels.flatten())
print("预测类别:",pred.flatten())
print(f"精准率:{precision}, 召回率:{recall}")
Last modification:June 29, 2021
博客维护不易,如果你觉得我的文章有用,请随意赞赏