在 OpenCV 中使用 PCA 进行降维
Dimension reduction with PCA in OpenCV
我有一个 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, ...
我想将我的 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();
这是二维数据集的示例。
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,我们可以计算出二维信号的特征值和特征向量。
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;
我们的eigenValue
和eigenvectors
将如下所示:
EigenValue=
[1.155625;
0.044175029]
EigenVectors=
[0.67787337, 0.73517865;
0.73517865, -0.67787337]
正如您在eigenValue
中看到的,第一行的值为 1.55,比 0.044 大得多。所以在 eigenvectors
中,第一行比第二行最重要,如果你在 EigenVectors
中保留相应的行,你几乎可以在一维中拥有整个数据(只是你压缩了数据,但是你的新一维数据中可用的二维图案)
我们如何提取最终数据?
要提取最终数据,您可以将 eigenVector
乘以原始数据并获得新数据,例如,如果我想将我的数据转换为一维数据,我可以使用以下代码
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);
我有一个 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, ...
我想将我的 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();
这是二维数据集的示例。
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,我们可以计算出二维信号的特征值和特征向量。
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;
我们的eigenValue
和eigenvectors
将如下所示:
EigenValue=
[1.155625;
0.044175029]
EigenVectors=
[0.67787337, 0.73517865;
0.73517865, -0.67787337]
正如您在eigenValue
中看到的,第一行的值为 1.55,比 0.044 大得多。所以在 eigenvectors
中,第一行比第二行最重要,如果你在 EigenVectors
中保留相应的行,你几乎可以在一维中拥有整个数据(只是你压缩了数据,但是你的新一维数据中可用的二维图案)
我们如何提取最终数据?
要提取最终数据,您可以将 eigenVector
乘以原始数据并获得新数据,例如,如果我想将我的数据转换为一维数据,我可以使用以下代码
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);