SVM支持向量机回归openCv c++

Posted

技术标签:

【中文标题】SVM支持向量机回归openCv c++【英文标题】:SVM Support Vector Machine regression openCv c++ 【发布时间】:2013-08-21 12:52:44 【问题描述】:

谁能向我解释如何在 openCv c++ 中使用 SVM 和回归? 回归应该返回一个值,这个值可以是图像中的一个位置(坐标 x 和 y)?还是一个数字?

我必须在视频分析中使用它。 我有三个点,我知道整个视频的轨迹。 我想用其中两个的轨迹来推断第三个的轨迹。 所以我想用这些轨迹训练一个 SVM。

我正在考虑这样组织我的训练数据和标签:

训练数据:每帧中两个点的位置(x,y) 标签:每帧第三个点的位置(x,y)

这是正确的方法吗?还是我应该这样组织:

训练数据:每帧我加负例的三个点的位置(x,y),改变第三个点的位置,模拟一个错误的训练集 labels:如果第三个点位置属于它的轨迹,则为1,如果它属于错误训练集,则为-1

【问题讨论】:

您确定可以(或应该)将 SVM 用于回归问题吗? SVM 是分类器,而不是回归算法。 @GilLevi 在docs.opencv.org/modules/ml/doc/support_vector_machines.html 中可以将参数 CvSVMParams 指定为允许回归的 CvSVM::EPS_SVR 或 CvSVM::NU_SVR 【参考方案1】:

SVM 可用于回归:见此处http://alex.smola.org/papers/2003/SmoSch03b.pdf 但可能对于你的问题会更适合多变量 RVM 看这里(带有 C++ 源代码):http://mi.eng.cam.ac.uk/~at315/MVRVM.htm

这是我的opencv版本的代码:

#include<iostream>
#include<fstream>
#include<cstdlib>
#include<windows.h>
#include<string>
#include<vector>
#include<opencv2/opencv.hpp>
using namespace std;

using namespace cv;
#define COUT_VAR(x) cout << #x"=" << x << endl;
#define SHOW_IMG(x) namedWindow(#x);imshow(#x,x);waitKey(20);

//calculates the conolution of two ploynoimals
// n  - size of polynomial x
// m  - size of polynomial y
// z  - resultant polynomial after the convolution
void conv(int n,int m,double* x,double* y,double* z)

    int i,j;
    for(i=0; i<(n+m-1); i++)
    
        z[i]=0.0;
        for(j=0; j<n; j++)
        
            if(((i-j)>=0)&& ((i-j)<m))
            
                z[i]+=x[j]*y[i-j];
            
        
    



//calculates poly noimal coeefeicents from a number of roots
//input
//n - number of roots
//x - array of roots
//ouput
//y - array of polynomial coefficnets

void poly(int n,double* x,double* y)

    int i,j;
    for(j=0; j<=n; j++)
    
        y[j]=0.0;
    
    y[0]=1;
    double temp[20];
    for(j=0; j<n; j++)
    
        for(i=0; i<=(j); i++)
        
            temp[i+1]=y[i+1]-x[j]*y[i];
        
        for(i=0; i<=(j); i++)
        
            y[i+1]=temp[i+1];
        
    


//find the roots of a polynomial

int Roots(int n,double* cof,double*roots)

    bool fnzf=false;
    int k=0,i;
    double acof[100];
    for(i=0; i<n; i++)
    
        if(!fnzf)
        
            if(fabs(cof[i])>10e-6)
            
                fnzf=true;
                acof[k]=cof[i];
                k++;
            
        
        else
        
            acof[k]=cof[i];
            k++;
        
    
    if(k==0)
    
        return 0;
    

    Mat a(k,1,CV_64FC1);

    for(i=0; i<k; i++)
    
        a.at<double>(i)=acof[i];
    
    Mat r;
    cv::solvePoly(a,r);
    Mat ch[2];
    cv::split(r,ch);

    Mat b=ch[0].clone();

    for(i=0; i<b.rows; i++)
    
        roots[i]=b.at<double>(i);
    

    return b.rows;






//this function sloves a polynomial equation of a single hyperparameter

void SolveForAlpha(int n,Mat& q, Mat& s,Mat& Q,Mat S,double old_alpha,double& newAlpha,double& l_inc)

    double ALPHA_MAX=1e12;
    double C[500], P[500], PP[500], SS[500], CC[500];
    int i,k,j;
    for(i=0; i<n; i++)
    
        C[i]=0.0;
    
    for(i=0; i<(2*n-1); i++)
    
        CC[i]=0.0;
    
    for(i=0; i<n; i++)
    
        k=0;
        for(j=0; j<n; j++)
        
            if(i==j)
            
                continue;
            
            SS[k]=-s.at<double>(j);
            k++;
        
        poly(n-1,SS,P);
        conv(n,n,P,P,PP);
        for(j=0; j<n; j++)
        
            C[j]=C[j]+P[j];
        
        for(j=0; j<(2*n-1); j++)
        
            CC[j]=CC[j]+ q.at<double>(i)*q.at<double>(i)*PP[j];
        
    
    for(i=0; i<n; i++)
    
        SS[i]=-s.at<double>(i);
    
    poly(n,SS,P);
    conv(n+1,n+1,P,P,PP);
    for(i=0; i<(2*n+1); i++)
    
        PP[i]=n*PP[i];
    
    double CC0[500];
    conv(n+1,n,P,C,CC0);
    double CCC[500];
    CCC[0]=CC0[0];
    for(i=1; i<(2*n); i++)
    
        CCC[i]=CC[i-1]+CC0[i];
    
    CCC[2*n]=0;
    bool fnonzero=false;
    double aa[1000];
    k=0;
    for(i=0; i<(2*n+1); i++)
    
        aa[i]=PP[i]-CCC[i];
    
    double roots[100];
    int nroots=Roots(2*n+1,aa,roots);
    roots[nroots]=ALPHA_MAX;
    nroots++;
    double L[100];
    double alphas[100];
    for(i=0; i<100; i++)
    
        L[i]=0.0;
    
    k=0;
    for( i=0; i<nroots; i++)
    
        if(roots[i]<=0)
        
            continue;
        
        double new_alpha=roots[i];
        if((old_alpha>=(ALPHA_MAX-1))&& (new_alpha<ALPHA_MAX))
        
            alphas[k]=new_alpha;
            for(j=0; j<n; j++)
            
                L[k]=L[k]+ log(new_alpha/(new_alpha+s.at<double>(j)))+((q.at<double>(j)*q.at<double>(j)/(new_alpha+s.at<double>(j))));
            
        
        else if((old_alpha<ALPHA_MAX)&& (new_alpha>=(ALPHA_MAX-1)))
        
            alphas[k]=new_alpha;
            for(j=0; j<n; j++)
            
                L[k]=L[k]- log(old_alpha/(old_alpha+s.at<double>(j)))-((q.at<double>(j)*q.at<double>(j)/(old_alpha+s.at<double>(j))));
            
        
        else if((old_alpha<ALPHA_MAX)&&(new_alpha<ALPHA_MAX))
        
            alphas[k]=new_alpha;
            double ad=(1/new_alpha)-(1/old_alpha);
            for (j=0; j<n; j++)
            
                L[k]=L[k]+ log(new_alpha/(new_alpha+s.at<double>(j)))+((q.at<double>(j)*q.at<double>(j)/(new_alpha+s.at<double>(j)))) -log(old_alpha/(old_alpha+s.at<double>(j)))-((q.at<double>(j)*q.at<double>(j)/(old_alpha+s.at<double>(j))));
            
        
        else
        
            alphas[k]=new_alpha;
            L[k]=0.0;
        
        k++;
    
    l_inc=-2000000.0;
    for(i=0; i<k; i++) if(L[i]>l_inc)
    
        l_inc=L[i];
        newAlpha=alphas[i];
    

//-------------------------------------------------------------------------------

Mat distSqrd(Mat& X,Mat& Y)

    Mat D2;
    int nx  = X.rows;
    int ny  = Y.rows;
    Mat xsq,ysq;
    pow(X,2,xsq);
    pow(Y,2,ysq);
    Mat sumsqx;
    cv::reduce(xsq,sumsqx,1,CV_REDUCE_SUM);
    Mat sumsqy;
    cv::reduce(ysq,sumsqy,1,CV_REDUCE_SUM);
    D2  = sumsqx*Mat::ones(1,ny,CV_64FC1) + Mat::ones(nx,1,CV_64FC1)*sumsqy.t() - 2*(X*(Y.t()));
    return D2;




Mat kernelFunction(Mat& X1,Mat& X2,double lenscal)

    Mat K;
    int N1=X1.rows;
    int N2=X2.rows;
    int d=X1.cols;
    double eta  = 1.0/pow(lenscal,2);
    exp(-eta*distSqrd(X1,X2),K);
    Mat K1=Mat(K.rows,K.cols+1,CV_64FC1);
    K.copyTo(K1( Range(0,K.rows),Range(1,K1.cols)));
    K1.col(0)=1;
    return K1;


//output
//  weights     trained weights
//  RV_idxs     index into column of PHI of relevant basis

//input
// PHI      basis function/design matrix
//  t       targetmatrix
// N      number of training examples
// M      number of basis functions
//[ N M] =size(PHI)
// P the number of target dimensions
// [ N P]= size(t)
// beta initial beta values for the target dimensions
// beta is set initially to for each target dimension p,  beta_p=(1/(var(t_p))


void TrainRVM( Mat &X,Mat &t,double KernelWidth,int Max_It, Mat& beta,Mat &weights,Mat& RV_idxs,Mat& RV_X)

    int N=X.rows;
    int M=N+1;
    int P=t.cols;

    int i,j,p,k,MM;
    const double INF=1e36;

    beta=Mat (P,1,CV_64FC1);
    Scalar mean,stddev;
    // начальное приближение точности
    for(int i=0;i<P;i++)
    
        cv::meanStdDev(t.col(i),mean,stddev);
        beta.at<double>(i)=1.0/(stddev[0]*stddev[0]+10.0*DBL_EPSILON);
    

    Mat nonZero=Mat::zeros(M,1,CV_8UC1);

    Mat PHI = kernelFunction(X,X,KernelWidth);
    Mat PHIt;

    PHIt=PHI.t()*t;

    const double ALPHA_MAX=1e12;

    Mat alpha(M,1,CV_64FC1);
    alpha=ALPHA_MAX;

    Mat gamma=Mat::ones(M,1,CV_64FC1);

    bool run_cond;

    Mat PHI2=PHI.t()*PHI;

    Mat s(P,1,CV_64FC1);
    Mat S(P,1,CV_64FC1);
    Mat q(P,1,CV_64FC1);
    Mat Q(P,1,CV_64FC1);
    Mat l_inc(M,1,CV_64FC1);
    Mat newAlpha(M,1,CV_64FC1);

    double max_alpha, max_linc=-INF;
    int max_index=-1;

    int maxidx[2];
    cv::minMaxIdx(l_inc,0,0,0,maxidx);
    max_index=maxidx[0];

    max_alpha=newAlpha.at<double>(max_index);
    alpha.at<double>(max_index)=max_alpha;

        //start the iterations
        run_cond=true;
        i=1;
        while(run_cond)
        
            MM=0;

            for(j=0; j<M; j++)
            
                if(alpha.at<double>(j)<ALPHA_MAX)
                
                    nonZero.at<unsigned char>(j)=true;
                    MM++;
                
                else
                
                    nonZero.at<unsigned char>(j)=false;
                
            

            Mat PHI_nz=Mat::zeros(N,MM,CV_64FC1);
            Mat alpha_nz(MM,1,CV_64FC1);

            k=0;
            for(j=0; j<M; j++)
            
                if(nonZero.at<unsigned char>(j))
                
                    alpha_nz.at<double>(k)=alpha.at<double>(j);
                    PHI.col(j).copyTo(PHI_nz.col(k));
                    k++;
                
            

            vector<Mat> SIGMA_nz;
            Mat HH=(PHI_nz.t()*PHI_nz);

            for(p=0; p<P; p++)
            
                Mat H=beta.at<double>(p)*HH;
                H.diag()+=alpha_nz;
                SIGMA_nz.push_back(H.inv(cv::DECOMP_SVD));
            

            Mat dp_tmp;
            Mat phi;

            for(k=0; k<M; k++)
            
                phi=PHI.col(k);
                for(j=0; j<P; j++)
                                   
                    dp_tmp=beta.at<double>(j)*phi.t()*phi-beta.at<double>(j)*beta.at<double>(j)*phi.t()*PHI_nz*SIGMA_nz[j]*PHI_nz.t()*phi;
                    S.at<double>(j)=dp_tmp.at<double>(0);
                    dp_tmp=beta.at<double>(j)*phi.t()*t.col(j)-beta.at<double>(j)*beta.at<double>(j)*phi.t()*PHI_nz*SIGMA_nz[j]*PHI_nz.t()*t.col(j);
                    Q.at<double>(j)=dp_tmp.at<double>(0);
                

                if(alpha.at<double>(k)<ALPHA_MAX)
                
                    s=alpha.at<double>(k)*S/(alpha.at<double>(k)-S);
                    q=alpha.at<double>(k)*Q/(alpha.at<double>(k)-S);
                
                else
                
                    s=S.clone();
                    q=Q.clone();
                
                SolveForAlpha(P,q,s,Q,S,alpha.at<double>(k),newAlpha.at<double>(k),l_inc.at<double>(k));
            

            cv::minMaxIdx(l_inc,0,&max_linc,0,maxidx);
            max_index=maxidx[0];
            max_alpha=newAlpha.at<double>(max_index);

            alpha.at<double>(max_index)=max_alpha;

            weights=Mat(MM,P,CV_64FC1);

            for(j=0; j<P; j++)
            
                Mat tmp=beta.at<double>(j)*SIGMA_nz[j]*PHI_nz.t()*t.col(j);
                tmp.copyTo(weights.col(j));

                double gamma_sum=0.0;

                gamma_sum=sum(1.0-alpha_nz.t()*SIGMA_nz[j].diag())[0];

                Mat error=t.col(j)-PHI_nz*(weights.col(j));
                pow(error,2,error);
                double ED=0.0;
                ED=sum(error)[0];
                beta.at<double>(j)=(((double)N)- gamma_sum)/ED;
            
            i++;

            // Критерий выхода по количеству итераций или по максимальному
            // изменению не превышающему заданный порог.
            if(i>Max_It || max_linc<(100.0*DBL_EPSILON))
            
                run_cond=false;
            
        

        Mat nonZero_m=Mat(nonZero);
        // Количество релевантных векторов
        int nRVS=cv::countNonZero(nonZero_m);
        // Индексы векторов
        RV_idxs=Mat(nRVS,1,CV_32SC1);
        // Координаты векторов (вторая координата по каждому измерению вычисляется)
        RV_X=Mat(nRVS-1,1,CV_64FC1);

        int ind=0;

        for(int i=0;i<nonZero.rows;i++)
        
            if(nonZero.at<unsigned char>(i))
            
                RV_idxs.at<int>(ind)=i;
                // первый индекс соответствует добавленной единице смещения
                // поэтому начинаем со второго.
                if(i>0)
                
                RV_X.at<double>(ind-1)=X.at<double>(i);
                
                ind++;
            
        


// -------------------------------------------------------------------
// Загрузка матриц. Для взаимодействия с матлабом во время отладки.
// -------------------------------------------------------------------
void ReadMat(ifstream& ifs,Mat& M)

    int rows;
    int cols;
    ifs >> rows;
    char comma;
    ifs >> comma;
    ifs >> cols;
    M=Mat(rows,cols,CV_64FC1);
    for(int i=0;i<rows;i++)
    
        for(int j=0;j<cols;j++)
        
            ifs >> M.at<double>(i,j);
            if(j!=cols-1)ifs >> comma;
        
    

// -------------------------------------------------------------------
// MATLAB matrix loading (for debug purpose)
// -------------------------------------------------------------------
Mat LoadMatrix(string filename)

    Mat M;
    ifstream ifs(filename);
    if (ifs.is_open())
    
        ReadMat(ifs,M);
        ifs.close();
    
    return M;


void PredictRVM(Mat& X,Mat& RV_X,Mat& weights,double KernelWidth,Mat& y_rvm)

    Mat PHI=kernelFunction(X,RV_X,KernelWidth);
    y_rvm=PHI*weights;


int main()

    int gH=600;
    int gW=600;
    Mat graph=Mat::zeros(gH,gW,CV_8UC3);
    namedWindow("graph");


    Mat t=LoadMatrix("t.txt");
    Mat X=LoadMatrix("X.txt");

    for(int i=0;i<X.rows;i++)
    
        circle(graph,Point(i*6,gW-(t.at<double>(i,0)+1)*160),2,Scalar(0,255,255),-1,CV_AA);
        circle(graph,Point(i*6,gW-(t.at<double>(i,1)+1)*160),2,Scalar(0,255,255),-1,CV_AA);
    

    imshow("graph",graph);
    waitKey(10);

    cout.precision(15);

    Mat weights;
    Mat RV_idxs;
    Mat beta;
    Mat RV_X;
    double KernelWidth=4;
    TrainRVM(X,t,KernelWidth,50, beta,weights,RV_idxs,RV_X);

    COUT_VAR(weights);

    Mat y_rvm;
    PredictRVM(X,RV_X,weights,KernelWidth,y_rvm);

    FileStorage fs("test.yml", FileStorage::WRITE);
    fs << "weights" << weights;
    fs << "RV_X" << RV_X;
    fs.release();


    for(int i=1;i<X.rows;i++)
    
        Point2d p11(i*6,gW-(y_rvm.at<double>(i,0)+1)*160);
        Point2d p21(i*6,gW-(y_rvm.at<double>(i,1)+1)*160);
        i--;
        Point2d p12(i*6,gW-(y_rvm.at<double>(i,0)+1)*160);
        Point2d p22(i*6,gW-(y_rvm.at<double>(i,1)+1)*160);
        i++;
        line(graph,p11,p12,Scalar(255,255,0),1,CV_AA);
        line(graph,p21,p22,Scalar(255,255,0),1,CV_AA);
    

    imshow("graph",graph);

    waitKey();

    return 0;


【讨论】:

以上是关于SVM支持向量机回归openCv c++的主要内容,如果未能解决你的问题,请参考以下文章

支持向量机原理线性支持回归

OpenCV支持向量机(SVM)介绍

分类和回归-支持向量机SVM算法

支持向量机

原创支持向量机原理线性支持回归

人工智能选股系列——支持向量机(SVM)模型