HOG特征提取-python实现

import math

import cv2
import numpy as np
from matplotlib import pyplot as plt

filename = './positive_sample/1.jpg'
img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE)  # 灰度图像
cv2.imshow("img", img)
img1 = np.sqrt(img * 1.0 / float(np.max(img)))  # 归一化和gamma校正,取值为1.0
# cv2.imshow("img1", img1)
print(img1.shape)
cv2.namedWindow("img", 0)
cv2.waitKey(0)
# 计算梯度
height, width = img1.shape
gradient_value_x = cv2.Sobel(img1, cv2.CV_64F, 1, 0, ksize=5)  # 1代表在x方向求导
gradient_value_y = cv2.Sobel(img1, cv2.CV_64F, 0, 1, ksize=5)
gradient_magnitude = cv2.addWeighted(gradient_value_x, 0.5, gradient_value_y, 0.5, 0)  # 计算该点像素点的梯度大小和方向
gradient_angle = cv2.phase(gradient_value_x, gradient_value_y, angleInDegrees=True)
# print(gradient_magnitude.shape)
# print(gradient_angle.shape)

# 为每个细胞单元构建梯度方向直方图, 将图像分为若干个单元格cell,默认cell为8*8的像素
cell_size = 8  # cell为8*8的细胞单元
bin_size = 8  # 直方图的条形的个数
angle_unit = 360 // bin_size
gradient_magnitude = abs(gradient_magnitude)
cell_gradient_vector = np.zeros((height // cell_size, width // cell_size, bin_size))
# print(cell_gradient_vector)


# 为每个细胞单元构建梯度方向直方图,将cell梯度与bin联系在一起,将cell写到直方图中
def cell_gradient(cell_magnitude, cell_angle):  # 将同一个cell的梯度值根据分的角度值用一权重分别赋给bin_size个维度
    orientation_centers = [0] * bin_size  # 建立需填充矩阵
    for k in range(cell_magnitude.shape[0]):  # 遍历每个cell的高
        for l in range(cell_magnitude.shape[1]):  # 遍历每个cell的宽
            gradient_strength = cell_magnitude[k][l]   # 获得该位置的梯度值
            gradient_angle = cell_angle[k][l]  # 获得该位置的角度值
            min_angle = int(gradient_angle // angle_unit) % bin_size  # 找到该角度处于bin_size角度范围的最小区间
            max_angle = (min_angle + 1) % bin_size  # 找到该角度处于bin_size角度范围的最大区间
            mod = gradient_angle % angle_unit
            orientation_centers[min_angle] += (gradient_strength * (1 - (mod // angle_unit)))
            orientation_centers[max_angle] += (gradient_strength * (mod // angle_unit))
            return orientation_centers


# 计算cell的大小和方向,采集细胞单元的各个像素点的梯度值和方向
# 这里两个循环,相当于给每个cell添加了bin_size维度的特征,简单来说就是求解每个cell对应角度范围的梯度值的累加
for i in range(cell_gradient_vector.shape[0]):  # 遍历cell的高
    for j in range(cell_gradient_vector.shape[1]):  # 遍历cell的宽
        cell_magnitude = gradient_magnitude[i * cell_size: (i + 1) * cell_size, j * cell_size: (j + 1) * cell_size]
        cell_angle = gradient_angle[i * cell_size: (i + 1) * cell_size, j * cell_size: (j + 1) * cell_size]
        # print(cell_angle.max())
        cell_gradient_vector[i][j] = cell_gradient(cell_magnitude, cell_angle)  # 将cell的梯度和方向填充到先前的矩阵中

# 可视化cell的梯度直方图
hog_image = np.zeros([height, width])
cell_gradient = cell_gradient_vector
cell_width = 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 = angle_unit
        for magnitude in cell_grad:
            angle_radian = math.radians(angle)
            x1 = int(x * cell_size + magnitude * cell_width * math.cos(angle_radian))
            y1 = int(y * cell_size + magnitude * cell_width * math.sin(angle_radian))
            x2 = int(x * cell_size - magnitude * cell_width * math.cos(angle_radian))
            y2 = int(y * cell_size - magnitude * cell_width * math.sin(angle_radian))
            cv2.line(hog_image, (y1, x1), (y2, x2), int(255 * math.sqrt(magnitude)))
            angle += angle_gap
plt.imshow(hog_image, cmap=plt.cm.gray)
plt.show()


# 统计block梯度信息,把cell单元组合成更大的块,块内归一化梯度直方图
hog_vector = []
for i in range(cell_gradient_vector.shape[0] - 1):
    for j in range(cell_gradient_vector.shape[1] - 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))
        magnitue = 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)
print(np.array(hog_vector).shape)  # (4661,32),共有4661个block,每个black都有32维的特征

cv2.waitKey(0)

import math
import os
from itertools import chain

import cv2
import joblib
import numpy as np
import skimage.novice
from PIL import Image
from matplotlib import pyplot as plt
from sklearn.svm import LinearSVC


class Hog_feature_extraction():
    def __init__(self, img, cell_size=8, bin_size=8):
        self.img = img
        self.img = np.sqrt(img / float(np.max(img)))
        self.cell_size = cell_size
        self.bin_size = bin_size
        self.angle_unit = 360 // bin_size
        assert type(self.bin_size) == int, "bin_size should be integer,"
        assert type(self.cell_size) == int, "cell_size should be integer,"
        assert type(self.angle_unit) == int, "bin_size should be divisible by 360"

    # 1-计算cell梯度;3-可视化直方图;
    def caculate_block(self, img):
        gradient_value_x = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)  # 1代表在x方向求导
        gradient_value_y = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)
        gradient_magnitude = cv2.addWeighted(gradient_value_x, 0.5, gradient_value_y, 0.5, 0)  # 计算该点像素点的梯度大小和方向
        gradient_angle = cv2.phase(gradient_value_x, gradient_value_y, angleInDegrees=True)
        gradient_magnitude = abs(gradient_magnitude)
        cell_gradient_vector = np.zeros((height // self.cell_size, width // self.cell_size, self.bin_size))
        for i in range(cell_gradient_vector.shape[0]):  # 遍历cell的高
            for j in range(cell_gradient_vector.shape[1]):  # 遍历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)  # 将cell的梯度和方向填充到先前的矩阵中
        # 可视化直方图
        cell_width = self.cell_size // 2
        hog_image = np.zeros([height, width])
        max_mag = np.array(cell_gradient_vector).max()
        for x in range(cell_gradient_vector.shape[0]):
            for y in range(cell_gradient_vector.shape[1]):
                cell_grad = cell_gradient_vector[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(hog_image, (y1, x1), (y2, x2), int(255 * math.sqrt(magnitude)))
                    angle += angle_gap
        hog_vector = []
        for i in range(cell_gradient_vector.shape[0] - 1):
            for j in range(cell_gradient_vector.shape[1] - 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))
                magnitue = mag(block_vector)
                if magnitude != 0:
                    normalize = lambda block_vector, magnitude: [element // magnitude for element in block_vector]
                    block_vector = normalize(block_vector, magnitude)  # block混叠空间块归一化
                hog_vector.append(block_vector)
        return hog_image, hog_vector  # 特征描述子

    # 2-构建直方图;
    def cell_gradient(self, cell_magnitude, cell_angle):  # 将同一个cell的梯度值根据分的角度值用一权重分别赋给bin_size个维度
        orientation_centers = [0] * self.bin_size  # 建立需填充矩阵
        for k in range(cell_magnitude.shape[0]):  # 遍历每个cell的高
            for l in range(cell_magnitude.shape[1]):  # 遍历每个cell的宽
                gradient_strength = cell_magnitude[k][l]   # 获得该位置的梯度值
                gradient_angle = cell_angle[k][l]  # 获得该位置的角度值
                min_angle = int(gradient_angle // self.angle_unit) % self.bin_size  # 找到该角度处于bin_size角度范围的最小区间
                max_angle = (min_angle + 1) % self.bin_size  # 找到该角度处于bin_size角度范围的最大区间
                mod = gradient_angle % self.angle_unit
                orientation_centers[min_angle] += (gradient_strength * (1 - (mod // self.angle_unit)))
                orientation_centers[max_angle] += (gradient_strength * (mod // self.angle_unit))
                return orientation_centers



img = cv2.imread(pos_img_path, cv2.IMREAD_GRAYSCALE)
height, width = img.shape
pos_hog = Hog_feature_extraction(img, cell_size=8, bin_size=8)
hog_image, pos_hog_vector = pos_hog.caculate_block(img)  # 获取图像的hog特征,block

你可能感兴趣的:(python,计算机视觉,机器学习)