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}")