Python 实现 HOG 算法

  • HOG 原理 - CSDN
  • HOG 原理 - 搜狐网

np.ndarray 存储 cells

import cv2
import numpy as np

np.set_printoptions(threshold=np.nan, linewidth=1000000)

# 向量长度: 9*4*7*15 = 3780
x_pixel = 128
y_pixel = 64

# 1 block = 4 cells
cell_w = 8

# block 窗口移动步长
step = 8

# 分成 8*8 cell
cell_x = int(x_pixel / cell_w)  # 128/8=16
cell_y = int(y_pixel / cell_w)  # 64/8=8


# 将 128*64 的矩阵 分成 8*8 的 cells
def div_cells(mag):
    mag_cells = np.zeros(shape=(cell_x, cell_y, cell_w, cell_w))  # 8*8 cells 一共 cell_x * cell_y 个

    # 沿 x轴 等分
    mag_x = np.split(mag, cell_x, axis=0)

    for i, l in enumerate(mag_x):
        # 沿 x轴 分割的 list 转成 ndarray 后 再沿着 y轴 等分
        mag_x[i] = np.array(l)
        mag_xy = np.split(mag_x[i], cell_y, axis=1)
        for j, l1 in enumerate(mag_xy):
            mag_xy[j] = np.array(l1)
            mag_cells[i][j] = mag_xy[j]

    return mag_cells


# mag_cell, ang_cell 都是 np.ndarray
def get_bins(mag_cell, ang_cell):
    # 直方图分为9个角度
    bin_num = 9
    bins = [0.0] * bin_num  # 创建一个长度为 bin_num 的实数 list

    offset = 20

    mag_list = mag_cell.flatten()
    ang_list = ang_cell.flatten()

    # enumerate 对 list 中每个元素加个序号
    # i 序号,ang 角度值
    for i, ang in enumerate(ang_list):
        if ang >= 180:
            ang -= 180  # 有向转无向 [0, 180]

        left_bin = int(ang / offset)

        right_bin = left_bin + 1 if left_bin != bin_num - 1 else 0

        # 对应一个 left < ang < right 求其 左右占比
        # 离左越近 占左比越高
        right_ratio = ang / offset - left_bin
        left_ration = 1 - right_ratio

        # 统计角度下的 权值 即 梯度幅值 按比划分左右
        # 求得的 bins 是 9维
        bins[left_bin] = mag_list[i] * left_ration
        bins[right_bin] = mag_list[i] * right_ratio

    return bins


def hog(img):
    gx = cv2.Sobel(img, ddepth=cv2.CV_32F, dx=1, dy=0)
    gy = cv2.Sobel(img, ddepth=cv2.CV_32F, dx=0, dy=1)

    # 幅值 角度 ndarray 类型
    mag, ang = cv2.cartToPolar(gx, gy, angleInDegrees=True)  # gx,gy 必须是实数类型
    ang = np.where(ang >= 180, ang - 180, ang)  # ang 转到[0-180)

    # 分割 mag ang 成 cells
    # 每个 cell_list 中 的 每个元素 都是一个 cell 的 二维 list
    mag_cells = div_cells(mag)
    ang_cells = div_cells(ang)

    hist = []

    # 遍历添加 一个 block 里的 4个 cells
    for x in range(cell_x - 1):  # 16
        for y in range(cell_y - 1):  # 8
            # 添加1个block里的4个cells
            hist.extend(get_bins(mag_cells[x][y], ang_cells[x][y]))
            hist.extend(get_bins(mag_cells[x][y + 1], ang_cells[x][y + 1]))
            hist.extend(get_bins(mag_cells[x + 1][y], ang_cells[x + 1][y]))  # 添加下一行的2个cell
            hist.extend(get_bins(mag_cells[x + 1][y + 1], ang_cells[x + 1][y + 1]))

    return np.array(hist)


src = cv2.imread('/Users/shuai/PycharmProjects/CatClassifier/cat1/0.jpg', flags=cv2.IMREAD_GRAYSCALE)
tmp = hog(src)
print(tmp)
print(tmp.shape)

List 存储 cells

import cv2
import numpy as np

np.set_printoptions(threshold=np.nan, linewidth=10000)

# 向量长度: 9*4*7*15 = 3780
x_pixel = 128
y_pixel = 64

# 1 block = 4 cells
cell_w = 8

# block 窗口移动步长
step = 8

# 分成 8*8 cell
cell_x = int(x_pixel / cell_w)  # 128/8=16
cell_y = int(y_pixel / cell_w)  # 64/8=8


# 将 128*64 的矩阵 分成 8*8 的 cells
def div_cells(mag):
    cell_list = []

    # 沿 x轴 等分
    mag_x = np.split(mag, cell_x, axis=0)

    for i, l in enumerate(mag_x):
        # 沿 x轴 分割的 list 转成 ndarray 后 再沿着 y轴 等分
        mag_x[i] = np.array(l)
        mag_xy = np.split(mag_x[i], cell_y, axis=1)
        for j in mag_xy:
            cell_list.append(j)

    return cell_list


def get_bins(mag_cell, ang_cell):
    # 直方图分为9个角度
    bin_num = 9
    bins = [0.0] * bin_num  # 创建一个长度为 bin_num 的实数 list

    offset = 20

    mag_list = mag_cell.flatten()
    ang_list = ang_cell.flatten()

    # enumerate 对 list 中每个元素加个序号
    # i 序号,ang 角度值
    for i, ang in enumerate(ang_list):
        if ang >= 180:
            ang -= 180  # 有向转无向 [0, 180]

        left_bin = int(ang / offset)

        right_bin = left_bin + 1 if left_bin != bin_num - 1 else 0

        # 对应一个 left < ang < right 求其 左右占比
        # 离左越近 占左比越高
        right_ratio = ang / offset - left_bin
        left_ration = 1 - right_ratio

        # 统计角度下的 权值 即 梯度幅值 按比划分左右
        # 求得的 bins 是 9维
        bins[left_bin] = mag_list[i] * left_ration
        bins[right_bin] = mag_list[i] * right_ratio

    return bins


def hog(img):
    gx = cv2.Sobel(img, ddepth=cv2.CV_32F, dx=1, dy=0)
    gy = cv2.Sobel(img, ddepth=cv2.CV_32F, dx=0, dy=1)

    # 幅值 角度 ndarray 类型
    mag, ang = cv2.cartToPolar(gx, gy, angleInDegrees=True)  # gx,gy 必须是实数类型
    ang = np.where(ang >= 180, ang - 180, ang)  # ang 转到[0-180)

    # 分割 mag ang 成 cells
    # 每个 cell_list 中 的 每个元素 都是一个 cell 的 二维 list
    mag_cells = div_cells(mag)
    ang_cells = div_cells(ang)

    hist = []

    # 遍历添加 一个 block 里的 4个 cells
    for x in range(cell_x - 1):  # 16
        for y in range(cell_y - 1):  # 8
            # 添加1个block里的4个cells
            hist.extend(get_bins(mag_cells[x], ang_cells[y]))
            hist.extend(get_bins(mag_cells[x], ang_cells[y + 1]))
            hist.extend(get_bins(mag_cells[x + cell_y], ang_cells[y]))  # 添加下一行的2个cell
            hist.extend(get_bins(mag_cells[x + cell_y], ang_cells[y + 1]))

    return hist


src = cv2.imread('/Users/shuai/PycharmProjects/CatClassifier/cat1/0.jpg', flags=cv2.IMREAD_GRAYSCALE)
tmp = hog(src)
print(tmp)
print(tmp.__len__())

你可能感兴趣的:(Python 实现 HOG 算法)