Opencv之HOG特征与SVM相结合的人体检测(增加自举法)

Hello~洛基在上一篇关于人体检测的文章末尾提到了自举法,这里科普一下,所谓自举法,即在一个容量为n的原始样本中重复抽取一系列容量也是n的随机样本,并保证每次抽样中每一样本观察值被抽取的概率都为1/n。好像不是很通俗易懂,说人话就是——应用于行人检测中的自举方法是,对于训练好的HOG检测器,将原来进行训练的负样本当做检测样本,利用检测器进行检测,检测出来的图像必定是不包含人体的样本,这些不包含人体的样本集合便成为了自举训练样本,将自举训练样本处理之后重新作为负样本,输入到SVM中进行再一次训练,如此一来得到的检测器会“进化”为错检率更低的进化版检测器。

Of course,自举训练可以进行多次,这样分类的效果可能会更好,不过也不排除,在进行了多次自举训练之后,检测器出现大量漏检情况哦- -所以自举训练的次数,可能并不是越多越好,这是我在进行试验的小总结(认真脸)。

Okay进入正题,也就是代码部分。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;
using namespace cv;

#define str "E:\\INRIAPerson\\HardExample\\"
int hardExampleCount = 0;

//因为在生成setSVMDetector中用到的检测子参数时要用到训练好的SVM的decision_func的protected类型参数alpha和rho,故只能通过继承之后利用函数访问了
class MySVM : public CvSVM
{
	public:
		//获得SVM的决策函数中的alpha数组
		double * get_alpha_vector()
		{
			return this->decision_func->alpha;
		}

		//获得SVM的决策函数中的rho参数,即偏移量
		float get_rho()
		{
			return this->decision_func->rho;
		}
};

int main()
{
	Mat src;
	char saveName[256];//剪裁出来的hard example图片的文件名
	string ImgName;
	//ifstream fin_detector("HOGDetectorParagram.txt");
	ifstream fin_imgList("neg.txt");//打开原始负样本图片文件列表
        //每次在载入计算好的HOG描述子,然后设置SVM检测器时,都会报错——Assertion failed checkDetectorSize。令人抓狂的一个错误
        //于是只能每次都重新根据训练好的SVM.xml,计算HOG描述子,然后再设置SVM检测器了。这个问题留到后面再解决!

	cout<<"载入训练好的SVM分类器"<(i,j) = pSVData[j];//第i个向量的第j维数据
	}

	//将alpha向量的数据复制到alphaMat中
	//double * pAlphaData = svm.get_alpha_vector();//返回SVM的决策函数中的alpha向量
	double * pAlphaData = svm.get_alpha_vector();
	for(int i=0; i(0,i) = pAlphaData[i];//alpha向量,长度等于支持向量个数
	}

	//计算-(alphaMat * supportVectorMat),结果放到resultMat中
	resultMat = -1 * alphaMat * supportVectorMat;//上一篇博文中有解释为什么是负号,这里不赘述

	//得到最终的setSVMDetector(const vector& detector)参数中可用的检测子
	vector myDetector;
	//将resultMat中的数据复制到数组myDetector中
	for(int i=0; i(0,i));
	}
	myDetector.push_back(svm.get_rho());//最后添加偏移量rho,得到检测子
	cout<<"检测子维数:"< myDetector;//自己的检测器数组
	//while(!fin_detector.eof())
	//{
		//fin_detector >> temp;
		//myDetector.push_back(temp);
	//}
	//cout<<"检测子维数:"< found;
		hog.detectMultiScale(src, found, 0, Size(8,8),Size(32,32), 1.05, 2);
		//处理得到的矩形框
		for(int i=0; i < found.size(); i++)
		{
			//将矩形框轮廓限定在图像内部,r的x、y坐标是相对于源图像src来定义的
			Rect r = found[i];
			if(r.x < 0)
				r.x = 0;
			if(r.y < 0)
				r.y = 0;
			if(r.x + r.width > src.cols)
				r.width = src.cols - r.x;
			if(r.y + r.height > src.rows)
				r.height = src.rows - r.y;

			//将矩形框框出的图片保存为难例
			Mat hardExampleImg = src(r);//从原图上截取矩形框大小的图片
			resize(hardExampleImg,hardExampleImg,Size(64,128));//将剪裁出来的图片缩放为64*128大小
			sprintf(saveName,"hardexample%09d.jpg",hardExampleCount++);//生成hard example图片的文件名
			imwrite(saveName, hardExampleImg);//保存框出的图片部分,这里没办法添加一个路径名称,所以全部保存在VS项目里了,好乱= =

			//画矩形框,因为hog检测出的矩形框比实际人体框要稍微大些,所以这里需要做一些调整
			r.x += cvRound(r.width*0.1);
			r.width = cvRound(r.width*0.8);
			rectangle(img, r.tl(), r.br(), Scalar(0,255,0), 2);
		}
		imwrite(str+ImgName,img);//将处理过的图像保存下来,这里保存的就是原始负样本加上各种框框之后的结果图片
		imshow("src",src);
		waitKey(20);
	}
	system("pause");
}

Opencv之HOG特征与SVM相结合的人体检测(增加自举法)_第1张图片 Opencv之HOG特征与SVM相结合的人体检测(增加自举法)_第2张图片 Opencv之HOG特征与SVM相结合的人体检测(增加自举法)_第3张图片

这个是经过自举法之后得到的新检测器的成果,是不是很Duang Duang Duang?来对比一下没有通过自举法得到的检测结果:

Opencv之HOG特征与SVM相结合的人体检测(增加自举法)_第4张图片Opencv之HOG特征与SVM相结合的人体检测(增加自举法)_第5张图片

其实我只利用了一次自举训练,便得到了以上的良好检测效果,因为检测的正负样本基数不够大,所以不敢进行多次自举训练,担心会造成大量漏检。最后值得一提的是,利用原始1000多张负样本进行自举检测,竟然得到了7000+张新的负样本,这说明原来的检测器检测效果堪忧。。。不过好在拥有了自举训练这个关键的idea,使得我们的检测器功能优化了很多~

Last but not least,洛基祝大家新年快乐!大家在刻苦敲代码的同时也别忘了去锻炼身体哦!现在是成都时间2017年1月3日凌晨12点38分

Nighty night~ :-D

你可能感兴趣的:(Opencv之HOG特征与SVM相结合的人体检测(增加自举法))