图像处理之HOG特征提取

图像处理之HOG特征提取算法

HOG(Histogram of Oriented Gradient)特征在对象识别与模式匹配中是一种常见的特征提取算法,是基于本地像素块进行特征直方图提取的一种算法,对象局部的变形与光照影响有很好的稳定性,最初是用HOG特征来来识别人像,通过HOG特征提取+SVM训练,可以得到很好的效果,OpenCV已经有了。HOG特征提取的大致流程如下:


第一步:

Gamma校正,主要是对输入图像进行校正,主要是为了补偿显示器带来的灰度偏差。常见的系数在2.5左右,这个方面的资料非常多。ImageJ的源代码中也有Gamma校正的实现,可以参照。

第二步:

图像转灰度,这个也属于常见操作了。

第三步:

计算图像的梯度与方向,可以使用SOBEL算子实现,最终得到图像的梯度振幅与角度。


第四步:

将图像划分为8x8的小网格,对每个小网格内的图像做梯度方向直方图,每个8x8=64个像素为一个CELL,对每个CELL根据角度分为9个直方图块(BIN),每个BIN的范围是20度。假设在CELL的某个像素点的角度是10,则把他对应的梯度值累加放到第一个编号是0的直方图中,最终得到编号是0~8的各个直方图的数据。这样做的一个不好的地方是,没有精准反应出来梯度权重对相邻直方图的影响,得到直方图也不是反锯齿的数据,所以一个刚好的方法,是根据角度的值,计算对应像素的梯度在左右相邻直方图上的权重,根据权重累加相应的值到相邻的直方图中。这样就完成了HOG中最重要的一步,权重角度直方图数据统计。CELL网格分割图如下:


得到对应的直方图如下:


角度直方图的编号与角度范围。


五:块描述子

将2x2的网格单元组合成为一个大的块(Block)对每个块之间有1/2部分是重叠区域。主要是将每个Cell的直方图合并为一个大的直方图向量,这样每个块就有36个向量描述子。对每个块的描述子做归一化处理,常见的归一化处理为L2-norm或者L1-norm,公式如下:


这样就得到每个块的描述子,对一个对象特征来说块可以是矩形的也可以是圆形的,根据要提取对象特征决定。得到特征之后,在目标图像上以一个CELL大小为步长,检测目标图像上是否有匹配的对象特征,对象特征匹配可以基于相似度,最常见的是欧几里得距离与巴斯系数。


举例:

对于64x128的像素块,可以分为8x16个Cell分为7x15个块(R-HOG) 总计的直方图向量数为:7x15x2x2x9 = 3780个向量


关键部分的代码实现:

public static List<HOGBlock> extract(byte[] gradient, int[] orientation, int width, int height) {

		// cell histograms
		int step = 8;
		int index = 0;
		int numRowBins = height / step;
		int numColBins = width / step;
		int binindex = 0, theta=0, gw = 0;
		float ww=0, wn=0, wp=0;
		HOGCell[][] cells = new HOGCell[numRowBins][numColBins];
		for (int row = 0; row < height; row += step) {
			for (int col = 0; col < width; col += step) {
				int roffset = 0, coffset = 0;
				cells[row / step][col / step] = new HOGCell();
				cells[row / step][col / step].row = row;
				cells[row / step][col / step].col = col;
				cells[row / step][col / step].bins = new double[9];
				for (int y = 0; y < step; y++) {
					for (int x = 0; x < step; x++) {
						roffset = y + row;
						if (roffset >= height) {
							roffset = 0;
						}
						coffset = x + col;
						if (coffset >= width) {
							coffset = 0;
						}
						index = roffset * width + coffset;
						theta = orientation[index];
						// 计算权重梯度,一次双线性插值
						ww = theta % 20;
						if(ww >= 10) {
							wn = ww - 10;
							wp = (20-wn) / 20.0f;
						}
						else {
							wn = 10 - ww;
							wp = (20-wn) / 20.0f;
						}
						
						// 获取方向
						binindex = theta / 20;
						if (binindex >= 9) {
							binindex = 8;
						}
						
						// 权重梯度值累加, 反锯齿
						gw = (gradient[index]&0xff);
						if(ww >=10) {
							cells[row / step][col / step].bins[binindex] += (wp*gw); 
							if(binindex < 8) {
								cells[row / step][col / step].bins[binindex+1] += ((1.0-wp)*gw);
							}
						}
						else {
							cells[row / step][col / step].bins[binindex] += (wp*gw);
							if(binindex > 0) {
								cells[row / step][col / step].bins[binindex-1] += ((1.0-wp)*gw);
							}
						}
					}
				}
			}
		}

		// merge as blocks for 2x2 cells, if cells less than 2x2 cells, just one
		// block
		index = 0;
		List<HOGBlock> blocks = new ArrayList<HOGBlock>();
		for (int i = 0; i < numRowBins - 1; i++) {
			for (int j = 0; j < numColBins - 1; j++) {
				int cellxoff = j + 1;
				int cellyoff = i + 1;
				if (cellxoff >= numColBins) {
					cellxoff = 0;
				}
				if (cellyoff >= numRowBins) {
					cellyoff = 0;
				}
				// 2x2
				HOGCell cell1 = cells[i][j];
				HOGCell cell2 = cells[i][cellxoff];
				HOGCell cell3 = cells[cellyoff][j];
				HOGCell cell4 = cells[cellyoff][cellxoff];
				HOGBlock block = new HOGBlock();
				block.vector = generateBlockVector(cell1, cell2, cell3, cell4);
				block.width = 2;
				block.height = 2;
				block.xpos = cell1.col;
				block.ypos = cell1.row;
				block.bindex = index;
				blocks.add(index, block);
				index++;
			}
		}

		// Block 归一化
		for (HOGBlock cellsBlock : blocks) {
			blockL1SquareNorm(cellsBlock);
		}

		return blocks;
	}

  • 9
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
好的,我可以帮助您用 OpenCV 编写一个图像处理程序来提取 HOG(方向梯度直方图)特征。 HOG 特征是一种用于对象检测的特征描述符,它被广泛应用于人脸识别、行人检测等领域。 以下是用 OpenCV 实现 HOG 特征提取的一些步骤: 1. 加载图像并转为灰度图像 ```python import cv2 # 加载图像 image = cv2.imread("input_image.jpg") # 转为灰度图像 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) ``` 2. 计算梯度幅值和方向 ```python # 计算梯度幅值和方向 gx = cv2.Sobel(gray, cv2.CV_32F, 1, 0) gy = cv2.Sobel(gray, cv2.CV_32F, 0, 1) magnitude, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True) ``` 3. 划分图像为 cell,并计算每个 cell 内的方向直方图 ```python # 划分图像为 8x8 的 cell cell_size = (8, 8) blocks_per_cell = (1, 1) cells_per_block = (2, 2) # 计算每个 cell 内的方向直方图 histogram = cv2.HOGDescriptor( _winSize=(gray.shape[1] // cell_size[1] * cell_size[1], gray.shape[0] // cell_size[0] * cell_size[0]), _blockSize=(cell_size[1] * cells_per_block[1], cell_size[0] * cells_per_block[0]), _blockStride=(cell_size[1], cell_size[0]), _cellSize=(cell_size[1], cell_size[0]), _nbins=9).compute(gray) ``` 4. 将所有 cell 的方向直方图串联起来,形成最终的 HOG 特征描述符 ```python # 将所有 cell 的方向直方图串联起来 features = [] for i in range(histogram.shape[0] - cells_per_block[0] + 1): for j in range(histogram.shape[1] - cells_per_block[1] + 1): block_feature = [] for k in range(cells_per_block[0]): for l in range(cells_per_block[1]): cell_feature = histogram[i + k, j + l, :] block_feature.extend(cell_feature) norm = np.sqrt(np.sum(np.array(block_feature)**2) + 1e-6) block_feature = [ele / norm for ele in block_feature] features.extend(block_feature) # 形成最终的 HOG 特征描述符 hog_descriptor = np.array(features) ``` 以上是用 OpenCV 编写的 HOG 特征提取程序的基本过程,您可以在此基础上进行更详细的定制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gloomyfish

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值