Hog+svm行人检测

(1)第一个工程是用来训练分类器和检测正样本检测率的

// PeopleDetectHog.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <ctype.h>
#include "cv.h"
#include "highgui.h"
#include "stdafx.h"
#include <ml.h>
#include <fstream>
#include <math.h>
#include <string>
#include <vector>
#include <stdio.h>

using namespace cv;
using namespace std;

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 _tmain(int argc, _TCHAR* argv[])
{
int positiveSampleCount = 2416; //正样本数
int negativeSampleCount = 18185; //负样本数
int totalSampleCount = positiveSampleCount + negativeSampleCount;

FILE* fp = fopen("PeopleDetectResult_INRIA2416.txt","w");

if(fp==NULL)
{
int n = GetLastError();
exit(1);
}

CvMat *sampleFeaturesMat = cvCreateMat(totalSampleCount , 3780, CV_32FC1); //这里第二个参数1764是hog维数,即矩阵的列是由下面的featureVec的大小决定的,可以由descriptors.size()得到,
//64*64的训练样本,该矩阵将是totalSample*1764;若是64*128,则对应3780维

cvSetZero(sampleFeaturesMat);
CvMat *sampleLabelMat = cvCreateMat(totalSampleCount, 1, CV_32FC1); //存储样本图片类型 ,正样本1,负样本-1
cvSetZero(sampleLabelMat);

// fprintf(fp, "%s\n","Hog描述算子:\n SVM参数:");
cout<<"waiting......"<<endl;
cout<<"start to training positive samples..."<<endl;

string buf;
char line[512];
vector<string> img_path;//输入文件名变量
ifstream svm_data( "D:\\program\\matlabprojects\\PeopleSample\\pos1\\train_list.txt");
while (svm_data)
{
if (getline( svm_data, buf ))
{
img_path.push_back( buf );
}
}

svm_data.close();//关闭文件

IplImage* src;
IplImage* img=cvCreateImage(cvSize(64,128),8,3);//需要分析的图片,这里默认设定图片是64*128大小,所以上面定义了3780,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行

long t1 = GetTickCount();
for(int i=0; i<positiveSampleCount; i++)
{
src=cvLoadImage(img_path[i].c_str(),1);
cvResize(src,img); //读取正样本图片
if( img == NULL )
{
cout<<" can not load the image:"<<img_path[i].c_str()<<endl;
continue;
}
cout<<" processing "<<img_path[i].c_str()<<endl;

cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8),cv::Size(8,8), 9);
//HOG的描述函数。如果是64*128的训练样本,需要把第一个参数改为cv::Size(64,128)

vector<float> featureVec;
hog.compute(img, featureVec, cv::Size(8,8)); //featureVec--存储每个样本图片的HOG特征向量
for (int j=0; j<featureVec.size(); j++)
{
CV_MAT_ELEM( *sampleFeaturesMat, float, i, j ) = featureVec[j];
}
sampleLabelMat->data.fl[i] = 1;
}

cvReleaseImage( &src);
cvReleaseImage( &img);
cout<<"end of training for positive samples..."<<endl;

long t2 = GetTickCount();
fprintf(fp, "%s%d\n", "training for positive samples timeis:",t2-t1);

cout<<"waiting......"<<endl;
cout<<"start to train negative samples..."<<endl;

string buff;
int m;
vector<string> img_neg_path;//输入文件名变量
ifstream svm_neg_data( "D:\\program\\matlabprojects\\PeopleSample\\neg4\\train_list.txt");
while (svm_neg_data)
{
if (getline( svm_neg_data, buff ))
{
img_neg_path.push_back( buff );
}
}

svm_neg_data.close();//关闭文件
IplImage* neg;
IplImage* neg_img=cvCreateImage(cvSize(64,128),8,3);

for (int i=0; i<negativeSampleCount; i++)
{
neg = cvLoadImage(img_neg_path[i].c_str(),1); //读取负样本图片
cvResize(neg,neg_img); //读取正样本图片
if( neg_img == NULL )
{
cout<<" can not load the image:"<<img_path[i].c_str()<<endl;
continue;
}

cout<<" processing"<<img_neg_path[i].c_str()<<endl;
cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8),cv::Size(8,8), 9); //若为64*128的样本,需要将第一个参数做出改动(上述)
vector<float> featureVec;
hog.compute(neg_img,featureVec,cv::Size(8,8)); //featureVec.size(),且对于不同大小的输入训练图片,这个值是不同的
//cout<<"The featureVector number of negativeSample is:"<<featureVec.size()<<endl; //查看一下featureVec的大小
for ( int j=0; j<featureVec.size(); j ++)
{
CV_MAT_ELEM( *sampleFeaturesMat, float, i + positiveSampleCount, j ) =featureVec[ j ]; //把HOG存储下来
}

sampleLabelMat->data.fl[ i + positiveSampleCount ] = -1;
m = i+1;
}
cout<<"The count of negativeSample is:"<<m<<endl;//统计处理过的负样本数目
fprintf(fp, "%s%d\n", "The count of negativeSample is:",m);
cout<<"end of training for negative samples..."<<endl;

long t3 = GetTickCount();
cout<<"waiting......"<<endl;
fprintf(fp, "%s%d\n", "training for negative samples timeis:",t3-t1);

//☆☆☆☆☆☆☆☆☆(5)SVM学习☆☆☆☆☆☆☆☆☆☆☆☆

cout<<"start to train for SVM classifier..."<<endl;

// SVM种类:CvSVM::C_SVC
// Kernel的种类:CvSVM::LINEAR
// degree:10.0(此次不使用)
// gamma:8.0
// coef0:1.0(此次不使用)
// C:0.01
// nu:0.5(此次不使用)
// p:0.1(此次不使用)
// 然后对训练数据正规化处理,并放在CvMat型的数组里。

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;
long t4 = GetTickCount();

svm.train( sampleFeaturesMat, sampleLabelMat, NULL, NULL, params ); //用SVM线性分类器训练
//sampleFeaturesMat保存各样本的特征值,sampleLabelMat保存图片类型*/

//保存最终的SVM
long t5 = GetTickCount();
fprintf(fp, "%s%d\n", "Time of train for SVM classifier is:",t5-t4);
svm.save( "SVM_DATA.xml" );
cout<<"SVM_DATA.xml保存完毕!"<<endl;

cvReleaseMat(&sampleFeaturesMat);
cvReleaseMat(&sampleLabelMat);

int supportVectorSize = svm.get_support_vector_count();
cout<<"support vector size of SVM:"<<supportVectorSize<<endl;
cout<<"SVM completed"<<endl;

CvMat *sv,*alp,*re; //所有样本特征向量
sv = cvCreateMat(supportVectorSize , 3780, CV_32FC1);
alp = cvCreateMat(1 , supportVectorSize, CV_32FC1);
re = cvCreateMat(1 , 3780, 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));
}

double* alphaArr = svm.get_alpha();
int alphaCount = svm.get_alpha_count();

for(int i=0; i<supportVectorSize; i++)
{
alp->data.fl[i] = alphaArr[i];
}
cvMatMul(alp, sv, re);

int posCount = 0;
for (int i=0; i<3780; i++)
{
re->data.fl[i] *= -1;
}

FILE* fpp = fopen("Peopledetector_INRIA2416.txt","w");

if(fpp==NULL)
{
int n = GetLastError();
exit(1);
}
for(int i=0; i<3780; i++)
{
fprintf(fpp,"%f \n",re->data.fl[i]);
}
float rho = svm.get_rho();
fprintf(fpp, "%f", rho);

cout<<"D:\hogSVMDetector.txt 保存完毕"<<endl; //保存HOG能识别的分类器

fclose(fpp);

cvReleaseMat(&sv);
cvReleaseMat(&alp);
cvReleaseMat(&re);
cvReleaseMat(&res);

// //***************************************检测正样本************************************
//
IplImage *test;
vector<string> img_tst_path;
// ifstream img_tst("D:\\program\\matlabprojects\\INRIAPerson\\test_my\\pos_bmp\\train_list.txt");//同输入训练样本,这里也是一样的,只不过不需要标注图片属于哪一类了
// ifstream img_tst("D:\\train_list.txt");
ifstream img_tst( "D:\\program\\matlabprojects\\PeopleSample\\pos1\\train_list2.txt");
while( img_tst )
{
if( getline( img_tst, buf ) )
{
img_tst_path.push_back( buf );
}
}
img_tst.close();


// CvMat *test_hog = cvCreateMat( 1, 1764, CV_32FC1 );//注意这里的1764,同上面一样
IplImage* trainImg=cvCreateImage(cvSize(64,128),8,3);
int right=0;
int wrong=0; //用于计算正确率
int n;
for( string::size_type j = 0; j != img_tst_path.size(); j++ )//依次遍历所有的待检测图片
{
test = cvLoadImage( img_tst_path[j].c_str(), 1);
if( test == NULL )
{
cout<<" can not load the image:"<<img_tst_path[j].c_str()<<endl;
continue;
}

cvZero(trainImg);
cvResize(test,trainImg); //读取图片
HOGDescriptor *hog=newHOGDescriptor(cvSize(64,128),cvSize(16,16),cvSize(8,8),cvSize(8,8),9); //具体意思见参考文章1,2
vector<float>descriptors;//结果数组

hog->compute(trainImg, descriptors,Size(1,1), Size(0,0)); //调用计算函数开始计算
cout<<"HOG dims: "<<descriptors.size()<<endl;
CvMat* SVMtrainMat=cvCreateMat(1,descriptors.size(),CV_32FC1);
n=0;
for(vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
{
cvmSet(SVMtrainMat,0,n,*iter);
n++;
}

int ret = svm.predict(SVMtrainMat);//获取最终检测结果,这个predict的用法见 OpenCV的文档

if (ret == 1)
{
right += 1;
}
else if (ret == -1)
{
wrong += 1;
}

}
DOUBLE result ;
result= double(right)/double(right+wrong);
cout<<"The Correct rateis:"<<result*100<<"%"<<endl; //检测正样本的正确率
fprintf(fp,"%s%f%s\n","The Correct rateis:",result*100,"%");
fclose(fp);

cvReleaseImage( &test );
cvReleaseImage( &trainImg );

*****************************************开始读入待识别的图像,检测车辆************************************

// IplImage* Img =cvLoadImage("D:\\program\\matlabprojects\\INRIAPerson\\Test\\pos_bmp\\00019.bmp"); //读入图像
// IplImage* DetecImg=cvCreateImage(cvSize(320,240),8,3);

// cvResize(Img,DetecImg);
// long t1 = GetTickCount();
//if (DetecImg == NULL)
//{
// cout<<" can not load the image"<<endl;
// exit(-1);
//} //检测图像有没有被读入

//vector<float> x;
//
//ifstream fileIn("Peopledetector4.txt", ios::in);
//float val = 0.0f;
//while(!fileIn.eof())
//{
// fileIn>>val;
// x.push_back(val);
//}
//fileIn.close();

//vector<cv::Rect> found; //检测出的车辆数量
//vector<cv::Rect> temp; //用于存放的容器
// vector<vector<cv::Rect>> bigfound;
//vector< vector<cv::Rect>> ::iterator bigit; //功能强大的迭代器

//IplImage* img = NULL;

//cv::HOGDescriptor hog(cv::Size(64,128),cv::Size(16,16), cv::Size(8,8), cv::Size(8,8), 9);
//hog.setSVMDetector(x); //x向量对应的分类器
//long t3 = GetTickCount();

//cout<<"The process time is:"<<t3-t1<<endl;
//
//
////hog.detectMultiScale(DetecImg, found, 0.7, cv::Size(8,8), cv::Size(5,5),1.06, 1, false); //检测当前图片的HOG特征,found为检测结果向量
// hog.detectMultiScale(DetecImg, found, 0.3, cv::Size(8,8), cv::Size(8,8),1.05, 2, false);
//long t4 = GetTickCount();

//cout<<"The process time is:"<<t4-t1<<endl;

//cvNamedWindow("img", CV_WINDOW_AUTOSIZE);
//
//int i,j;
//vector<cv::Rect> found_filtered;
//for (i = 0; i<found.size();i++)
//{
// Rect r = found[i];
// //下面的这个for语句是找出所有没有嵌套的矩形框r,并放入found_filtered中,如果有嵌套的
// //话,则取外面最大的那个矩形框放入found_filtered中
// for(j = 0; j <found.size(); j++)
// if(j != i && (r&found[j])==r)
// break;
// if(j == found.size())
// found_filtered.push_back(r);
//}

//cout<<"The number of vehicle is:"<<found_filtered.size()<<endl; //检测车辆数
////在图片img上画出矩形框,因为hog检测出的矩形框比实际人体框要稍微大些,所以这里需要
////做一些调整
//for(i = 0; i <found_filtered.size(); i++)
//{
// Rect r = found_filtered[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);
// cvRectangle(DetecImg,cvPoint(r.x,r.y),cvPoint(r.x+r.width,r.y+r.height),CV_RGB(255,0,0),2);
//}
//cvShowImage("img",DetecImg);
//cvWaitKey(0);
//long t5 = GetTickCount();

//cout<<"The process time is:"<<t5-t1<<endl;
//system("pause");
//cvWaitKey(0);
//
// cvReleaseImage(&DetecImg);

//**********************************处理视频************************************

CvCapture* cap = cvCreateFileCapture("D:\\项目文档\\智能交通\\行人视频\\20120925\\20120925174702950.avi");//读入视频
if (!cap)
{
cout<<"avi file load error……"<<endl;
system("pause");
exit(-1);
} //检测视频有没有被读入

vector<float> x;

ifstream fileIn("Peopledetector4.txt",ios::in);
float val = 0.0f;
while(!fileIn.eof())
{
fileIn>>val;
x.push_back(val);
}
fileIn.close();

vector<cv::Rect> found; //检测出的车辆数量
vector<cv::Rect> temp; //用于存放的容器
vector<vector<cv::Rect>> bigfound;
vector< vector<cv::Rect>> ::iterator bigit; //功能强大的迭代器
cvNamedWindow("img",CV_WINDOW_AUTOSIZE);

IplImage* img = NULL;
IplImage* SizeImg=cvCreateImage(cvSize(320,240),8,3);

long t1 = GetTickCount();
// cv::HOGDescriptor hog(cv::Size(64,64), cv::Size(16,16), cv::Size(8,8),cv::Size(8,8), 9);
cv::HOGDescriptor hog(cv::Size(64,128), cv::Size(16,16), cv::Size(8,8),cv::Size(8,8), 9);

long t4 = GetTickCount();
cout<<"time:"<<t4-t1<<endl;
hog.setSVMDetector(x); //x向量对应的分类器

while(1)
{
img=cvQueryFrame(cap);
// img = cvLoadImage("D:\\000120.bmp");
cvZero(SizeImg);
cvResize(img,SizeImg);
if(!img) break;
cvWaitKey(1);
//hog.detectMultiScale(img,found,0.9,cv::Size(2,2),cv::Size(64,64),1.06,1,false);
// hog.detectMultiScale(SizeImg, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
// hog.detectMultiScale(SizeImg, found, 0, cv::Size(11,11), cv::Size(32,32),0.5,2);
// hog.detectMultiScale(SizeImg, found, 1.0, cv::Size(16,16), cv::Size(32,32),1.05, 2, false);
hog.detectMultiScale(SizeImg, found, 0, Size(8, 8), Size(16, 16), 1.0,2,false);

//检测当前帧的HOG特征,found为检测结果向量

int i,j;
vector<cv::Rect> found_filtered;
for (i = 0; i<found.size();i++)
{
Rect r = found[i];
//下面的这个for语句是找出所有没有嵌套的矩形框r,并放入found_filtered中,如果有嵌套的
//话,则取外面最大的那个矩形框放入found_filtered中
for(j = 0; j <found.size(); j++)
if(j != i && (r&found[j])==r)
break;
if(j == found.size())
found_filtered.push_back(r);
}

cout<<"The number of vehicle is:"<<found_filtered.size()<<endl; //检测人数
//在图片img上画出矩形框,因为hog检测出的矩形框比实际人体框要稍微大些,所以这里需要
//做一些调整
for(i = 0; i <found_filtered.size(); i++)
{
Rect r = found_filtered[i];
r.x += cvRound(r.width*0.1);
r.width = cvRound(r.width*0.7);
r.y += cvRound(r.height*0.1);
r.height = cvRound(r.height*0.7);
// rectangle(img, r.tl(), r.br(), Scalar(0, 255, 0), 3);
cvRectangle(SizeImg,cvPoint(r.x,r.y),cvPoint(r.x+r.width,r.y+r.height),CV_RGB(255,0,0),1);
}
cvShowImage("img",SizeImg);
cvWaitKey(1);

}
return 0;

}

(1)其中正负样本的选取还是要根据自己具体的问题选取,开始选取的是INRIA、MIT和TUD的样本库,正样本检测效果还可以95%,只是检测自己的视频图像效果就不好了

(2)样本为64×128,样本生成方法见下一篇日志,哈哈

用matlab生成样本

(1)      生成正样本    

(2)      生成负样本

样本生成之后,在文件夹中建立文本:

dir /b/s/p/w *.bmp>train_list.txt

@pause

即可生成目录

你可能感兴趣的:(Hog+svm行人检测)