opencv 26.HOG

    Histogram of oriented gradients 简称 HoG, 是计算机视觉和图像处理领域一种非常重要的特征,被广泛地应用于物体检测,人脸检测,人脸表情检测等。

    HoG 最早是在2005 年的CVPR 上由 Navneet Dalal 和 Bill Triggs 提出来的,是一种用于表征图像局部梯度方向梯度强度分布特性的描述符。HoG 的算法很简单,对于物体的特征表示却非常有效。

HOG算法

灰度图像转换—>梯度计算与梯度方向直方图—>重叠块直方图归一化—>HOG特征

灰度图像转换

1.对于彩色图像,将RGB分量转化成灰度图像,cvtColor
其转化公式为:
G r a y = 0.3 ∗ R + 0.59 ∗ G + 0.11 ∗ B G r a y=0.3 * R+0.59 * G+0.11 * B Gray=0.3R+0.59G+0.11B
2.Gama校正
在图像照度不均匀的情况下,可以通过Gamma校正,将图像整体亮度提高或降低。在实际中可以采用两种不同的方式进行Gamma标准化,平方根、对数法。这里我们采用平方根的办法,公式如下(其中γ=0.5):

Y ( x , y ) = I ( x , y ) γ Y(x, y)=I(x, y)^{\gamma} Y(x,y)=I(x,y)γ

int main()
{
	Mat picture = imread("test.jpg", 0);//通过imread第二参数直接读入灰度图像
	Mat img;
	picture.convertTo(img, CV_32F);	//转换成浮点
	sqrt(img, img);					//gamma校正
	normalize(img, img, 0, 255, NORM_MINMAX, CV_8UC1);//归一化像素值[0,255]
	imshow("原图", picture);
	imshow("Gamma校正", img);
	waitKey(); 
	return 0;
}

在这里插入图片描述

梯度计算与梯度方向直方图

在这里插入图片描述
在这里插入图片描述
将图像划分成若干个cells(单元)8x8=64个像素为一个cell,相邻的cell之间不重叠。在每个cell内统计梯度方向直方图,将所有梯度方向划分为9个bin(即9维特征向量),作为直方图的横轴,角度范围所对应的梯度值累加值作为直方图纵轴。

Mat picture = imread("test.jpg", 0);//灰度
	Mat img;
 
	picture.convertTo(img, CV_32F);	//转换成浮点
	sqrt(img, img);					//gamma校正
	normalize(img, img, 0, 255, NORM_MINMAX, CV_32F);//归一化[0,255]浮点数
 
	Mat gradient = Mat::zeros(img.rows, img.cols, CV_32F);//梯度
	Mat theta = Mat::zeros(img.rows, img.cols, CV_32F);//角度
 
	for (int i = 1; i < img.rows - 1; i++)
	{
		for (int j = 1; j < img.cols - 1; j++)
		{
			float Gx, Gy;
 
			Gx = img.at<float>(i, j + 1) - img.at<float>(i, j - 1);
			Gy = img.at<float>(i + 1, j) - img.at<float>(i - 1, j);
 
			gradient.at<float>(i, j) = sqrt(Gx * Gx + Gy * Gy);//梯度模值
			theta.at<float>(i, j) = float(atan2(Gy, Gx) * 180 / CV_PI);//梯度方向[-180°,180°]
		}
	}
 
	normalize(gradient, gradient, 0, 255, NORM_MINMAX, CV_8UC1);//归一化[0,255] 无符号整型
	normalize(img, img, 0, 255, NORM_MINMAX, CV_8UC1);

重叠块直方图归一化

1.如果图像大小不能被8x8整除
  假设有一幅图像大小为220x310,将其划分成若干个8x8的cells,显然220÷8=27.5、310÷8=38.75不是整数,也就是说划分之后依然还有多余像素不能构成cell。处理办法是将图像缩放成能被8整除的长宽(如216x304),再划分。216÷8=27,304÷8=38,因此,216x304的图像可以得到27x38个cells,没有重叠。

Mat picture = imread("test.jpg", 0);//灰度
resize(picture, picture, cvSize(int(picture.cols / 8) * 8, int(picture.rows / 8) * 8));//转化成能被8除尽的行、列

  由于图像中光照情况和背景的变化多样,梯度值的变化范围会比较大,因而良好的特征标准化对于检测率的提高相当重要。标准化的方法多种多样,大多数的都是将celll放在block中,然后标准化每个block。

  block representaTIon, 简单来说,就是将图像进行分块, 将图像分成一块一块,每一块都可以用一个histogram 做统计,然后将每一块的histogram 连起来,形成一个长的的histogram。block representaTIon 也是局部特征提取最常用到的一种方式。

  图像分块,也有两种方式,一种是overlap,一种是non-overlap,也就是说块与块之间有重叠,或者没有重叠。在计算HoG的时候,一般都会选择overlap 的分块方式。

  以上述缩放后的图像为例,共得到27x38个cell,也就是将图像划分成了27x38个单元;将上下左右相邻的2x2个cells当做一个block整体,如下所示(为方便观察,每个颜色框故意错开了一点),黑色的8x8像素为一个cell,红、蓝、黄、粉红、绿框都是一个block,即每个框内2x2的cell组成一个block。故27x38个cell可划分成26x37个block,每个block为16x16像素。相邻block之间是有重叠的,这样有效的利用了相邻像素信息,对检测结果有很大的帮助。
在这里插入图片描述
  接下分别对每个block进行标准化,一个block内有4个cell,每个cell含9维特征向量,故每个block就由4x9=36维特征向量来表征。

在这里插入图片描述
由于L2-norm简单且在检测中效果相对较好,故一般采用它。

  经过上述对有重叠部分block的直方图归一化之后,将所有block的特征向量都组合起来,则形成26x37x36=34632维特征向量,这就是HOG特征,这个特征向量就可以用来表征整个图像了。

  实际上,在运用的时候,我们通常是选取一幅图像中的一个窗口来进行特征提取,依然以上述220X310大小图像为例,经过缩放处理后为216x304,但并不直接提取整个图像的HOG特征,而是用一个固定大小的窗口在图像上滑动,滑动的间隔为8个像素,opencv中默认的窗口大小为128x64(高128,宽64),即有(128÷8)x(64÷8)=16x8个cell,也即有15x7个block,现在提取每个窗口的HOG特征,则可得到105x36=3780维HOG特征向量。

  将这330个3780维的HOG特征当做测试样本,用支持向量机(SVM)分类器来判别出,这些窗口的HOG特征是否有行人,有行人的用矩形框标记起来。HOG行人特征及所对应的SVM分类器的参数,在opencv中已经训练好了,我们只需要得到HOG特征,然后调用SVM即可得到判别结果。

//25 HOG
void StartOp2::ImageProcess2_25()
{
	Mat src;
	src = imread("../../Images/21.jpg", 1);
	if (!src.data) {
		cout << "文件打开失败" << endl;
	}

	Mat dst, dst_gray;
	resize(src, dst, cvSize(int(src.cols / 8) * 8, int(src.rows / 8) * 8));//转化成能被8除尽的行、列
	cvtColor(dst, dst_gray, COLOR_BGR2GRAY);

	/*win_size – 检测窗大小。需要和块的大小、步长匹配。
	  block_size – 块的大小。需要和细胞大小匹配。目前只支持(16,16)的大 小。
	  block_stride – 块的步长,必须是细胞大小的整数倍。
	  cell_size – 细胞大小。目前只支持(8, 8)的大小。
	  nbins – 投票箱的个数。目前只支持每个细胞9个投票箱。
	  win_sigma – 高斯平滑窗口参数。
	  threshold_L2hys – L2-Hys归一化收缩率。
	  gamma_correction – 伽马校正预处理标志,需要或不需要。
	  nlevels – 检测窗口的最大数目。*/
	HOGDescriptor detector(Size(64,128), Size(16,16), Size(8,8), Size(8,8), 9);

	//计算的结果
	vector<float> descriptors;
	vector<Point> locations;
	detector.compute(dst_gray, descriptors, Size(8, 8), Size(0, 0), locations);
	cout << descriptors.size();

	detector.setSVMDetector(detector.getDefaultPeopleDetector());
	vector<Rect> foundLocations;
	/*mg – 源图像。只支持CV_8UC1和CV_8UC4数据类型。
	  found_locations – 检测出的物体的边缘。
      hit_threshold – 特征向量和SVM划分超平面的阀值距离。通常它为0,并应由检测器系数决定。但是,当系数被省略时,可以手动指定它。
      win_stride – 窗口步长,必须是块步长的整数倍。
      padding – 模拟参数,使得CUP能兼容。
      scale0 – 检测窗口增长参数。
      group_threshold – 调节相似性系数的阈值。检测到时,某些对象可以由许多矩形覆盖。 0表示不进行分组*/
	detector.detectMultiScale(src, foundLocations, 0, Size(8, 8), Size(32, 32), 1.05, 2);
	Mat result = src.clone();
	for (size_t t = 0; t < foundLocations.size(); t++) {
		rectangle(result, foundLocations[t], Scalar(0, 0, 255), 2, 8, 0);
	}
	namedWindow("HOG SVM Detector Demo", CV_WINDOW_AUTOSIZE);
	imshow("HOG SVM Detector Demo", result);
}

参考文章:
https://blog.csdn.net/hujingshuang/article/details/47337707/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值