[置顶] OPENCV 改写SVM的计算可以自己控制边界的值


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;
}






   

你可能感兴趣的:(opencv,svm改写)