【转载自 /ppp8300885/article/details/71078555】
全部代码:
importcv2importnumpy as npimportmathimportmatplotlib.pyplot as pltclassHog_descriptor():def __init__(self, img, cell_size=16, bin_size=8):
self.img=img
self.img= np.sqrt(img /np.max(img))
self.img= img * 255self.cell_size=cell_size
self.bin_size=bin_size
self.angle_unit= 360 /self.bin_sizeassert 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"
defextract(self):
height, width=self.img.shape
gradient_magnitude, gradient_angle=self.global_gradient()
gradient_magnitude=abs(gradient_magnitude)
cell_gradient_vector= np.zeros((height / self.cell_size, width /self.cell_size, self.bin_size))for i inrange(cell_gradient_vector.shape[0]):for j in range(cell_gradient_vector.shape[1]):
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)
hog_image=self.render_gradient(np.zeros([height, width]), cell_gradient_vector)
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 invector))
magnitude=mag(block_vector)if magnitude !=0:
normalize= lambda block_vector, magnitude: [element / magnitude for element inblock_vector]
block_vector=normalize(block_vector, magnitude)
hog_vector.append(block_vector)returnhog_vector, hog_imagedefglobal_gradient(self):
gradient_values_x= cv2.Sobel(self.img, cv2.CV_64F, 1, 0, ksize=5)
gradient_values_y= cv2.Sobel(self.img, cv2.CV_64F, 0, 1, ksize=5)
gradient_magnitude= cv2.addWeighted(gradient_values_x, 0.5, gradient_values_y, 0.5, 0)
gradient_angle= cv2.phase(gradient_values_x, gradient_values_y, angleInDegrees=True)returngradient_magnitude, gradient_angledefcell_gradient(self, cell_magnitude, cell_angle):
orientation_centers= [0] *self.bin_sizefor i inrange(cell_magnitude.shape[0]):for j in range(cell_magnitude.shape[1]):
gradient_strength=cell_magnitude[i][j]
gradient_angle=cell_angle[i][j]
min_angle, max_angle, mod=self.get_closest_bins(gradient_angle)
orientation_centers[min_angle]+= (gradient_strength * (1 - (mod /self.angle_unit)))
orientation_centers[max_angle]+= (gradient_strength * (mod /self.angle_unit))returnorientation_centersdefget_closest_bins(self, gradient_angle):
idx= int(gradient_angle /self.angle_unit)
mod= gradient_angle %self.angle_unitreturn idx, (idx + 1) %self.bin_size, moddefrender_gradient(self, image, cell_gradient):
cell_width= self.cell_size / 2max_mag=np.array(cell_gradient).max()for x inrange(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=self.angle_unitfor magnitude incell_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(image, (y1, x1), (y2, x2), int(255 *math.sqrt(magnitude)))
angle+=angle_gapreturnimage
img= cv2.imread('person_037.png', cv2.IMREAD_GRAYSCALE)
hog= Hog_descriptor(img, cell_size=8, bin_size=8)
vector, image=hog.extract()printnp.array(vector).shape
plt.imshow(image, cmap=plt.cm.gray)
plt.show()
5. 结果分析
本文最终单幅图像HOG特征的求取平均时间为1.8秒,相比最初版本所需的5.4秒有个长足的改进。
相比初期的版本hog梯度特征图
可见最终版本中
能够更加有效的区分梯度显示边缘。这是因为对各个像素的梯度进行了全局归一化,并且在描绘梯度方向时加入了梯度量级的非线性映射,使得梯度方向产生明显的深浅和长度差异,更易于区分边缘,凸显明显的梯度变化。
此外在输入图像时,采用Gamma校正对输入图像进行颜色空间的标准化能够抑制噪声,使得产生的边缘更加明显,清晰。
此外改变cell的大小和直方图方向通道的效果如下:
cell_size = 10 即 16*16个像素
可以看出增大cell的size得到的特征图更加注重基本轮廓和边缘,而忽略一些细节,某种程度上降低了噪声。
当通道数目为16个方向
梯度特征图像的细节变得更加明显,方向更多。
6. 在人脸识别,物体检测中的应用
在提取完图像的HOG特征之后,可以使用SVM进行分类训练,能完成行人检测等任务。
未来工作可参考Github的行人检测项目/icsfy/Pedestrian_Detection
---------------------
作者:ppp8300885