0
点赞
收藏
分享

微信扫一扫

opencv 特征提取 - HOG

云岭逸人 2022-02-13 阅读 88

一、HOG特征

HOG(Histograms of Oriented Gradients)梯度方向直方图

二、HOG特征提取流程

1)灰度图像 转换(将图像看做一个x,y,z(灰度)的三维图像);


2)采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;

#if 1 // 图像增强算法 --gamma
int  Gamma = 2;
int main(int args, char* arg)
{
	Mat	src = imread("C:\\Users\\19473\\Desktop\\opencv_images\\88.jpg");
	if (!src.data)
	{
		printf("could not  load  image....\n");
	}
	imshow("原图像", src);
	// 注意点 : CV_32FC3
	Mat dst(src.size(), CV_32FC3);

	for (int i = 0; i < src.rows; i++)
	{
		for (int j = 0; j < src.cols; j++)
		{
			// 对bgr 的每个通道都进行计算
			dst.at<Vec3f>(i, j)[0] = pow(src.at<Vec3b>(i, j)[0], Gamma);
			dst.at<Vec3f>(i, j)[1] = pow(src.at<Vec3b>(i, j)[1], Gamma);
			dst.at<Vec3f>(i, j)[2] = pow(src.at<Vec3b>(i, j)[2], Gamma);
		}
	}
	// 归一化
	normalize(dst, dst, 0, 255, CV_MINMAX);

	convertScaleAbs(dst, dst);

	imshow("增强后的图像", dst);
	waitKey(0);
	return -1;
}
#endif

3)计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰

Mat non_max_supprusion(Mat  dx, Mat dy)  //传进来的是两个方向上的差分矩阵  3*3 的掩膜
{
	//边缘强度=sqrt(dx 的平方+dy 的平方) 
	Mat  edge;
	magnitude(dx, dy, edge);// 计算幅度值
	int  rows = dx.rows;
	int  cols = dy.cols;
	//边缘强度的非极大值抑制
	Mat edgemag_nonMaxSup = Mat::zeros(dx.size(), dx.type());
	// 用两个循序计算出  和梯度方向 并且转换成angleMatrix
	for (int row = 1; row < rows - 1; row++)
	{
		for (int col = 1; col < cols - 1; col++)
		{
			float x = dx.at<float>(row, col);
			float y = dx.at<float>(row, col);
			// 梯度的方向---atan2f

			float  angle = atan2f(y, x) / CV_PI * 180;
			// 当前位置的边缘强度
			float  mag = edge.at<float>(row, col);
			// 找到左右两个方向
			if (abs(angle) < 22.5 || abs(angle) > 157.5)
			{
				float  left = edge.at<float>(row, col - 1);
				float  right = edge.at<float>(row, col + 1);
				// 判断两个方向上的
				if (mag > left && mag > right) {
					edgemag_nonMaxSup.at<float>(row, col) = mag;
				}

			}
			// 左上和右下两个方向
			if ((abs(angle) >= 22.5 && abs(angle) < 67.5) || (abs(angle) < -112.5 && abs(angle) > 157.5))
			{
				float  lefttop = edge.at<float>(row - 1, col - 1);
				float  rightbottom = edge.at<float>(row + 1, col + 1);
				// 判断两个方向上的
				if (mag > lefttop && mag > rightbottom) {
					edgemag_nonMaxSup.at<float>(row, col) = mag;
				}
			}

			//  上  下 方向
			if ((abs(angle) >= 67.5 && abs(angle) <= 112.5) || (abs(angle) >= -112.5 && abs(angle) <= -67.5))
			{
				float  top = edge.at<float>(row - 1, col);
				float  down = edge.at<float>(row + 1, col);
				// 判断两个方向上的
				if (mag > top && mag > down) {
					edgemag_nonMaxSup.at<float>(row, col) = mag;
				}
			}




			//  右上  左下 方向
			if ((abs(angle) > 122.5 && abs(angle) < 157.5) || (abs(angle) > -67.5 && abs(angle) <= -22.5))
			{
				float  leftdown = edge.at<float>(row - 1, col + 1);
				float  rightup = edge.at<float>(row + 1, col - 1);
				// 判断两个方向上的
				if (mag > leftdown && mag > rightup) {
					edgemag_nonMaxSup.at<float>(row, col) = mag;
				}
			}
		}
	}
	return  edgemag_nonMaxSup;
}


4)将图像划分成小cells(例如8* 8像素 / cell); 算出每个cell的梯度大小及方向.然后将每像素的梯度方向在 区间内(无向:0-180,有向:0-360)平均分为9个bins,每个cell内的像素用幅值来表示权值,为其所在的梯度直方图进行加权投票.

 

5)统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor;  快描述籽
6)将每几个cell组成一个block(例如3 * 3个cell / block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。快描述籽归一化


7)将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor了。这个就是最终的可供分类使用的特征向量了 特征数据与检测窗口

对于大小为128×64大小的图像,采用8*8像素的sell,2×2个cell组成的16×16像素的block,采用8像素的block移动步长,这样检测窗口block的数量有((128-16)/8+1)×((64-16)/8+1)=15×7.则HOG特征描述符的维数为15×7×4×9.

8) 匹配方法

 

HOG的缺点:


速度慢,实时性差;难以处理遮挡问题

三、代码演示

int main(int args, char* arg)
{
	//目标图像
	src = imread("C:\\Users\\19473\\Desktop\\opencv_images\\153.jpg");
	if (!src.data)
	{
		printf("could not  load  image....\n");
	}
	namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);

	//namedWindow(OUT_TITLE, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_TITLE, src);
	/*
	 // 将图像重新规定大小
	resize(src, dst,Size(64,128));

	cvtColor(dst, src_gary, CV_BGR2GRAY);

	HOGDescriptor  detector(Size(64,128), Size(16,16), Size(8,8),Size(8,8),9);
	vector<float>  descripers;
	vector<Point>  locations;
	detector.compute(src_gary, descripers, Size(0,0), Size(0, 0), locations);
	printf("num  of  HOG:  %d\n", descripers.size());
	*/


	//SVM分类器 --描述子
	HOGDescriptor  hog = HOGDescriptor();
	hog.setSVMDetector(hog.getDefaultPeopleDetector());
	vector<Rect>   foundloactions;
	// 多尺度检测
	hog.detectMultiScale(src, foundloactions, 0, Size(8, 8), Size(32, 32), 1.05, 2, false);
	//若rects有嵌套,则取最外面的矩形存入rect
	for (size_t i = 0; i < foundloactions.size(); i++)
	{
		rectangle(src, foundloactions[i], Scalar(0, 0, 255), 2, 8.0);
	}

	namedWindow(OUT_TITLE, CV_WINDOW_AUTOSIZE);
	imshow(OUT_TITLE, src);
	waitKey(0);
	return 0;
}

 

 

 

 

举报

相关推荐

0 条评论