在OpenCV中使用PCA降低尺寸

nas*_*002 3 c++ opencv pca

我有一个3xN Mat数据,它保存在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, ...
Run Code Online (Sandbox Code Playgroud)

我想将我的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();
Run Code Online (Sandbox Code Playgroud)

Sae*_*omi 6

我们来看一个2D数据的例子

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];
Run Code Online (Sandbox Code Playgroud)

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

Mat x(10,1,CV_32F,X_array);   //Copy X_array to Mat (PCA need Mat form)
Mat y(10,1,CV_32F,Y_array);   //Copy Y_array to Mat
Run Code Online (Sandbox Code Playgroud)

然后我们将附加xy a cv::Mat data,我们这样做,因为整个数据必须统一(如果您的数据是2D信号,如图像,那么您可以通过重塑简单地将2D信号转换为1D信号)

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
Run Code Online (Sandbox Code Playgroud)

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]
Run Code Online (Sandbox Code Playgroud)

然后使用cv::PCA我们可以计算eigenValueseigenVectors2D信号.

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 component 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;
Run Code Online (Sandbox Code Playgroud)

我们eigenValue并且eigenvectors会像下面:

EigenValue=
         [1.155625;
          0.044175029]


EigenVectors=
        [0.67787337, 0.73517865;
         0.73517865, -0.67787337]
Run Code Online (Sandbox Code Playgroud)

如您所见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)
Run Code Online (Sandbox Code Playgroud)

在您的示例中,如果要将3D转换为2D,则将尺寸设置为保留2,如果要转换为1D,则将此参数设置为1,如下所示

1D

int numOfComponents= 1;
PCA pca(data, cv::Mat(), CV_PCA_DATA_AS_ROW, numOfComponents);
Run Code Online (Sandbox Code Playgroud)

2

int numOfComponents= 2;
PCA pca(data, cv::Mat(), CV_PCA_DATA_AS_ROW, numOfComponents);
Run Code Online (Sandbox Code Playgroud)