您的位置:首页 > 运维架构

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

2015-03-03 11:42 323 查看
<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>



内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: