OpenCV学习(35) OpenCV中的PCA算法

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);            }// 确保数据能被reshapeif(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

时间: 2024-09-20 16:36:48

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

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

kmeans算法的原理参考:http://www.cnblogs.com/mikewolf2002/p/3368118.html 下面学习一下opencv中kmeans函数的使用.      首先我们通过OpenCV中的随机数产生器RNG,生成一些均匀分布的随机点,这些点的位置对应一副图像中的像素位置,然后使用kmeans算法对这些随机点进行分类,并计算出分类簇的中心点.      随机产生的簇的数量是2到5之间的值,采样点的数量范围是1-1000,一维矩阵centers存放kmeans算法结束

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

本章我们学习LBP图像的原理和使用,因为接下来教程我们要使用LBP图像的直方图来进行脸部识别. 参考资料: http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html http://www.cnblogs.com/mikewolf2002/p/3438166.html       LBP的基本思想是以图像中某个像素为中心,对相邻像素进行阈值比较.如果中心像素的亮度大于等于它的相邻像素,把相邻像素标记为1,否则标

OpenCV学习(3) OpenCV框架

      OpenCV是一个开源的视觉库,其中包括很多计算机视觉的算法实现.在版本2.2以后,OpenCV采用C++特征的API,在1.x版本中,OpenCV函数都是传统的C语言形式.       OpenCV采用模块化的结构,每个模块都是由一些动态和静态库组成,该模块会实现一些特定的计算机视觉算法.要使用某个特定的库,我们必须在程序中先包含该库的头文件,并把该库的lib作为链接库. 例如要使用core和highgui库,则必须在程序源文件中包含: #include <opencv2/core

OpenCV学习(2) OpenCV的配置

      下面我们在VS2010中编写一个简单的OpenCV程序,来看看如何在程序中使用OpenCV. 创建一个新的Win32 控制台程序,附加选项为空工程(empty project),并添加一个cpp源文件main.cpp,内容如下: #include <opencv2/core/core.hpp> #include <opencv2/highgui//highgui.hpp> int main() { cv::Mat img = cv::imread("lenna

OpenCV学习(1) OpenCV的安装

1. 下载文件 下载最新的OpenCV windows版本: 链接:http://sourceforge.net/projects/opencvlibrary/files/opencv-win/       我下载的版本是2.46,下载后得到OpenCV-2.4.6.0.exe,自解压该文件到目录D:\opencv2.31\opencv2.46.自解压之后,会生成一个opencv的子目录,所有的opencv文件都在这个目录中. 2.编译文件 我使用CMake2.8来编译OpenCV:      

OpenCV学习(9) 分水岭算法(3)

本教程我学习一下opencv中分水岭算法的具体实现方式. 原始图像和Mark图像,它们的大小都是32*32,分水岭算法的结果是得到两个连通域的轮廓图. 原始图像:(原始图像必须是3通道图像) Mark图像: 结果图像:       初始的mark图像数据如下,黄色的部分为我们的第一个mark区域,值为255,第二个区域为褐红色的区域,值为128,第三个绿色的区域,值为64.   opencv分水岭算法描述如下: 初始化mark矩阵,生成最初的注水区域. 1.设置mark图像的边框值为-1 2.

opencv中的sift算法是不是只能检测一个匹配目标啊?

问题描述 opencv中的sift算法是不是只能检测一个匹配目标啊? 初学sift算法,现在做一个小程序,用opencv里的sift算法匹配目标,现在假设场景中存在多个匹配的目标,但是每次检测好像都只检测到第一个.怎样让它把多个目标都识别出来啊?小白求指导!先谢谢各位大神 解决方案 sift算法是基于图像特征进行匹配的,你可以尝试基于图像区域的一些算法,看你的匹配目标在哪里,将其设定为匹配区域就可以了

OpenCV学习(38) 人脸识别(3)

            前面我们学习了基于特征脸的人脸识别,现在我们学习一下基于Fisher脸的人脸识别,Fisher人脸识别基于LDA(线性判别算法)算法,算法的详细介绍可以参考下面两篇教程内容: http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html LDA算法细节参考: http://www.cnblogs.com/mikewolf2002/p/3435750.html   程序代码: #includ

(转) OpenCV学习笔记大集锦 与 图像视觉博客资源2之MIT斯坦福CMU

      首页 视界智尚 算法技术 每日技术 来打我呀 注册     OpenCV学习笔记大集锦 整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址:http://blog.csdn.net/column/details/opencv-manual.html 2:部分OpenCV的函数解读和原理解读 作者:梦想腾飞数量:20篇博文网址:http:/