opencv学习-算法-pca

申明,本文转载自http://blog.csdn.net/yang_xian521/article/details/7445536

PCA(principal component analysis,主成分分析),我想是大家用的最多的降维手段,对于PCA的理解,我想大神们都各有各的绝招,可以应用的场合也非常多。下面就介绍一下OpenCV中PCA这个类,因为常用,所以这个类相对OpenCV而言显得比较独立,放在了core这部分中。

PCA类的成员函数包括构造函数、运算符重载()、project、backProject这几个函数,还包括成员变量eigenvectors、eigenvalues、mean。使用也很方便。比如我要计算一组向量的PCA,我们只需要定义个PCA实例,获得主成分,调用project测试新样本,也可以再调用backProject重建原始向量,是project的一个逆运算。

在实际使用我我发现了一个bug,构造函数和运算符重载()函数的第三个参数只能使用0或者1(分别对应CV_PCA_DATA_AS_ROW和CV_PCA_DATA_AS_COL),但调用对应的宏却编译无法通过,不知道大家是否也是一样的情况

下面结合一个实例分析:

2001年全国各地区消费情况指数

地区 食品X1 衣着X2 家庭设备X3 医疗保健X4 交通通信X5 娱乐教育X6 居住X7

北京 101.5 100.4 97.0 98.7 100.8 114.2 104.2
天津 100.8 93.5 95.9 100.7 106.7 104.3 106.4
河北 100.8 97.4 98.2 98.2 99.5 103.6 102.4
山西 99.4 96.0 98.2 97.8 99.1 98.3 104.3
内蒙古 101.8 97.7 99.0 98.1 98.4 102.0 103.7
辽宁 101.8 96.8 96.4 92.7 99.6 101.3 103.4
吉林 101.3 98.2 99.4 103.7 98.7 101.4 105.3
黑龙江 101.9 100.0 98.4 96.9 102.7 100.3 102.3
上海 100.3 98.9 97.2 97.4 98.1 102.1 102.3
江苏 99.3 97.7 97.6 101.1 96.8 110.1 100.4
浙江 98.7 98.4 97.0 99.6 95.6 107.2 99.8
安徽 99.7 97.7 98.0 99.3 97.3 104.1 102.7
福建 97.6 96.5 97.6 102.5 97.2 100.6 99.9
江西 98.0 98.4 97.1 100.5 101.4 103.0 99.9
山东 101.1 98.6 98.7 102.4 96.9 108.2 101.7
河南 100.4 98.6 98.0 100.7 99.4 102.4 103.3
湖北 99.3 96.9 94.0 98.1 99.7 109.7 99.2
湖南 98.6 97.4 96.4 99.8 97.4 102.1 100.0
广东 98.2 98.2 99.4 99.3 99.7 101.5 99.9
广西 98.5 96.3 97.0 97.7 98.7 112.6 100.4
海南 98.4 99.2 98.1 100.2 98.0 98.2 97.8
重庆 99.2 97.4 95.7 98.9 102.4 114.8 102.6
四川 101.3 97.9 99.2 98.8 105.4 111.9 99.9
贵州 98.5 97.8 94.6 102.4 107.0 115.0 99.5
云南 98.3 96.3 98.5 106.2 92.5 98.6 101.6
西藏 99.3 101.1 99.4 100.1 103.6 98.7 101.3
陕西 99.2 97.3 96.2 99.7 98.2 112.6 100.5
甘肃 100.0 99.9 98.2 98.3 103.6 123.2 102.8
青海 102.2 99.4 96.2 98.6 102.4 115.3 101.2
宁夏 100.1 98.7 97.4 99.8 100.6 112.4 102.5
新疆 104.3 98.7 100.2 116.1 105.2 101.6 102.6 

我们用PCA来分析这些向量的对消费水平的贡献,代码实现如下:

[cpp]  view plain copy
  1. #include <opencv2/core/core.hpp>  
  2. #include <iostream>  
  3. #include <fstream>  
  4.   
  5. using namespace cv;  
  6. using namespace std;  
  7.   
  8. void main(int argc, char** argv)  
  9. {  
  10.     const int SAMPLE_NUM = 31;  
  11.     const int VECTOR_NUM = 7;  
  12.     fstream fp;  
  13.     string temp;  
  14.     char* filename = argv[1];  
  15.     Mat pcaSet(SAMPLE_NUM, VECTOR_NUM, CV_32F);  
  16.     // 读取数据,生成pcaSet  
  17.     fp.open(filename, ios::in);  
  18.     for (int i=0; i<SAMPLE_NUM; i++)  
  19.     {  
  20.         getline(fp, temp, ' ');  
  21.         for (int j=0; j<VECTOR_NUM; j++)  
  22.         {  
  23.             fp >> pcaSet.at<float>(i, j);  
  24.         }  
  25.     }  
  26.     fp.close();  
  27.   
  28. //  cout << pcaSet << endl;  
  29.     PCA pca(pcaSet, Mat(), 0/*CV_PCA_DATA_AS_ROW*/);  
  30.     cout << pca.eigenvalues << endl;  
  31.     cout << endl;  
  32.     cout << pca.eigenvectors << endl;  
  33. }  

我这里只把前3维的结果显示如下:

eigenvalues:[43.18,14.60,9.21]、

eigenvectors:[0.013,0.034,-.0.100, -0.130, 0.207,0.963,-0.020;

    0.157,0.038,0.121,0.893,0.395,0.046,0.060;

    0.214,0.018,-0.001,-0.404,0.813,-0.228,0.277]

以下代码转载自http://www.cnblogs.com/zcftech/archive/2013/04/13/3017411.html

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>


#include <fstream>
#include <sstream>


using namespace cv;
using namespace std;




//将给出的图像回归为值域在0~255之间的正常图像
Mat norm_0_255(const Mat& src) {
    // 构建返回图像矩阵
    Mat dst;
    switch(src.channels()) {
    case 1://根据图像通道情况选择不同的回归函数
        cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
        break;
    case 3:
        cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
        break;
    default:
        src.copyTo(dst);
        break;
    }
    return dst;
}


// 将一副图像的数据转换为Row Matrix中的一行;这样做是为了跟opencv给出的PCA类的接口对应
//参数中最重要的就是第一个参数,表示的是训练图像样本集合
Mat asRowMatrix(const vector<Mat>& src, int rtype, double alpha = 1, double beta = 0) {
    // 样本个数
    size_t n = src.size();
    // 如果样本为空,返回空矩阵
    if(n == 0)
        return Mat();
    // 样本的维度
    size_t d = src[0].total();
    // 构建返回矩阵
    Mat data(n, d, rtype);
    // 将图像数据复制到结果矩阵中
    for(int i = 0; i < n; i++) {
        //如果数据为空,抛出异常
        if(src[i].empty()) {
            string error_message = format("Image number %d was empty, please check your input data.", i);
            CV_Error(CV_StsBadArg, error_message);
        }
        // 图像数据的维度要是d,保证可以复制到返回矩阵中
        if(src[i].total() != d) {
            string error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, d, src[i].total());
            CV_Error(CV_StsBadArg, error_message);
        }
        // 获得返回矩阵中的当前行矩阵:
        Mat xi = data.row(i);
        // 将一副图像映射到返回矩阵的一行中:
        if(src[i].isContinuous()) {
            src[i].reshape(1, 1).convertTo(xi, rtype, alpha, beta);
        } else {
            src[i].clone().reshape(1, 1).convertTo(xi, rtype, alpha, beta);
        }
    }
    return data;
}


int main(int argc, const char *argv[]) {
    // 训练图像集合
    vector<Mat> db;


    // 本例中使用的是ORL人脸库,可以自行在网上下载
    //将数据读入到集合中


    db.push_back(imread("s1/1.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s1/2.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s1/3.pgm", IMREAD_GRAYSCALE));


    db.push_back(imread("s2/1.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s2/2.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s2/3.pgm", IMREAD_GRAYSCALE));


    db.push_back(imread("s3/1.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s3/2.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s3/3.pgm", IMREAD_GRAYSCALE));


    db.push_back(imread("s4/1.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s4/2.pgm", IMREAD_GRAYSCALE));
    db.push_back(imread("s4/3.pgm", IMREAD_GRAYSCALE));


    // 将训练数据读入到数据集合中,实现PCA类的接口
    Mat data = asRowMatrix(db, CV_32FC1);


    // PCA中设定的主成分的维度,这里我们设置为10维度
    int num_components = 10;


    // 构建一份PCA类
    PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, num_components);


    // 复制PCA方法获得的结果
    Mat mean = pca.mean.clone();
    Mat eigenvalues = pca.eigenvalues.clone();
    Mat eigenvectors = pca.eigenvectors.clone();


    // 平均脸:
    imshow("avg", norm_0_255(mean.reshape(1, db[0].rows)));


    // 前三个训练人物的特征脸
    imshow("pc1", norm_0_255(pca.eigenvectors.row(0)).reshape(1, db[0].rows));
    imshow("pc2", norm_0_255(pca.eigenvectors.row(1)).reshape(1, db[0].rows));
    imshow("pc3", norm_0_255(pca.eigenvectors.row(2)).reshape(1, db[0].rows));


    // Show the images:
    waitKey(0);


    // Success!
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值