hog适合做行人的识别和车辆识别 对一定区域的形状描述方法
可以表示较大的形状 把图像分成一个一个小的区域的直方图
用cell做单位做直方图
计算各个像素的梯度强度和方向
用3*3的像素组成一个cell 3*3的cell组成一个block来归一化 提高亮度不变性
常用SVM分类器一起使用 进行行人分类
代码思路:
将图像分成cell为单位 例如把图像分成9*9像素的cell为单位。用sobel计算梯度大小和方向。
遍历每一个cell,一个cell可以分8类,用角度当作数组的下标,也就是分类的依据,数组的大小也就是分类的一个类的大小就是梯度的大小相加。
计算两个图的直方图的直方图距离的大小累加值
计算hog直方图函数:
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的大小。
计算两个直方图的距离
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
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
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);
这是比较关键的代码 就是动态开辟一个内存
delete[] ref_hist;
delete[] pl_hist;
delete[] bg_hist;
destroyAllWindows();
记得要释放内存!
完整代码:
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 简直一摸一样 结束实验