在OpenCV中使用PCA进行降维

3
我有一个3xN的矩阵数据,保存在yaml文件中,长这样:
%YAML:1.0

data1: !!opencv-matrix
rows: 50
 cols: 3
 dt: d
 data: [ 7.1709999084472656e+01, -2.5729999542236328e+01,
   -1.4074000549316406e+02, 7.1680000305175781e+01,
   -2.5729999542236328e+01, -1.4075000000000000e+02,
   7.1639999389648438e+01, -2.5729999542236328e+01,
   -1.4075000000000000e+02, 7.1680000305175781e+01,
   -2.5729999542236328e+01, -1.4075000000000000e+02, ...

我想把我的3D数据降维到1D或者2D,然后在QwtPlotCurve上进行可视化。为了实现这个目的,我已经在OpenCV中实现了PCA函数,但是不知道如何从PCA结果中获取计算出来的X和Y坐标。
int numOfComponents= 100;
PCA pca(data, cv::Mat(), CV_PCA_DATA_AS_ROW, numOfComponents);

Mat mean= pca.mean.clone();
Mat eigenvalues= pca.eigenvalues.clone();
Mat eigenvectors= pca.eigenvectors.clone();

请使用Mat.at(int row, int col),具体说明请参见此处 - Joseph D.
1
你的意思是:for(int i= 0; i<numOfComponents; ++i) { Mat feature= pca.project(data.row(i)) } 这样做,还是我可以用 pca.project(data, resultMat); 投影新的维度? - nasil122002
1个回答

13

以下是一个二维数据集的示例。

x=[2.5, 0.5, 2.2, 1.9, 3.1, 2.3, 2, 1, 1.5, 1.1];
y=[2.4, 0.7, 2.9, 2.2, 3.0, 2.7, 1.6, 1.1, 1.6, 0.9];

我们可以使用以下代码在OpenCV中编写这些数组。
float X_array[]={2.5,0.5,2.2,1.9,3.1,2.3,2,1,1.5,1.1};
float Y_array[]={2.4,0.7,2.9,2.2,3.0,2.7,1.6,1.1,1.6,0.9};

cv::Mat x(10,1,CV_32F,X_array);   //Copy X_array to Mat (PCA need Mat form)
cv::Mat y(10,1,CV_32F,Y_array);   //Copy Y_array to Mat

接下来,我们将把x和y组合成一个统一的cv::Mat数据。因为整个数据必须在一个地方才能使用PCA函数,所以我们必须组合我们的数据。(如果您的数据是以二维格式,例如图像,则可以简单地将二维信号转换为一维信号并将它们组合)

x.col(0).copyTo(data.col(0));  //copy x into first column of data
y.col(0).copyTo(data.col(1));  //copy y into second column of data

最后一个代码之后的数据将会像下面这样:
data=
    [2.5, 2.4;
     0.5, 0.7;
     2.2, 2.9;
     1.9, 2.2;
     3.1, 3;
     2.3, 2.7;
     2,   1.6;
     1,   1.1;
     1.5, 1.6;
     1.1, 0.9]

使用cv::PCA,我们可以计算2D信号的特征值和特征向量。

cv::PCA pca(data,                 //Input Array Data
            Mat(),                //Mean of input array, if you don't want to pass it   simply put Mat()
            CV_PCA_DATA_AS_ROW,   //int flag
            2);                   // number of components that you want to retain(keep)
           


Mat mean=pca.mean;                // get mean of Data in Mat form
Mat eigenvalue=pca.eigenvalues;
Mat eigenvectors=pca.eigenvectors;

我们的eigenValueeigenvectors将如下所示:
EigenValue=
         [1.155625;
          0.044175029]


EigenVectors=
        [0.67787337, 0.73517865;
         0.73517865, -0.67787337]

eigenValue中可以看出,第一行的值为1.55,比0.044大得多。因此,在eigenvectors中,第一行比第二行更重要,如果保留与EigenVectors相应的行,则可以将几乎所有数据压缩为1D(简单地说,您已经压缩了数据,但新的1D数据中仍然包含2D模式)。

如何提取最终数据?

要提取最终数据,可以通过将eigenVector与原始数据相乘并获取新数据来实现。例如,如果要将数据转换为1D,则可以使用以下代码:

Mat final=eigenvectors.row(0)*data.t(); //firts_row_in_eigenVector * tranpose(data)

在您的例子中,如果您想将3D转换为2D,则将维度设置为保留2,如果您想转换为1D,则将此参数设置为1,如下所示。 1D
int numOfComponents= 1;
PCA pca(data, cv::Mat(), CV_PCA_DATA_AS_ROW, numOfComponents);

2

int numOfComponents= 2;
PCA pca(data, cv::Mat(), CV_PCA_DATA_AS_ROW, numOfComponents);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接