2DPCA—二维主成分分析详解及编程
目录
一、为什么提出2DPCA(Why)
二、2DPCA数学公式(What)
(一)模型
(二)策略(优化目标)
(三)算法(如何计算投影向量)
(四)特征提取和图像重构
三、2DPCA编程(How)
第一幅插图是对此篇文章的总结,建议看完文章以后再行观看。本文主要参考了《Two-Dimensional PCA:A New Approach to Appearance-Based Face Representation and Recognition》
一、为什么提出2DPCA(Why)
PCA存在着以下问题:
1、使用PCA进行图像分类识别时,需要将二维矩阵转换为一维向量,使得图像内在的结构信息丢失。
2、使用PCA学习特征向量时,由一维向量构造的协方差矩阵尺寸过大,计算复杂度高。
3、由于训练样本数量较少,协方差矩阵尺寸过大,因此PCA容易导致过拟合问题。
因此考虑直接使用二维图像构造协方差矩阵,计算投影轴(特征向量),并直接使用二维图像进行投影获得图像的模式特征。
二、2DPCA数学公式(What)
(一)模型
使用表示N个二维图像,图像尺寸为,2DPCA旨在使用二维图像计算维标准正交列向量作为投影轴,实现如下的特征提取:
其中为二维图形投影后得到的新特征,大小为维。
(二)策略(优化目标)
那么如何度量投影轴或者投影后特征?引入投影后特征的总散射,即投影后特征构造的协方差矩阵的迹,进行衡量。其定义如下:
其中表示投影后特征构造的协方差矩阵,表示协方差矩阵的迹。根据协方差的性质,我们的目标是最大化:
由于我们往往计算多个投影轴,因此将上述优化公式广义化为求取个特征向量:
接下来进行的公式推导。
首先计算投影后特征构造的协方差矩阵,表示如下:
根据上式,可以根据以下公式:
定义图像协方差矩阵如下:
显而易见,图像协方差矩阵是直接使用N个二维图像直接构建,尺寸为n*n。
(三)算法(如何计算投影向量)
此时有,因此寻找最大化的维列向量转换为求取图像协方差矩阵的特征向量。
1、载入所有二维图像矩阵,计算平均图像;
2、对所有二维图像进行中心化处理,计算图像协方差矩阵;
3、计算图像协方差矩阵的特征向量和特征值,选择前个最大特征值以及对于特征向量组成投影矩阵。
(四)特征提取和图像重构
假设图像矩阵为,尺寸为;对应前个最大特征值的特征向量组成投影矩阵,尺寸为。将图像矩阵投影到第个特征向量上,可以得到第个主成分,尺寸为
将k个主成分组成特征矩阵(特征图像),尺寸为。
使用特征提取得到的主成分和学习得到的特征向量计算重构子图像,亦或者使用特征矩阵和投影矩阵计算前k个重构子图像相加得到的重构图像。
重构子图像:
重构图像:
三、2DPCA编程(How)
使用VS2015+opencv 3.4.1进行编程,编程语言为C++,主要根据第二节的第三小节的步骤进行。我将ORL人脸数据库中每个人的10幅图像随机分为5幅训练图像和5幅测试图像,因此得到了训练数据集和测试数据集,大小都为200幅图像。使用训练数据集计算特征向量,载入训练数据集中一副图像进行特征提取和重构。
1、程序初始参数设置:
#include<iostream>
#include<opencv2\opencv.hpp>using namespace std;
using namespace cv;//void
//{//定义需要修改的变量int eigenNum = 2; //特征向量数目int trainNum = 200; //训练样本数目int testNum = 200; //测试样本数目int nrows = 112, ncols = 92; //样本大小string trainPath = "F:\\机器学习\\DataSet\\facetrain\\"; //训练样本存储路径string testPath = "F:\\机器学习\\DataSet\\facetest\\"; //测试样本存储路径//定义程序所需变量string samplePath;//当前样本Mat srcSample; //当前样本Mat sampleAve = Mat::zeros(nrows, ncols, CV_32FC1);//样本均值Mat covMatrix = Mat::zeros(ncols, ncols, CV_32FC1);//协方差矩阵Mat eigenVecs(ncols, eigenNum, CV_32FC1); //特征向量Mat eigenVals(eigenNum, 1, CV_32FC1); //特征值vector<Mat> trainSamples; //存储训练样本
2、载入所有二维图像矩阵,图像大小为112*92,计算平均图像;
//加载图像,计算均值(图像ID号从1开始)for (int i = 1; i <= trainNum; i++){samplePath = trainPath + to_string(static_cast<long long>(i)) + ".png";srcSample = imread(samplePath, 0); //载入当前样本if (srcSample.empty()){cout << "图像不存在" << endl;return;}srcSample.convertTo(srcSample, CV_32FC1); //数据类型转换trainSamples.push_back(srcSample.clone()); //存储当前样本sampleAve += srcSample / double(trainNum);//计算样本均值}
3、对所有二维图像进行中心化处理,计算图像协方差矩阵,矩阵大小为n*n;
//计算协方差矩阵for (int i = 0; i < trainNum; i++){srcSample = trainSamples[i] - sampleAve;//中心化处理covMatrix += srcSample.t()*srcSample/double(trainNum);//计算协方差矩阵}
4、计算图像协方差矩阵的特征向量和特征值,特征向量尺寸为n*1;选择前个最大特征值以及对于特征向量组成投影矩阵,投影矩阵尺寸为n*k。
//计算特征向量和特征值Mat calcVecs, calcVals;eigen(covMatrix, calcVals, calcVecs);eigenVecs = (calcVecs.rowRange(0, eigenNum)).t();eigenVals = calcVals.rowRange(0, eigenNum);//保存特征向量CvMat storeMat;storeMat = eigenVecs;cvSave("eigenVecs.txt", &storeMat);
5、特征提取和重构图像,特征大小为m*k
//特征提取图像重构samplePath = testPath + "2.png";srcSample = imread(samplePath,0);imshow("src", srcSample);srcSample.convertTo(srcSample, CV_32FC1);srcSample = srcSample - sampleAve;Mat feature = srcSample*eigenVecs;Mat reconImg = feature*eigenVecs.t() + sampleAve;normalize(reconImg, reconImg, 0, 255,CV_MINMAX, CV_8UC1);imshow("reconstruction", reconImg);samplePath = to_string(eigenNum) + ".png";imwrite(samplePath, reconImg);
程序结果输出:
2DPCA—二维主成分分析详解及编程相关推荐
- C语言 指针+二维数组详解 (应付期末、考研的最强笔记,建议收藏)
哈喽!这里是一只派大鑫,不是派大星.本着基础不牢,地动山摇的学习态度,从基础的C语言语法讲到算法再到更高级的语法及框架的学习.更好地让同样热爱编程(或是应付期末考试 狗头.jpg)的大家能够在学习阶段 ...
- iOS中 扫描二维码/生成二维码详解
最近大家总是问我有没有关于二维码的demo,为了满足大家的需求,特此研究了一番,希望能帮到大家! 指示根视图: ? 1 self.window.rootViewController = [[UINav ...
- python定义二维数组_二维数组的定义、初始化和输出,C语言二维数组详解
本节学习二维数组.二维数组与一维数组相似,但是用法上要比一维数组复杂一点.后面的编程中,二维数组用得很少,因为二维数组的本质就是一维数组,只不过形式上是二维的.能用二维数组解决的问题用一维数组也能解决 ...
- php 二维数组排序详解: array_multisort
定义和用法 array_multisort() 函数返回一个排序数组.您可以输入一个或多个数组.函数先对第一个数组进行排序,接着是其他数组,如果两个或多个值相同,它将对下一个数组进行排序. 注释: ...
- 1.3 Java二维数组详解
为了方便组织各种信息,计算机常将信息以表的形式进行组织,然后再以行和列的形式呈现出来.二维数组的结构决定了其能非常方便地表示计算机中的表,以第一个下标表示元素所在的行,第二个下标表示元素所在的列.下面 ...
- 微信小程序canva生成图片,长按图片识别小程序二维码详解
下面这个图片就是通过图片和文字等内容合成的一张带有微信小程序二维码的图片,在小程序内部长按可以识别出来: 基本思路是先将内容用canvas排好版,然后把该canvas转化成图片:图片利用wx.prev ...
- 二维码详解(QR Code)
作者:王子旭 链接:https://zhuanlan.zhihu.com/p/21463650 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 2016.7.5 更新 ...
- Java二维数组详解:二维数组的声明和初始化,以及获取二维数组的值
为了方便组织各种信息,计算机常将信息以表的形式进行组织,然后再以行和列的形式呈现出来.二维数组的结构决定了其能非常方便地表示计算机中的表,以第一个下标表示元素所在的行,第二个下标表示元素所在的列.下面 ...
- Django生成二维码详解
自强学堂中用Django生成二维码,发现python.django版本不同,达不到教程中的效果,所以把自己的过程总结出来:思路:在网页输入要转化成二维码的网址,提交到表单调用相应方法生成二维码. 环境 ...
最新文章
- pytorch nn.LSTM()参数详解
- [Android实例] 最全的Android开发资源整理--进阶必备
- 防静电塑料包装袋周围的静电场
- jmeter发送json数据,报405、400错误解决方案
- linux硬盘目录下,Linux 新添加的硬盘格式化并挂载到目录下
- ABAP search help (搜索帮助) 五种方法
- oracle 偶数与奇数,在PL / SQL中计算数字中的奇数和偶数
- python爬虫进阶(初始)
- Java程序员情人节_盘点程序员情人节的表白,前端程序员最浪漫,后端不服来战...
- c ++类成员函数_C ++编程中的数据成员和成员函数
- 第二次作业(贪吃蛇)
- (转载)Http Module 介绍
- VS2019如何修改字体大小
- 使用VC做一个简单的UI界面对话框
- (转)300家平台倒闭,BAT纷纷离场,到底什么模式已经全军覆没?
- c语言银行卡管理系统的意义,使用会员管理系统的意义
- 静默安装Oracle19c软件与数据库
- 相对于就业来讲,前端工程师和后端开发哪个比较好?
- laravel5.5利用网易邮箱发送邮件
- Latex自动化学报模板学习和问题解决总结