PCA原理及OpenCV实现

一、介绍

           PCA(principal component analysis)就是主分量分析,是一种常用的数据分析方法。PCA通过线性变换将原始数据变换为一组各维度线性无关的表示,可用于提取数据的主要特征分量,常用于高维数据的降维。通过数据降维可以实现数据的压缩,同时方便数据分析和提高算法的处理速度。PCA的原理就是通过正交变换,最大化样本协方差阵的对角元素,最小化非对角元素。但是PCA应用本身是基于一定假设的:

1.线性。即特征的变换是线性变换,作用有限,目前也有非线性的特征变换kernel PCA。

2.处理的数据分布式服从指数族概率密度函数,即能通过均值和协方差来表征数据的分布,因为只有在这个情况下信噪比和协方差矩阵才能表示噪声和数据冗余。(好在实际应用中常见的数据是服从高斯分布或近似高斯分布)。

二、PCA原理介绍

          关于PCA的理论与公式推导网络上很多,尴尬的是本人功底有限,理论方面这里就不列出啦。下面主要从Opencv应用的角度大概来讲讲自己对PCA具体怎么实现数据集降维的理解。
1、把原始数据中每个样本用一个向量表示,然后把所有样本组合起来构成一个矩阵,避免样本的单位的影响,样本集需要标准化。
2、求该矩阵的协方差矩阵。(关于协方差矩阵的理解大家可以看看这篇文章)
3、求步骤2中得到的协方差矩阵的特征值和特征向量。

(再将求出的特征向量按照特征值的大小进行组合形成一个映射矩阵,并根据指定的PCA保留的特征个数取出映射矩阵的前n行或者前n列作为最终的映射矩阵。映射矩阵是对原始数据的映射,从而来达到从高维度降维的目的)。

三、代码帮助理解

直接上代码吧,当作自己的备忘,有注释便于理解如何使用Opencv简单的实现PCA。

#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\ml\ml.hpp>
 
using namespace cv;
using namespace std;

void DoPca(const Mat &_data, int dim, Mat &eigenvalues, Mat &eigenvectors);
 
void printMat( Mat _data )
{
    Mat data = cv::Mat_<double>(_data);
    for ( int i=0; i<data.rows; i++ )
    {
        for ( int j=0; j< data.cols; j++ )
        {
            cout << data.at<double>(i,j) << "  ";
        }
        cout << endl;
    }
}
 
int main(int argc, char* argv[])
{
    float A[ 60 ]={ 
    1.5 , 2.3 , 1.5 , 2.3 , 1.5 , 2.3 , 
    3.0 , 1.7 , 3.0 , 1.7 , 3.0 , 1.7 , 
    1.2 , 2.9 , 1.2 , 2.9 , 1.2 , 2.9 , 
    2.1 , 2.2 , 2.1 , 2.2 , 2.1 , 2.2 ,
    3.1 , 3.1 , 3.1 , 3.1 , 3.1 , 3.1 , 
    1.3 , 2.7 , 1.3 , 2.7 , 1.3 , 2.7 , 
    2.0 , 1.7 , 2.0 , 1.7 , 2.0 , 1.7 , 
    1.0 , 2.0 , 1.0 , 2.0 , 1.0 , 2.0 , 
    0.5 , 0.6 , 0.5 , 0.6 , 0.5 , 0.6 , 
    1.0 , 0.9 , 1.0 , 0.9 , 1.0 , 0.9 }; 
 
    Mat DataMat = Mat::zeros( 10, 6, CV_32F );
 
    //将数组A里的数据放入DataMat矩阵中
    for ( int i=0; i<10; i++ )
    {
        for ( int j=0; j<6; j++ )
        {
            DataMat.at<float>(i, j) = A[i * 6 + j];
        }
    }
 
    // OPENCV PCA
    PCA pca(DataMat, noArray(), CV_PCA_DATA_AS_ROW);
 
    Mat eigenvalues;//特征值
    Mat eigenvectors;//特征向量
 
    DoPca(DataMat, 3, eigenvalues, eigenvectors);
 
    cout << "eigenvalues:" << endl;
    printMat( eigenvalues );
    cout << "\n" << endl;
    cout << "eigenvectors:" << endl;
    printMat( eigenvectors );
 
    system("pause");
    return 0;
}
 
 
void DoPca(const Mat &_data, int dim, Mat &eigenvalues, Mat &eigenvectors)
{
    assert( dim>0 );
    Mat data =  cv::Mat_<double>(_data);
 
    int R = data.rows;
    int C = data.cols;
 
    if ( dim>C )
        dim = C;

    //计算均值
    Mat m = Mat::zeros( 1, C, data.type() );
 
    for ( int j=0; j<C; j++ )
    {
        for ( int i=0; i<R; i++ )
        {
            m.at<double>(0,j) += data.at<double>(i,j);
        }
    }

    m = m/R; 
    //求取6列数据对应的均值存放在m矩阵中,均值: [1.67、2.01、1.67、2.01、1.67、2.01]
    

    //计算协方差矩阵
    Mat S =  Mat::zeros( R, C, data.type() );
    for ( int i=0; i<R; i++ )
    {
        for ( int j=0; j<C; j++ )
        {
            S.at<double>(i,j) = data.at<double>(i,j) - m.at<double>(0,j); // 数据矩阵的值减去对应列的均值
        }
    }
    
    Mat Average = S.t() * S /(R);
    //计算协方差矩阵的方式----(S矩阵的转置 * S矩阵)/行数


    //使用opencv提供的eigen函数求特征值以及特征向量
    eigen(Average, eigenvalues, eigenvectors);
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鸳鸯锅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值