PCA算法的基本原理可以参考:http://www.cnblogs.com/mikewolf2002/p/3429711.html

    对一副宽p、高q的二维灰度图,要完整表示该图像,需要m = p*q维的向量空间,比如100*100的灰度图像,它的向量空间为100*100=10000。下图是一个3*3的灰度图和表示它的向量表示:

该向量为行向量,共9维,用变量表示就是[v0, v1, v2, v3, v4, v5, v6, v7, v8],其中v0...v8,的范围都是0-255。

      现在的问题是假如我们用1*10000向量,表示100*100的灰度图,是否向量中的10000维对我们同样重要?肯定不是这样的,有些维的值可能对图像更有用,有些维相对来说作用小些。为了节省存储空间,我们需要对10000维的数据进行降维操作,这时就用到了PCA算法,该算法主要就是用来处理降维的,降维后会尽量保留更有意义的维数,它的思想就是对于高维的数据集来说,一部分维数表示大部分有意义的数据。

算法的基本原理:

假设   表示一个特征向量,其中 【注:xi可能也是一个列向量】

1.计算均值向量

2.计算协方差矩阵 S

3.计算S的特征值   和对应的特征向量,根据线性代数知识我们知道有公式:

4. 对特征值按照大小进行递减排序,特征向量的顺序和特征值是一致的。假设我们只需要保留K个维数(K<n),则我们会选取特征值最大的前K个特征向量,用这K个特征向量,来表示图像,这K个向量就是图像K个主成分分量。

对于被观测的向量,它的K个主成分量可以通过下面公式计算得到:

,其中

因为W是正交矩阵,所有有

下面我们在OpenCV中看一个计算PCA的例子:

1.首先读入10副人脸图像,这些图像大小相等,是一个人的各种表情图片。

2.把图片转为1*pq的一维形式,p是图像宽,q是图像高。这时我们的S矩阵就是10行,每行是pq维的向量。

3.然后我们在S上执行PCA算法,设置K=5,求得5个特征向量,这5个特征向量就是我们求得的特征脸,用这5个特征脸图像,可以近似表示之前的十副图像。

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp" #include <iostream>
#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;
} //转化给定的图像为行矩阵
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);
}
// 确保数据能被reshape
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);
//转化为1行,n列的格式
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; string prefix = "../att_faces/"; db.push_back(imread(prefix + "s1/1.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/2.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/3.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/4.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/5.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/6.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/7.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/8.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/9.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/10.pgm", IMREAD_GRAYSCALE)); // Build a matrix with the observations in row:
Mat data = asRowMatrix(db, CV_32FC1); // PCA算法保持5主成分分量
int num_components = 5; //执行pca算法
PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, num_components); //copy 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));
imshow("pc4", norm_0_255(pca.eigenvectors.row(3)).reshape(1, db[0].rows));
imshow("pc5", norm_0_255(pca.eigenvectors.row(4)).reshape(1, db[0].rows)); while(1)
waitKey(0); // Success!
return 0;
}

我们输入的10副图像为:

得到的5副特征脸为:

均值脸为:

 

程序代码:参照工程FirstOpenCV32

OpenCV学习(35) OpenCV中的PCA算法的更多相关文章

  1. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  2. sklearn中调用PCA算法

    sklearn中调用PCA算法 PCA算法是一种数据降维的方法,它可以对于数据进行维度降低,实现提高数据计算和训练的效率,而不丢失数据的重要信息,其sklearn中调用PCA算法的具体操作和代码如下所 ...

  3. OpenCV学习(22) opencv中使用kmeans算法

    kmeans算法的原理参考:http://www.cnblogs.com/mikewolf2002/p/3368118.html 下面学习一下opencv中kmeans函数的使用.      首先我们 ...

  4. OpenCV学习笔记——OpenCV安装

    关于OpenCV安装 1.下载和安装OpenCV SDK 在官网:http://opencv.org/上找到OpenCV windows版下载 . 后得到一个 opencv-2.X.X.exe的文件, ...

  5. OpenCV学习(39) OpenCV中的LBP图像

    本章我们学习LBP图像的原理和使用,因为接下来教程我们要使用LBP图像的直方图来进行脸部识别. 参考资料: http://docs.opencv.org/modules/contrib/doc/fac ...

  6. OpenCV学习(3) OpenCV框架

          OpenCV是一个开源的视觉库,其中包括很多计算机视觉的算法实现.在版本2.2以后,OpenCV采用C++特征的API,在1.x版本中,OpenCV函数都是传统的C语言形式.       ...

  7. OpenCV学习(1) OpenCV的安装

    前沿 准备了好几天,终于开始了,不管怎样,接下来的这个月一定把这本书很好的啃下来.当然OpenCV可以在很多的IDE下安装与配置,我这里就只在VS2010和VC6.0下安装配置了,当然这篇博文主要讲在 ...

  8. OpenCV学习:OpenCV源码编译(vc9)

    安装后的OpenCV程序下的build文件夹中,只找到了vc10.vc11和vc12三种编译版本的dll和lib文件,需要VS2010及以上的IDE版本,而没有我们常用的VS2008版本. 于是,需要 ...

  9. OpenCV学习:OpenCV文件一览

    了解一些OpenCV代码整体的模块结构后,再重点学习自己感兴趣的部分,会有一种一览众山小的感觉~ Come on! C:\OpenCV\opencv\build\include文件夹下包含两个文件夹: ...

随机推荐

  1. thinkphp中常用的模板变量

    在thinkphp中的模板要加载静态文件如css,js等文件时要经常用到模板常量. 假如项目放在/web/shop中,则如下所示对应常量的输出值: 1 2 3 4 5 6 7 8 9 // 不含域名 ...

  2. hdu-1540线段树刷题

    title: hdu-1540线段树刷题 date: 2018-10-18 19:55:21 tags: acm 刷题 categories: ACM-线段树 概述 哇,,,这道线段树的题可以说是到目 ...

  3. spring4声明式事务—02 xml配置方式

    1.配置普通的 controller,service ,dao 的bean. <!-- 配置 dao ,service --> <bean id="bookShopDao& ...

  4. 02-c#基础之01-基础语法(二)

    1.变量的存储以及变量的几种类型 变量:用来在计算机当中存储数据. 存储变量的语法: 变量类型 变量名: 变量名=值: int number=100: 2.赋值"=" " ...

  5. sublime插件FileHeader使用,自动的添加模板

    sublime插件FileHeader能够自动的监测创建新文件动作,自动的添加模板 下载地址:https://github.com/shiyanhui/FileHeader FileHeader能够自 ...

  6. with在模板中的应用

    var str = 'Hello <%= name %>!'; var o = { name: 'Alice' }; function tmpl(str, obj) { str = 'va ...

  7. Go语言特点

    作者:asta谢链接:https://www.zhihu.com/question/21409296/answer/18184584来源:知乎 1.Go有什么优势 可直接编译成机器码,不依赖其他库,g ...

  8. 【10.9校内练习赛】【搜索】【2-sat】【树链剖分】【A_star k短路】【差分约束+判负环】

    在洛谷上复制的题目! P3154 [CQOI2009]循环赛 题目描述 n队伍比赛,每两支队伍比赛一次,平1胜3负0. 给出队伍的最终得分,求多少种可能的分数表. 输入输出格式 输入格式: 第一行包含 ...

  9. ListView实现下拉刷新功能

    很久没有写博客了,感觉都懒惰了,今天说一下一个自定义的空间,就是ListView下拉列表可以刷新的功能,相信很多同学都看到过这种功能,最典型的就是新浪微博的下拉刷新列表了. 废话不多说,首先呢,下拉刷 ...

  10. php <a href></a>链接地址中是php变量,链接文本也是php变量的代码处理方法

    1.所用php变量名为$recent_tests,是一个二维数组,示例如下: $recent_tests[0]["test_url"] = www.baidu.com $recen ...