OPENCV C++(八)HOG的实现

hog适合做行人的识别和车辆识别 对一定区域的形状描述方法

可以表示较大的形状 把图像分成一个一个小的区域的直方图

用cell做单位做直方图

计算各个像素的梯度强度和方向

用3*3的像素组成一个cell 3*3的cell组成一个block来归一化 提高亮度不变性

常用SVM分类器一起使用 进行行人分类

代码思路:

将图像分成cell为单位 例如把图像分成9*9像素的cell为单位。用sobel计算梯度大小和方向。

遍历每一个cell,一个cell可以分8类,用角度当作数组的下标,也就是分类的依据,数组的大小也就是分类的一个类的大小就是梯度的大小相加。

计算两个图的直方图的直方图距离的大小累加值


计算hog直方图函数:

cpp 复制代码
int calcHOG(cv::Mat src, float* hist, int nAngle, int cellSize)
{

	int nX = src.cols / cellSize;
	int nY = src.rows / cellSize;

	int binAngle = 360 / nAngle;


	Mat gx, gy;
	Mat mag, angle;
	Sobel(src, gx, CV_32F, 1, 0, 1);
	Sobel(src, gy, CV_32F, 0, 1, 1);
	cartToPolar(gx, gy, mag, angle, true);

	
	Rect roi;
	roi.x = 0;
	roi.y = 0;
	roi.width = cellSize;
	roi.height = cellSize;


	for (int i = 0; i < nY; i++) {
		for (int j = 0; j < nX; j++) {

			Mat roiMat;
			Mat roiMag;
			Mat roiAgl;

			roi.x = j * cellSize;
			roi.y = i * cellSize;

			//赋值图像
			roiMat = src(roi);
			roiMag = mag(roi);
			roiAgl = angle(roi);

			//当前cell第一个元素在数组中的位置
			int head = (i * nX + j) * nAngle;

			for (int n = 0; n < roiMat.rows; n++) {
				for (int m = 0; m < roiMat.cols; m++) {
					//计算角度在哪个bin,通过int自动取整实现
					int pos = (int)(roiAgl.at<float>(n, m) / binAngle);
					//以像素点的值为权重
					hist[head + pos] += roiMag.at<float>(n, m);
				}
			}

		}
	}

	return 0;

}

mag梯度大小强度 angle是角度的mat

传入的参数就是:图像,直方图数组,分成几个angle类型(一般是8个),cell的大小。

计算两个直方图的距离

cpp 复制代码
float normL2(float* Hist1, float* Hist2, int size)
{
	float sum = 0;
	for (int i = 0; i < size; i++) {
		sum += (Hist1[i] - Hist2[i]) * (Hist1[i] - Hist2[i]);
	}
	sum = sqrt(sum);
	return sum;
}

第一种是自己申明数组 然后做hog

cpp 复制代码
	Mat temple = imread("hogTemplate.jpg",0);
	Mat img1 = imread("img1.jpg",0);
	Mat img2 = imread("img2.jpg",0);

	float his[3000] = { 0 };
	float his1[3000] = { 0 };
	float his2[3000] = { 0 };

	printf("%d %d\r\n",temple.cols,temple.rows);

	calcHOG(temple, his, 8, 9);
	calcHOG(img1, his1, 8, 9);
	calcHOG(img2, his2, 8, 9);
	float summ = normL2(his, his1, 3000);
	float summ2 = normL2(his, his2, 3000);
	cout << summ <<"\r\n" << endl;
	cout << "------" << endl;
	cout << summ2 <<"\r\n" << endl;
	

用动态开辟内存数组来进行hog

cpp 复制代码
	int nX = refMat.cols / blockSize;
	int nY = refMat.rows / blockSize;
	int bins = nX * nY * nAngle;
	
	float* ref_hist = new float[bins];
	memset(ref_hist, 0, sizeof(float) * bins);
	float* pl_hist = new float[bins];
	memset(pl_hist, 0, sizeof(float) * bins);
	float* bg_hist = new float[bins];
	memset(bg_hist, 0, sizeof(float) * bins);

这是比较关键的代码 就是动态开辟一个内存

cpp 复制代码
	delete[] ref_hist;
	delete[] pl_hist;
	delete[] bg_hist;
	destroyAllWindows();

记得要释放内存!

完整代码:

cpp 复制代码
	cv::Mat refMat = imread("hogTemplate.jpg");
	cv::Mat plMat = imread("img1.jpg");
	cv::Mat bgMat = imread("img2.jpg");
	int nAngle = 8;
	int blockSize = 9;
	int nX = refMat.cols / blockSize;
	int nY = refMat.rows / blockSize;
	int bins = nX * nY * nAngle;
	
	float* ref_hist = new float[bins];
	memset(ref_hist, 0, sizeof(float) * bins);
	float* pl_hist = new float[bins];
	memset(pl_hist, 0, sizeof(float) * bins);
	float* bg_hist = new float[bins];
	memset(bg_hist, 0, sizeof(float) * bins);
	int reCode = 0;
	reCode = calcHOG(refMat, ref_hist, nAngle, blockSize);
	reCode = calcHOG(plMat, pl_hist, nAngle, blockSize);
	reCode = calcHOG(bgMat, bg_hist, nAngle, blockSize);

	float dis1 = normL2(ref_hist, pl_hist, bins);
	float dis2 = normL2(ref_hist, bg_hist, bins);
	std::cout << "distance between reference and img1:" << dis1 << std::endl;
	std::cout << "distance between reference and img2:" << dis2 << std::endl;
	(dis1 <= dis2) ? (std::cout << "img1 is similar" << std::endl) : (std::cout << "img2 is similar" << std::endl);


	delete[] ref_hist;
	delete[] pl_hist;
	delete[] bg_hist;
	destroyAllWindows();


	

	return 0;
}

有没有很疑惑 为啥两种计算的方式 他们hog值不一样?

因为第一种我把他灰度化了 所以值偏低,我们现在把第二种方法的也灰度化

ok 简直一摸一样 结束实验

相关推荐
测试人社区—小叶子7 分钟前
测试开发面试高频“灵魂八问”深度解析与应答策略
网络·人工智能·测试工具·云原生·容器·面试·职场和发展
蛐蛐蜉蝣耶7 分钟前
Spring AI与MCP集成实践:构建智能应用的新方式
人工智能·微服务·java开发·spring ai·mcp
中冕—霍格沃兹软件开发测试9 分钟前
测试工具链的构建与团队协作:从工具集成到价值流动
人工智能·科技·测试工具·开源·appium·bug
serve the people13 分钟前
tensorflow 零基础吃透:SavedModel 与 RaggedTensor 的结合使用
人工智能·tensorflow·neo4j
高洁0116 分钟前
激活函数应该具有哪些特征
人工智能·python·深度学习·神经网络·transformer
全栈陈序员18 分钟前
【Python】基础语法入门(十五)——标准库精选:提升效率的内置工具箱
开发语言·人工智能·python·学习
MARS_AI_20 分钟前
大模型呼叫技术:客服行业的智能化演进与云蝠实践
人工智能·自然语言处理·交互·信息与通信·agi
RoboWizard20 分钟前
双接口移动固态硬盘兼容性怎么样?
人工智能·缓存·智能手机·电脑·金士顿
AI营销视界21 分钟前
2025年GEO与AI营销平台:谁主全球沉浮?
人工智能
美狐美颜sdk23 分钟前
美颜SDK算法工程师实践笔记:滤镜与特效模块的可维护性设计
人工智能·计算机视觉·第三方美颜sdk·视频美颜sdk·人脸美型sdk