opencv2笔记03-线性判别分析(LDA)

1. 线性判别分析(二类情况)

判别准则函数:
J(w)=|μ1~μ2~|2S1~2+S2~2
其中:

1.d维x空间
各类样本的均值向量:
μi=1Nixωix
类内离散度矩阵:
Si=xωi(xμi)(xμi)T
总类内离散度矩阵
Sw=S1+S2
类间离散度矩阵:
Sb=μ1μ2μ1μ2T

2.一维y空间
各类样本的均值:
μi~=1Niyωiy=1NixωiwTx
μi~=wTμi
类内离散度
Si~2=yωi(yμ~i)2
Si~2=xωi(wTxwTμi)2
Si~2=xωiwT(xμi)(xμi)Tw
Si~2=wTSiw
总类内离散度
Sw~=S1~2+S2~2
Sw~=wT(S1+S2)w
Sw~=wT(Sw)w

最终:
J(w)=wTSbwwTSww

2. 线性判别分析(多类情况)

有C个类别,需要K维向量(或者叫做基向量)来做投影。
W=[w1w2...wk]T
y=WTx

1.d维x空间
类内离散度矩阵:
Si=xωi(xμi)(xμi)T
总类内离散度矩阵
Sw=ci=1Si
类间离散度矩阵(每类均值点相对于样本中心的散列情况):
Sb=ci=1NiμiμμiμT
其中 μ 为所有样本的均值:
μ=1Nxx=1NxwiNiμi

2.k维y空间
μi~=1Niyωiy
μ~=1Nyy
类内离散度矩阵:
Si~=yωi(yμi~)(yμi~)T
总类内离散度
Sw~=ci=1Si~=ci=1yωi(yμi~)(yμi~)T
类间离散度矩阵(每类均值点相对于样本中心的散列情况):
Sb~=ci=1Niμ~iμ~μ~iμ~T

最终:
J(w)=|S~b||S~w|=wTSbwwTSww

3. 求解(Fisher linear discrimination)

利用Lagrange乘法算子求解:
L(w,λ)=wTSbwλ(wTSwwc)
Lw=SbwλSww=0
SbwλSww=0
即:
Sbw=λSww
S1wSbw=λw
Sb=μ1μ2μ1μ2T
Sbw=μ1μ2μ1μ2Tw=μ1μ2λw 其中 λw 为常数
S1wμ1μ2λw=λw
由于对w扩大缩小任何倍不影响结果,因此可以约去两边的未知常数 λwλ ,得到
S1wμ1μ2=w

代码实现:

int cv_lda(void)  
{  
    //sampledata  
    double sampledata[6][2]={{0,1},{0,2},{2,4},{8,0},{8,2},{9,4}};  
    Mat mat=Mat(6,2,CV_64FC1,sampledata);  
    //labels  
    vector<int>labels;  

    for(int i=0;i<mat.rows;i++)  
    {  
        if(i<mat.rows/2)  
        {  
            labels.push_back(0);  
        }  
        else  
        {  
            labels.push_back(1);  
        }  
    }  

    //do LDA  
    //初始化并计算,构造函数中带有计算  
    LDA lda=LDA(mat,labels,1);  
    //get the eigenvector  
    //获得特征向量  
    Mat eivector=lda.eigenvectors().clone();  

    cout<<"特征向量(double)类型:"<<endl;  
    for(int i=0;i<eivector.rows;i++)  
    {  
        for(int j=0;j<eivector.cols;j++)  
        {  
            cout<<eivector.ptr<double>(i)[j]<<" ";  
        }  
        cout<<endl;  
    }  


    //------------------------------计算两个类心------------  
    //针对两类分类问题,计算两个数据集的中心  
    int classNum=2;  
    vector<Mat> classmean(classNum);  
    vector<int> setNum(classNum);  

    for(int i=0;i<classNum;i++)  
    {  
        classmean[i]=Mat::zeros(1,mat.cols,mat.type());  //初始化类中均值为0  
        setNum[i]=0;  //每一类中的条目数  
    }  

    Mat instance;  
    for(int i=0;i<mat.rows;i++)  
    {  
        instance=mat.row(i);//获取第i行  
        if(labels[i]==0)  //如果标签为0  
        {     
            add(classmean[0], instance, classmean[0]);  //矩阵相加  
            setNum[0]++;  //数量相加  
        }  
        else if(labels[i]==1)  //对于第1类的处理  
        {  
            add(classmean[1], instance, classmean[1]);  
            setNum[1]++;  
        }  
        else  
        {}  
    }  
    for(int i=0;i<classNum;i++)   //计算每一类的均值  
    {  
        classmean[i].convertTo(classmean[i],CV_64FC1,1.0/static_cast<double>(setNum[i]));  
    }  
    //----------------------------------END计算类心-------------------------  


    vector<Mat> cluster(classNum);  //一共2类  


    cout<<"特征向量:"<<endl;  
    cout<<eivector<<endl;   //此时的特征向量是一个列向量  


    cout<<endl<<endl;  
    cout<<"第一种方式(手动计算):"<<endl;  
    //1.投影的第一种方式:Y=X*W  
    //有的教程写成Y=W^T*X,(此时的X是列向量看待的所以需要将w转置)  
    for(int i=0;i<classNum;i++)  
    {  
        cluster[i]=Mat::zeros(1,1,mat.type()); //初始化0  
        //特征向量的转置同类均值相乘)  
        cluster[i]=classmean[i]*eivector;  
    }  

    cout<<"The project cluster center is:"<<endl;  //计算均值的投影  
    for(int i=0;i<classNum;i++) //输出两类中心的投影值  
    {  
        cout<<cluster[i].at<double>(0)<<endl;  
    }  

    //2.第二种方式使用内置函数计算  
    //第一个中心  
    cout<<endl<<"第二种方式:";  
    cout<<endl<<"第一个类均值的投影:"<<endl;  
    cout<<lda.project(classmean[0]).at<double>(0);  
    cout<<endl<<"第二个类均值的投影"<<endl;  
    cout<<lda.project(classmean[1]).at<double>(0);  


    system("pause");  
    return 0;  
}  

结果:
这里写图片描述

reference:
[1]. http://www.cnblogs.com/jerrylead/archive/2011/04/21/2024384.html
[2]. http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值