下面的程序亲自测试成功,但是其实不用这么麻烦的:
#include "opencv2/opencv.hpp"
#include "windows.h"
#include "fstream"
#include <iostream>
using namespace std;
using namespace cv;
class Mysvm: public CvSVM
{
public:
int get_alpha_count()
{
return this->sv_total;
}
int get_sv_dim()
{
return this->var_all;
}
int get_sv_count()
{
return this->decision_func->sv_count;
}
double* get_alpha()
{
return this->decision_func->alpha;
}
float** get_sv()
{
return this->sv;
}
float get_rho()
{
return this->decision_func->rho;
}
};
int my_train()
{
/*-----------------------------------------------------------------------------
* d:/pedestrianDetect-peopleFlow.txt是用来保存所有样本的特点,大小为样本数*3780(每个样本的特点数)
*d:/pedestrianDetect-peopleFlow.txt是用来保存所有样本的特点,大小为样本数*1764(每个样本的特点数)
*
*
*
*-----------------------------------------------------------------------------*/
char classifierSavePath[256] = "d:/pedestrianDetect-peopleFlow.txt";
string buf;
vector<string> pos_img_path;
vector<string> neg_img_path;
ifstream svm_pos_data("pos.txt"); /* 批处理惩罚法度生成 */
ifstream svm_neg_data("neg.txt"); /* 批处理惩罚生成 */
while( svm_pos_data )//将练习样本文件依次读取进来
{
if( getline( svm_pos_data, buf ) )
pos_img_path.push_back( buf );
}
while( svm_neg_data )//将练习样本文件依次读取进来
{
if( getline( svm_neg_data, buf ) )
neg_img_path.push_back( buf );
}
cout<<pos_img_path.size()<<"个正样本"<<endl;
cout<<neg_img_path.size()<<"个负样本"<<endl;
int totalSampleCount=pos_img_path.size()+neg_img_path.size();
// CvMat *sampleFeaturesMat = cvCreateMat(totalSampleCount , 3780, CV_32FC1);
CvMat *sampleFeaturesMat = cvCreateMat(totalSampleCount , 1764, CV_32FC1);
//64*128窗口大小的练习样本,该矩阵将是totalSample*3780
//64*64的窗口大小的练习样本,该矩阵将是totalSample*1764
cvSetZero(sampleFeaturesMat);
CvMat *sampleLabelMat = cvCreateMat(totalSampleCount, 1, CV_32FC1);//样本标识
cvSetZero(sampleLabelMat);
cout<<"************************************************************"<<endl;
cout<<"start to training positive samples..."<<endl;
for(int i=0; i<pos_img_path.size(); i++)
{
cv::Mat img1 = cv::imread(pos_img_path.at(i));
Mat img;
resize(img1,img,Size(64,64));
if( img.data == NULL )
{
cout<<"positive image sample load error: "<<i<<endl;
system("pause");
continue;
}
//cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
vector<float> featureVec;
hog.compute(img, featureVec, cv::Size(8,8));
unsigned int featureVecSize = featureVec.size();
for (int j=0; j<featureVecSize; j++)
{
CV_MAT_ELEM( *sampleFeaturesMat, float, i, j ) = featureVec[j];
}
sampleLabelMat->data.fl[i] = 1;
}
cout<<"end of training for positive samples..."<<endl;
cout<<"*********************************************************"<<endl;
cout<<"start to train negative samples..."<<endl;
for (int i=0; i<neg_img_path.size(); i++)
{
cv::Mat img1 = cv::imread(neg_img_path.at(i));
Mat img;
resize(img1,img,Size(64,64));
if(img.data == NULL)
{
cout<<"negative image sample load error: "<<endl;
continue;
}
// cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
vector<float> featureVec;
hog.compute(img,featureVec,cv::Size(8,8));//策画HOG特点
int featureVecSize = featureVec.size();
for ( int j=0; j<featureVecSize; j ++)
{
CV_MAT_ELEM( *sampleFeaturesMat, float, i + pos_img_path.size(), j ) = featureVec[j];
}
sampleLabelMat->data.fl[ i + pos_img_path.size() ] = -1;
}
cout<<"end of training for negative samples..."<<endl;
cout<<"********************************************************"<<endl;
cout<<"start to train for SVM classifier..."<<endl;
CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 1000, FLT_EPSILON);
params.C = 0.01;
Mysvm svm;
svm.train( sampleFeaturesMat, sampleLabelMat, NULL, NULL, params ); //用SVM线性分类器练习
svm.save(classifierSavePath);
cvReleaseMat(&sampleFeaturesMat);
cvReleaseMat(&sampleLabelMat);
int supportVectorSize = svm.get_support_vector_count();
cout<<"support vector size of SVM:"<<supportVectorSize<<endl;
cout<<"************************ end of training for SVM ******************"<<endl;
CvMat *sv,*alp,*re;//所有样本特点向量
//sv = cvCreateMat(supportVectorSize , 3780, CV_32FC1);
sv = cvCreateMat(supportVectorSize , 1764, CV_32FC1);
alp = cvCreateMat(1 , supportVectorSize, CV_32FC1);
//re = cvCreateMat(1 , 3780, CV_32FC1);
re = cvCreateMat(1 , 1764, CV_32FC1);
CvMat *res = cvCreateMat(1 , 1, CV_32FC1);
cvSetZero(sv);
cvSetZero(re);
for(int i=0; i<supportVectorSize; i++)
{
//memcpy( (float*)(sv->data.fl+i*3780), svm.get_support_vector(i), 3780*sizeof(float));
memcpy( (float*)(sv->data.fl+i*1764), svm.get_support_vector(i), 1764*sizeof(float));
}
double* alphaArr = svm.get_alpha();
int alphaCount = svm.get_alpha_count();
for(int i=0; i<supportVectorSize; i++)
{
alp->data.fl[i] = (float)alphaArr[i];
}
cvMatMul(alp, sv, re);
int posCount = 0;
// for (int i=0; i<3780; i++)
//{
// re->data.fl[i] *= -1;
// }
for (int i=0; i<1764; i++)
{
re->data.fl[i] *= -1;
}
/*-----------------------------------------------------------------------------
* d:/hogSVMDetector-peopleFlow.txt文件中保存的是支撑向量,共有3781个值,是一个3781*1的列向量
*d:/hogSVMDetector-peopleFlow.txt文件中保存的是支撑向量,共有1764个值,是一个3781*1的列向量
*
*-----------------------------------------------------------------------------*/
FILE* fp = fopen("d:/hogSVMDetector-peopleFlow.txt","wb");
if( NULL == fp )
{
return 1;
}
// for(int i=0; i<3780; i++)
//{
// fprintf(fp,"%f \n",re->data.fl[i]);
// }
for(int i=0; i<1764; i++)
{
fprintf(fp,"%f \n",re->data.fl[i]);
}
float rho = svm.get_rho();
fprintf(fp, "%f", rho);
cout<<"d:/hogSVMDetector.txt 保存完毕"<<endl;//保存HOG能识此外分类器
fclose(fp);
return 1;
}
void my_detect()
{
CvCapture* cap = cvCreateFileCapture("E:\\test.avi");
if (!cap)
{
cout<<"avi file load error..."<<endl;
system("pause");
exit(-1);
}
vector<float> x;
ifstream fileIn("e:/hogSVMDetector-peopleFlow.txt", ios::in);
float val = 0.0f;
while(!fileIn.eof())
{
fileIn>>val;
x.push_back(val);
}
fileIn.close();
vector<cv::Rect> found;
cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
/*-----------------------------------------------------------------------------
*
*
* 若是setSVMDetector呈现题目的话,可能是这个原因:因为默认hog.getDefaultPeopleDetector()
* 获取的检测器的大小是3781*1的列向量,所以若是生成的e:/hogSVMDetector-peopleFlow.txt里的大小不等的话
* ,读入
* 就会呈现错误,可能这个函数推敲了运行的速度题目,所以限制了大小为3781*1
*
* 希罕重视:有些童鞋可能生成的特点向量是15876(所以setSVMDetector里的列向量就是15877了与默认的大小不一,assetion就失足了)
* ,只要调剂下图像的大小和检测窗口的大小,使生成的特点向量为3780就行了,怎么策画,可以参考
* 网上其他博客
*
*-----------------------------------------------------------------------------*/
hog.setSVMDetector(x);
IplImage* img = NULL;
cvNamedWindow("img", 0);
while(img=cvQueryFrame(cap))
{
hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
if (found.size() > 0)
{
for (int i=0; i<found.size(); i++)
{
CvRect tempRect = cvRect(found[i].x, found[i].y, found[i].width, found[i].height);
cvRectangle(img, cvPoint(tempRect.x,tempRect.y),
cvPoint(tempRect.x+tempRect.width,tempRect.y+tempRect.height),CV_RGB(255,0,0), 2);
}
}
}
cvReleaseCapture(&cap);
}
#include<fstream>
int main(int argc, char** argv){
//my_train();
//my_detect();
vector<float> x;
ifstream fileIn("d:/hogSVMDetector-peopleFlow.txt", ios::in); /* 读入支撑向量,没须要读入样本的向量 */
float val = 0.0f;
while(!fileIn.eof())
{
fileIn>>val;
x.push_back(val);
}
fileIn.close();
vector<Rect> found, found_filtered;
// cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
hog.setSVMDetector(x);
Mat img;
img=imread("d:/TEMP1/00281.jpg",1);
hog.detectMultiScale(img, found, 0, cv::Size(2,2), cv::Size(1,1), 1.05, 2);
size_t i, j;
for( i = 0; i < found.size(); i++ )
{
Rect r = found[i];
for( j = 0; j < found.size(); j++ )
if( j != i && (r & found[j]) == r)
break;
if( j == found.size() )
found_filtered.push_back(r);
}
for( i = 0; i < found_filtered.size(); i++ )
{
Rect r = found_filtered[i];
// the HOG detector returns slightly larger rectangles than the real objects.
// so we slightly shrink the rectangles to get a nicer output.
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(img, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
}
imshow("people detector", img);
waitKey();
/*cvNamedWindow("img", 0);
string testimage="E:\database\picture_resize_pos\resize000r.bmp";
Mat img=cv::imread(testimage);
hog.detectMultiScale(img, found, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 2);
if (found.size() > 0)
{
printf("found!");
}*/
return 0;
}
比如说:
cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
生成的hog特征是1764维,sv是N*1764 维 但是因为是线性核,所以N维向量可以对应乘完相加 ,得到一个1*1764的向量 最后保存 一个偏置
SVM函数f(x) = W*SV*A+B 其中(W为alpha,SV支持向量,A为样本的HOG特征,B为偏置)
注意:偏置项保存在最后要取反的(也就是要加负号)。
//img为输入待检测的图片;found为检测到目标区域列表;参数3为程序内部计算为行人目标的阈值,也就是检测到的特征到SVM分类超平面的距离; //参数4为滑动窗口每次移动的距离。它必须是块移动的整数倍;参数5为图像扩充的大小;参数6为比例系数,即测试图片每次尺寸缩放增加的比例; //参数7为组阈值,即校正系数,当一个目标被多个窗口检测出来时,该参数此时就起了调节作用,为0时表示不起调节作用。 hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);