opencv SVM 训练行人检测器注意事项

<span style="color: rgb(255, 0, 0); font-size: 18px; font-weight: bold; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">事项1:支持向量一个的原因?</span>

如下的解答:用opencv2.49的我是这么理解的:对于线性SVM,在opencv\sources\modules\ml\src\svm.cpp这个源码的optimize_linear_svm()函数中opencv的作者已经解释很很清楚了,“we optimize only linear SVM: compress all the support vectors into one.”,support_vector*alpha的工作他已经做了,直接拿生成的<support_vector>+<rho>应该就可以作为分类器拿去用了,<support_vector>代表-w,<rho>代表b,而线性分类器不就是wx+b=0吗?(只有线性分类器做了此项优化,其他非线性SVM请按照原来的步骤操作)


事项2:一般训练应该包括以下几步
1、提取正负样本hog特征
2、投入svm分类器训练,得到model
3、由model生成检测子
4、利用检测子检测负样本,得到hardexample
5、提取hardexample的hog特征并结合第一步中的特征一起投入训练,得到最终检测子。

经过以上步骤,检测效果会有大的提升。


事项3:如何得到W,并将其转化为opencv中的检测器

假设线性分类器是wx+b=0,这里得到的<support_vector>*<alpha>相当于-w,得到的rho相当于b,所以这里相当于将<support_vector>*<alpha>得到的结果<rec>每一项都取负,得到w,与b组成新的Mat后代入到detectMultiScale()中进行识别。


<span style="font-size:14px;">//继承自CvSVM的类,因为生成setSVMDetector()中用到的检测子参数时,需要用到训练好的SVM的decision_func参数,
//但通过查看CvSVM源码可知decision_func参数是protected类型变量,无法直接访问到,只能继承之后通过函数访问
class MySVM : public CvSVM
{
public:
	//获得SVM的决策函数中的alpha数组
	double * get_alpha_vector()
	{
		return this->decision_func->alpha;
	}

	int get_alpha_count()
	{
		return this->sv_total;
	}

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

	int get_sv_dim()
	{
		return this->var_all;
	}

	int get_sv_count()
	{
		return this->decision_func->sv_count;
	}

	float** get_sv()
	{
		return this->sv;
	}
};
</span>

将训练好的SVM转化为检测算子

<span style="font-size:12px;">vector<float> getSVMDetector(MySVM svm)
{
	/*************************************************************************************************
	线性SVM训练完成后得到的XML文件里面,有一个数组,叫做support vector,还有一个数组,叫做alpha,有一个浮点数,叫做rho;
	将alpha矩阵同support vector相乘,注意,alpha*supportVector,将得到一个列向量。之后,再该列向量的最后添加一个元素rho。
	如此,变得到了一个分类器,利用该分类器,直接替换opencv中行人检测默认的那个分类器(cv::HOGDescriptor::setSVMDetector()),
	就可以利用你的训练样本训练出来的分类器进行行人检测了。
	***************************************************************************************************/
	int DescriptorDim = svm.get_var_count();//特征向量的维数,即HOG描述子的维数
	int supportVectorNum = svm.get_support_vector_count();//支持向量的个数
	cout<<"支持向量个数:"<<supportVectorNum<<endl;

	Mat alphaMat = Mat::zeros(1, supportVectorNum, CV_32FC1);//alpha向量,长度等于支持向量个数
	Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);//支持向量矩阵
	Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);//alpha向量乘以支持向量矩阵的结果

	//将支持向量的数据复制到supportVectorMat矩阵中
	for(int i=0; i<supportVectorNum; i++)
	{
		const float * pSVData = svm.get_support_vector(i);//返回第i个支持向量的数据指针
		for(int j=0; j<DescriptorDim; j++)
		{
			//cout<<pData[j]<<" ";
			supportVectorMat.at<float>(i,j) = pSVData[j];
		}
	}

	//将alpha向量的数据复制到alphaMat中
	double * pAlphaData = svm.get_alpha_vector();//返回SVM的决策函数中的alpha向量
	for(int i=0; i<supportVectorNum; i++)
	{
		alphaMat.at<float>(0,i) = pAlphaData[i];
	}

	//计算-(alphaMat * supportVectorMat),结果放到resultMat中
	//gemm(alphaMat, supportVectorMat, -1, 0, 1, resultMat);//不知道为什么加负号?
	resultMat = -1 * alphaMat * supportVectorMat;

	//得到最终的setSVMDetector(const vector<float>& detector)参数中可用的检测子
	vector<float> myDetector;
	//将resultMat中的数据复制到数组myDetector中
	for(int i=0; i<DescriptorDim; i++)
	{
		myDetector.push_back(resultMat.at<float>(0,i));
	}
	//最后添加偏移量rho,得到检测子
	myDetector.push_back(svm.get_rho());
	cout<<"检测子维数:"<<myDetector.size()<<endl;

	//保存检测子参数到文件

//  	ofstream fout("HOGDetectorForOpenCV_2400PosINRIA_12000Neg.txt");
//  	for(int i=0; i<myDetector.size(); i++)
//  	{
//  		fout<<myDetector[i]<<endl;
//  	}

	return myDetector;
}</span>


调用检测算子,并转化为opencv格式,进行多尺度检测
	vector<float> myDetector = getSVMDetector(svm);

	//设置HOGDescriptor的检测子
	HOGDescriptor myHOG;
	myHOG.setSVMDetector(myDetector);
	//myHOG.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

<span style="font-size: 18px;"><strong>     </strong></span><span style="font-size:14px;">Mat src = imread("5.png");
	vector<Rect> found, found_filtered;//矩形框数组
	cout<<"进行多尺度HOG人体检测"<<endl;
	myHOG.detectMultiScale(src, found, 0, Size(8,8), Size(32,32), 1.05, 2);//对图片进行多尺度行人检测
	cout<<"找到的矩形框个数:"<<found.size()<<endl;

	//画矩形框,因为hog检测出的矩形框比实际人体框要稍微大些,所以这里需要做一些调整
	for(int i=0; i<found.size(); i++)
	{
		Rect r = found[i];

		r.x += cvRound(r.width*0.1);
		r.width = cvRound(r.width*0.8);
		r.y += cvRound(r.height*0.07);
		r.height = cvRound(r.height*0.8);
		rectangle(src, r.tl(), r.br(), Scalar(0,255,0), 3);
	}

	namedWindow("src",0);
	imshow("src",src);
	waitKey();
</span>






评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小新识图

你的鼓励是我最大的分享动力。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值