Advertisement

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)
    
  
    
    
    
    
    python
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/3SzR1O0I7drKk6lLtCGmXVgM9yus.png)
复制代码
 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
    
    
![](https://ad.itadn.com/c/weblog/blog-img/images/2025-08-18/GlDiVokt0HCLue7Sa456jXP3b8YK.png)

全部评论 (0)

还没有任何评论哟~