cv :: eigen创建转置特征向量w.r.t.来自matlab的那些

时间:2017-04-09 14:23:53

标签: c++ matlab opencv pca eigenvector

我已经编写了用于计算PCA的this matlab函数的C ++版本(注意这里的数据是列式的,就像在原始的matlab代码中一样)。如果您有兴趣:

  • U是获得的旋转矩阵
  • lamsx
  • 的特征值
  • Utmu只是U.t()*mu
  • x是数据矩阵
  • nPCs我们要保留的主要组件的数量

这是我的C ++代码(随意查看):

template <typename T>
void cc::relja_PCA(T &U, T &lams, T &mu, T &Utmu, const T &x, size_t nPCs, const bool substractMean){
    int nPoints = x.cols;
    int nDims = x.rows;

    if(nPCs <= 0)
        nPCs = nDims;

    if(substractMean){
        cv::reduce(x,mu, 1, CV_REDUCE_AVG);
        for(int i=0; i<nPoints; i++){
            x.col(i) = x.col(i) - mu;
        }
    }
    else
        mu = cv::Mat::zeros(1, nDims, x.type());

    bool doDual;
    T X2;
    if(nDims<=nPoints){
        doDual = false;
        cv::mulTransposed(x,X2, false);
    }
    else{
        doDual = true;
        cv::mulTransposed(x, X2, true);
    }

    X2 /= (nPoints-1);

    cv::eigen(X2, lams, U);

    U = U.t();


    //save only the first nPCs elements of L, which is already a vector
    if(nPCs>0 && nPCs<X2.rows){
        lams(cv::Range(0, nPCs), cv::Range(0, lams.cols)).copyTo(lams);
        U(cv::Range(0,U.rows),cv::Range(0,nPCs)).copyTo(U);
    }

    if (doDual){

        cv::Mat1f diag = lams.clone();
        for(int i=0; i<diag.rows; i++)
            diag.at<float>(i,1) = diag.at<float>(i,1) > 1e-9 ? diag.at<float>(i,1) : 1e-9;
        cv::sqrt(diag, diag);
        diag = 1.0f/diag;
        diag = cv::Mat::diag(diag);
        U = x * (U * diag / std::sqrt(nPoints-1)) ;
    }

    Utmu = U.t() * mu;

}

使用以下函数调用该函数:

//given some nPCs
cv::Mat1f U, lams, mu, Utmu;
cc::relja_PCA(U, lams, mu, Utmu, mat, nPCs);

一个特征列向量feat的投影用:

完成
feat = U.t()*feat - Utmu; //or equivalently feat = U.t() * (feat- mu); 

我有两个问题:

  1. 为什么U中的cv::eigen(X2, lams, U);[U, L]= eigs(X2, nPCs);的转置版本?如您所见,为了保证原始代码的结果相同,我必须U=U.t();。为什么?我在使用5x4玩具矩阵和nPC = 3测试代码时注意到了这一点。
  2. We know表示特征向量的符号并不重要,但我想知道这是否会在这种情况下产生任何问题。我注意到U的一些列与w.r.t相反。来自matlab的那些。

0 个答案:

没有答案