OPENCV里面SVM predict的时候默认是大于零为正样本,小于零为负样本
下面的程序可以自己设定阈值进行判断,最后的值为sum。
暂时只写了线性核的函数,和高斯核的函数,而且因为高斯核函数有多个分类器,所以下面的只为演示(这两个核用的最多)
最后的sum为边界值(之前rbf版本有误,现在已经更改过了。)
#include "stdafx.h" #include<opencv2\core\core.hpp> #include<opencv2\ml\ml.hpp> #include<opencv2\imgproc\imgproc.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\objdetect\objdetect.hpp> using namespace std; using namespace cv; #include<iostream> #include <vector> #include <string> #include "fstream" #define winSize 28//可以更改 HOGDescriptor *hog=new HOGDescriptor(cvSize(28,28),cvSize(14,14),cvSize(7,7),cvSize(7,7),9,1,-1,HOGDescriptor::L2Hys,0.200000,false); //HOGDescriptor *hog=new HOGDescriptor(cvSize(64,64),cvSize(16,16),cvSize(8,8),cvSize(8,8),9,1,-1,HOGDescriptor::L2Hys,0.200000,false); class mySVM : public CvSVM { public: enum { LINEAR=0, POLY=1, RBF=2, SIGMOID=3 }; int *get_sv_index(int i)//获取第几个支持向量的索引 { auto aa= this->decision_func;//aa也就是CvSVMDecisionFunc*类型,版本低的VS不支持aurto aa+=i; return aa->sv_index; } /////////////////////////////////////////////////////////////////////////////////////////// //计算线性核的函数, //calc_poly 计算多项式核函数 需要添加 beta 的值 double get_calc_liner(int vec_count ,int vec_size,Mat &a,Mat &b,Mat &c,double *alpha,double beta ) { //vecs/a 支持向量 vec_count支持向量个数 vec_size 一个支持向量的维数 another/b 样本数据 results/c 计算后的结果 // this->kernel->calc_linear(vec_count,vec_size, vecs,another,results); ////////////////////根据原型改编////////////////// int j, k; double sum=0; for( j = 0; j < vec_count; j++ ) { float *sample = a.ptr<float>(j); float *another = b.ptr<float>(0); float *results = c.ptr<float>(0); double s = 0; for( k = 0; k <= vec_size - 4; k += 4 ) s += sample[k]*another[k] + sample[k+1]*another[k+1] +sample[k+2]*another[k+2] + sample[k+3]*another[k+3]; for( ; k <vec_size; k++ ) s += sample[k]*another[k]; results[j] = (float)(s*alpha[j]+beta ); sum+=results[j]; } return sum; } ///////////////////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////// //////////////////////////RBF核的计算,可以看到RBF核里面没有alpha而是在外面//////////////////////////////////////// double get_calc_rbf( int vcount, int var_count, Mat &a,Mat &b,Mat &c,double *alpha ) { //vecs/a 支持向量 vec_count支持向量个数 vec_size 一个支持向量的维数 another/b 样本数据 results/c 计算后的结果 // this->kernel->calc_rbf(vec_count,vec_size, vecs,another,results); ////////////////////根据原型改编////////////////// double sum1=0; //Mat R = Mat( 1, vcount, CV_32FC1 ); double gamma =-this->params.gamma; int j, k; float* results=0; for( j = 0; j < vcount; j++ ) { float* sample = a.ptr<float>(j); float* another = b.ptr<float>(0); results = c.ptr<float>(0); double s = 0; for( k = 0; k <= var_count - 4; k += 4 ) { double t0 = sample[k] - another[k]; double t1 = sample[k+1] - another[k+1]; s += t0*t0 + t1*t1; t0 = sample[k+2] - another[k+2]; t1 = sample[k+3] - another[k+3]; s += t0*t0 + t1*t1; } for( ; k < var_count; k++ ) { double t0 = sample[k] - another[k]; s += t0*t0; } results[j] = (float)(s*gamma); } if( vcount > 0 ) cv::exp( c, c ); for( k = 0; k < vcount; k++ ) sum1 += alpha[k]*results[k]; return sum1; } double get_rho(int i)//获得一个分类器的偏置 { auto aa= this->decision_func; aa+=i; return aa->rho; } double *get_alpha(int i)//获得一个分类器的alpha系数 { auto aa= this->decision_func; aa+=i; return aa->alpha; } }; Mat get_hog(string filename) { vector<string> img_path;//输入文件名变量 ifstream svm_data(filename.c_str()); string buf; int len=0; while( svm_data )//将训练样本文件依次读取进来 { if( getline( svm_data, buf ) ) { if( len%2==0) img_path.push_back( buf );//图像路径 } len++; } svm_data.close();//关闭文件 Mat img =imread(img_path[0]); Mat test; resize(img,test,Size(winSize,winSize)); vector<float>descriptors; hog->compute(test,descriptors,Size(1,1), Size(0,0)); Mat another(descriptors);//hog特征 another= another.reshape(1,1); Mat tezheng=Mat(len/2,another.size().width,CV_32FC1); float *p = another.ptr<float>(0); float *pp=tezheng.ptr<float>(0); for(int i=0;i<another.size().width;i++) { pp[i]=p[i]; } for(int j =1;j<len/2;j++) { Mat img =imread(img_path[j]); resize(img,test,Size(winSize,winSize)); hog->compute(test,descriptors,Size(1,1), Size(0,0)); Mat another(descriptors); another= another.reshape(1,1); float *p = another.ptr<float>(0); float *pp=tezheng.ptr<float>(j); for(int i=0;i<another.size().width;i++) { pp[i]=p[i]; } } return tezheng; } vector<float> get_Bi(Mat &sv,Mat &train,int pos ,double *alpha,double rho ,Mat &test) { int num=train.size().height; int SZ_num=pos; int SF_num=num-pos; double S_Z=0; double S_F=0; mySVM svm= mySVM(); // Mat b=Mat(1,train.size().width,CV_32FC1); Mat results=Mat(1,train.size().width,CV_32FC1); Mat results1=Mat(pos,train.size().width,CV_32FC1); Mat results2=Mat(num-pos,train.size().width,CV_32FC1); int width=train.size().width; for (int i =0;i<pos;i++) { Mat b=Mat(train,Rect(0,i,width,1)); S_Z+=svm.get_calc_liner(sv.size().height,sv.size().width,sv,b,results,alpha,0)-rho; Mat mm=results1(Rect(0,i,width,1)); results.copyTo(mm); } for (int i =pos;i<num;i++) { Mat b=Mat(train,Rect(0,i,width,1)); S_F+=svm.get_calc_liner(sv.size().height,sv.size().width,sv,b,results,alpha,0)-rho; Mat mm=results2(Rect(0,i-pos,width,1)); results.copyTo(mm); } double A=-S_F/S_Z; double BB=-1/(A*SZ_num+SF_num); int count =sv.size().width; int con=count/36; // Mat Bi=Mat(1,count,CV_32FC1); // Mat block=Mat(train.size().height,36,CV_32FC1); vector<float> m1; vector<float> m2; vector<float>bi; int hei=results1.size().height; int cou=count; for (int i=0;i<count;i++) { Mat block_Z=Mat(train,Rect(i,0,1,results1.size().height)); block_Z=block_Z; Mat block_F=Mat(train,Rect(i,pos,1,results2.size().height)); block_F=block_F; Scalar_<double> l1; l1=sum(block_Z); Scalar_<double> l2; l2=sum(block_F); m1.push_back(l1.val[0]); m2.push_back(l2.val[0]); if((i+1)%count==0) { Mat mm1(m1); Mat mm2(m2); mm1=A*mm1; for (int j=0;j<con;j++) { Mat sv_=Mat(sv,Rect(j*36,0,36,1)); Mat m_1=Mat(mm1,Rect(0,j*36,1,36)); Mat m_2=Mat(mm2,Rect(0,j*36,1,36)); Mat m_=m_1+m_2; Mat aa=sv_*m_; aa=aa*BB; bi.push_back(aa.at<float>(0,0));//得到每个Bi的值 } Mat Bi(bi); } } return bi; } vector<float> get_ceshi(Mat &test,Mat &sv,double *alpha,vector<float>Bi) { int test_num=test.size().height; int count = test.size().width/36; int count_ = test.size().width; vector<float>dd; for(int i =0;i!=test_num;++i) { Mat s=Mat(test,Rect(0,i,count_,1)); for (int j=0;j!=count;++j) { Mat ss=Mat(s,Rect(j*36,0,36,1)); Mat svs=Mat(sv,Rect(j*36,0,36,1)); ss=ss.reshape(1,36); Mat dst =svs*ss+Bi[j]; dd.push_back(dst.at<float>(0,0)); } } return dd; } #include<iterator> int _tmain(int argc, _TCHAR* argv[]) { Mat b;//存储index Mat c; Mat test;//用于RESIZE的矩阵 mySVM ssvm = mySVM(); ssvm.load("2.xml"); Mat tezheng; string name="train.txt"; tezheng=get_hog(name); int fenleiqi =3;//对于线性核来说这里只能是0,而高斯核的话有几个分类器就有几个 int *m= ssvm.get_sv_index(fenleiqi);//读取索引 int count= ssvm.get_support_vector_count();//获取一共有多少个支持向量 static int var_count =ssvm.get_var_count();//支持向量的维数 //const float *sv= ssvm.get_support_vector(1);//获取第几个支持向量 double rho = ssvm.get_rho(fenleiqi);//对应第几个分类器 double *alpha = ssvm.get_alpha(fenleiqi); float **vesc=0; ///////////////////////////////////////////////////////// ///////////////////获取index索引/////////////////////////// for (int i=0;i<count;i++) { int uu=(int)(m[i]); if (uu<0||uu>count) break; b.push_back(uu); } /////////////////////////////////////////////////////// int * p;//指向index float * pp;//指向一个分类器的支持向量 static int len=b.size().height;//一个分类器支持向量的个数 Mat a=Mat(len,var_count,CV_32FC1);//开辟存储支持向量的Mat空间 //float *aa[len]; //////////////////////////////////////////////////////////////// /////////////////生成了向量里面的所有值/////////////////////// for (int i =0;i<len;i++) { p=b.ptr<int>(0); pp=a.ptr<float>(i); const float *sv= ssvm.get_support_vector(p[i]);//获取第几个支持向量 for (int j =0;j<var_count;j++) { float u=(float)*(sv++); pp[j]=u;//获取单个值 } } ///////////////////////////////////// //////////////////////////////////////////////////////////////////// CvSVMParams param; param= ssvm.get_params(); int type= param.kernel_type; //得到kernel类型 vector<float>descriptors; //////////////////存入图片名//////////////////// /////////////////////////////////////////////////////////////////// vector<string> img_path;//输入文件名变量 ifstream svm_data( "fufu.txt" ); string buf; while( svm_data )//将训练样本文件依次读取进来 { if( getline( svm_data, buf ) ) { img_path.push_back( buf );//图像路径 } } svm_data.close();//关闭文件 ///////////////////////////////////////////////////////////////////// Mat img =imread(img_path[8]);//读取图像 resize(img,test,Size(winSize,winSize)); hog->compute(test,descriptors,Size(1,1), Size(0,0)); Mat another(descriptors);//hog特征 another = another.reshape(1,1); Mat results=Mat(1,var_count,CV_32FC1);//相乘的结果矩阵 int vec_count=b.size().height;//读取有多少个支持向量 Mat results1=Mat(1,vec_count,CV_32FC1);//相乘的结果矩阵 ////////////////////////////计算SVM的值,opencv默认是大于零为正,小于零为负//////////////////// //double sum= ssvm.get_calc_liner(vec_count,var_count,a,another,results,alpha,0)-rho; //////////////////////////////通过计算可以自己制定正负的边间/////////////////////////////////////////////////// //////////////////////////////////////////////偏置为负值是因为,经过验证得到的/////////////////////////////////// double sum1 = ssvm.get_calc_rbf(vec_count,var_count,a,another,results1,alpha)-rho; /////////////////////////////////////////////////////////////////////////////////// // vector<float> Bi=get_Bi(a,tezheng,200,alpha,rho,another);//得到Bi的值 // double bi_sum=0; // for(auto i=Bi.cbegin();i!=Bi.cend();++i) // { // bi_sum+=*i; // } ///////////////////////////////////////////////////////////////////////////////////// // // string test_filename="fufu.txt"; // Mat test_=get_hog(test_filename); // // vector<float>test_score= get_ceshi(test_,a,alpha,Bi);//获得N*49个得分 return 0; }