Opencv學習筆記-----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);
}

 同時貼出結果圖,可以看到6個列(維度)的特徵值以及特徵向量:



順便給大家推薦一個圖像去模糊算法,香港大學的賈佳亞大牛發明的,處於世界領先水平,而且個人主頁上有豐富的源碼。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章