目录
第一幅插图是对此篇文章的总结,建议看完文章以后再行观看。本文主要参考了《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);
程序结果输出: