HOG可视化代码注解

#include  
#include 
#include 
#include 

const float PI = 3.14;
using namespace cv;
using namespace std;

// HOGDescriptor visual_imagealizer  
// adapted for arbitrary size of feature sets and training images  
Mat get_hogdescriptor_visual_image(
	Mat& origImg,
	vector<float>& descriptorValues,
	Size winSize,
	Size cellSize,
	int scaleFactor,
	double viz_factor)
{
     
	//可视化图
	Mat visual_image;
	//乘以缩放因子,这里因子是1
	resize(origImg, visual_image, Size(origImg.cols * scaleFactor, origImg.rows * scaleFactor));
	//bin:9
	int gradientBinSize = 9;
	// pi / 9,得到的是每个bin的弧度大小(20度)
	float radRangeForOneBin = PI / (float)gradientBinSize;

	// (904,600)的图,在x和y方向上各有几个cells
	int cells_in_x_dir = winSize.width / cellSize.width;//904 / 8 = 113
	int cells_in_y_dir = winSize.height / cellSize.height;// 600 / 8 = 75
	int totalnrofcells = cells_in_x_dir * cells_in_y_dir;// 113*75
	//构造gradinetStrengths为3维矩阵,大小[75][113][9], 存储每个cell 9个方向的梯度大小
	float*** gradientStrengths = new float** [cells_in_y_dir];
	//构造cellUpdateCounter为2维矩阵,大小[75][113],存储每个cell被计算梯度的次数,便于后面做平均
	int** cellUpdateCounter = new int* [cells_in_y_dir];

	/*
		构造+初始化值
	*/
	for (int y = 0; y < cells_in_y_dir; y++)
	{
     
		gradientStrengths[y] = new float* [cells_in_x_dir];
		cellUpdateCounter[y] = new int[cells_in_x_dir];
		for (int x = 0; x < cells_in_x_dir; x++)
		{
     
			gradientStrengths[y][x] = new float[gradientBinSize];
			cellUpdateCounter[y][x] = 0;

			for (int bin = 0; bin < gradientBinSize; bin++)
				gradientStrengths[y][x][bin] = 0.0;//各个方向梯度先初始化为0
		}
	}

	// blocks(16*16,stride=8)数目计算:number of blocks = number of cells - 1  
	int blocks_in_x_dir = cells_in_x_dir - 1;//112
	int blocks_in_y_dir = cells_in_y_dir - 1;//74

	// compute gradient strengths per cell  
	int descriptorDataIdx = 0;
	int cellx = 0;
	int celly = 0;

	//依次遍历每个block
	for (int blockx = 0; blockx < blocks_in_x_dir; blockx++)
	{
     
		for (int blocky = 0; blocky < blocks_in_y_dir; blocky++)
		{
     
			// 遍历每个block的4 cells
			for (int cellNr = 0; cellNr < 4; cellNr++)
			{
     
				// cell编号(由cellx和celly组成)
				int cellx = blockx;
				int celly = blocky;
				if (cellNr == 1) celly++;
				if (cellNr == 2) cellx++;
				if (cellNr == 3)
				{
     
					cellx++;
					celly++;
				}
				//每个cell的9个梯度方向计算gradient strength
				for (int bin = 0; bin < gradientBinSize; bin++)
				{
     
					float gradientStrength = descriptorValues[descriptorDataIdx];
					descriptorDataIdx++;
					gradientStrengths[celly][cellx][bin] += gradientStrength;
				} 
				//该cell被统计的次数加1,方便后面做平均
				cellUpdateCounter[celly][cellx]++;
			} 
		} 
	} 

	/*
		每个cell计算平均 gradient strengths 
	*/
	 
	for (int celly = 0; celly < cells_in_y_dir; celly++)
	{
     
		for (int cellx = 0; cellx < cells_in_x_dir; cellx++)
		{
     

			float NrUpdatesForThisCell = (float)cellUpdateCounter[celly][cellx];

			// compute average gradient strenghts for each gradient bin direction  
			for (int bin = 0; bin < gradientBinSize; bin++)
			{
     
				gradientStrengths[celly][cellx][bin] /= NrUpdatesForThisCell;
			}
		}
	}


	cout << "descriptorDataIdx = " << descriptorDataIdx << endl;//298368

	
	/*
		draw cells
		每个cell可视化
	*/
	for (int celly = 0; celly < cells_in_y_dir; celly++)
	{
     
		for (int cellx = 0; cellx < cells_in_x_dir; cellx++)
		{
     
			//cell的左上角坐标(drawX,drawY)
			int drawX = cellx * cellSize.width;//cellx*8
			int drawY = celly * cellSize.height;//celly*8
			//cell的中心点
			int mx = drawX + cellSize.width / 2;
			int my = drawY + cellSize.height / 2;
			
			//画出一个个cell框
			rectangle(visual_image,
				Point(drawX * scaleFactor, drawY * scaleFactor),
				Point((drawX + cellSize.width) * scaleFactor,(drawY + cellSize.height) * scaleFactor),
				CV_RGB(100, 100, 100),
				1);

			// draw in each cell all 9 gradient strengths  
			for (int bin = 0; bin < gradientBinSize; bin++)
			{
     
				//记录该方向的gradient strength
				float currentGradStrength = gradientStrengths[celly][cellx][bin];

				//gradient strength = 0, no line to draw
				if (currentGradStrength == 0)
					continue;

				//该方向的弧度(加上radRangeForOneBin / 2应该是为了弧度值在该弧度区间居中)
				float currRad = bin * radRangeForOneBin + radRangeForOneBin / 2;

				//计算该弧度的正弦余弦值
				float dirVecX = cos(currRad);
				float dirVecY = sin(currRad);
				float maxVecLen = cellSize.width / 2;//4
				float scale = viz_factor; // just a visual_imagealization scale, to see the lines better  

				// compute line coordinates 线的两端坐标 
				float x1 = mx - dirVecX * currentGradStrength * maxVecLen * scale;
				float y1 = my - dirVecY * currentGradStrength * maxVecLen * scale;
				float x2 = mx + dirVecX * currentGradStrength * maxVecLen * scale;
				float y2 = my + dirVecY * currentGradStrength * maxVecLen * scale;

				// draw gradient visual_imagealization  
				line(visual_image,
					Point(x1 * scaleFactor, y1 * scaleFactor),
					Point(x2 * scaleFactor, y2 * scaleFactor),
					CV_RGB(0, 255, 255),
					1);

			} // for (all bins)  

		} // for (cellx)  
	} // for (celly)  


	// don't forget to free memory allocated by helper data structures!  
	for (int y = 0; y < cells_in_y_dir; y++)
	{
     
		for (int x = 0; x < cells_in_x_dir; x++)
		{
     
			delete[] gradientStrengths[y][x];
		}
		delete[] gradientStrengths[y];
		delete[] cellUpdateCounter[y];
	}
	delete[] gradientStrengths;
	delete[] cellUpdateCounter;

	return visual_image;
}


int main()
{
     
	HOGDescriptor hog;
	hog.winSize = Size(904, 600);
	vector<float> des;
	Mat src = cv::imread("C:\\Users\\11655\\Desktop\\cHog\\MyTest_Hog\\003.jpg");
	Mat dst;
	resize(src, dst, Size(904, 600));
	imshow("src", src);
	cout << "原图src:" << src.rows << " *" << src.cols << endl;//370 600
	imshow("dst", dst);
	cout << "缩放后dst:" << dst.rows << " *" << dst.cols << endl;//600  904
	hog.compute(dst, des);
	//112*74*4*9=298368
	//112和74如何得到?16*16的block在904*600的windows上以步长为8滑动,产生112*74个16*16的blocks
	//4? 每个block内有4个固定的8*8的cells; 9? 每个cell有9个方向特征
	cout << des.size() << endl;//298368。经过hog变换
	Mat background = Mat::zeros(Size(904, 600), CV_8UC1);//单通道图

	// background: 进行可视化的底图(初始化为全0)
	// des: vector数组
	// Window size. Default value is Size(64,128).here is (904, 600)
	// Cell size. Default value is Size(8,8).
	// 缩放因子:1
	// 画图用到的一个缩放因子,为了更好的可视化
	Mat background_hog = get_hogdescriptor_visual_image(background, des, hog.winSize, hog.cellSize, 1, 2.0);
	imshow("HOG特征1", background_hog);//904*600
	imwrite("特征可视化1.jpg", background_hog);
	Mat src_hog = get_hogdescriptor_visual_image(src, des, hog.winSize, hog.cellSize, 1, 2.0);
	imshow("HOG特征2", src_hog);
	imwrite("特征可视化2.jpg", src_hog);
	waitKey();
	return 0;
}

你可能感兴趣的:(cv,opencv,可视化)