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

简介: PCA算法的基本原理可以参考:http://www.cnblogs.com/mikewolf2002/p/3429711.html     对一副宽p、高q的二维灰度图,要完整表示该图像,需要m = p*q维的向量空间,比如100*100的灰度图像,它的向量空间为100*100=10000。

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

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

imageimage

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

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

算法的基本原理:

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

1.计算均值向量 image

image

2.计算协方差矩阵 S

image

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

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

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

image其中image

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

下面我们在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副图像为:

image_thumbimage_thumb2image_thumb3image_thumb4image_thumb5image_thumb6image_thumb7image_thumb8image_thumb9image_thumb1

得到的5副特征脸为:

imageimageimage

imageimage

均值脸为:

image

 

程序代码:参照工程FirstOpenCV32

相关文章
|
1天前
|
机器学习/深度学习 算法
应用规则学习算法识别有毒的蘑菇
应用规则学习算法识别有毒的蘑菇
|
12天前
|
机器学习/深度学习 算法 数据挖掘
【Python机器学习专栏】关联规则学习:Apriori算法详解
【4月更文挑战第30天】Apriori算法是一种用于关联规则学习的经典算法,尤其适用于购物篮分析,以发现商品间的购买关联。该算法基于支持度和置信度指标,通过迭代生成频繁项集并提取满足阈值的规则。Python中可借助mlxtend库实现Apriori,例如处理购物篮数据,设置支持度和置信度阈值,找出相关规则。
|
12天前
|
机器学习/深度学习 算法 前端开发
【Python机器学习专栏】集成学习算法的原理与应用
【4月更文挑战第30天】集成学习通过组合多个基学习器提升预测准确性,广泛应用于分类、回归等问题。主要步骤包括生成基学习器、训练和结合预测结果。算法类型有Bagging(如随机森林)、Boosting(如AdaBoost)和Stacking。Python中可使用scikit-learn实现,如示例代码展示的随机森林分类。集成学习能降低模型方差,缓解过拟合,提高预测性能。
|
25天前
|
机器学习/深度学习 算法 前端开发
Scikit-learn进阶:探索集成学习算法
【4月更文挑战第17天】本文介绍了Scikit-learn中的集成学习算法,包括Bagging(如RandomForest)、Boosting(AdaBoost、GradientBoosting)和Stacking。通过结合多个学习器,集成学习能提高模型性能,减少偏差和方差。文中展示了如何使用Scikit-learn实现这些算法,并提供示例代码,帮助读者理解和应用集成学习提升模型预测准确性。
|
25天前
|
机器学习/深度学习 算法 Python
使用Python实现集成学习算法:Bagging与Boosting
使用Python实现集成学习算法:Bagging与Boosting
22 0
|
26天前
|
算法 安全 数据可视化
python关联规则学习:FP-Growth算法对药品进行“菜篮子”分析
python关联规则学习:FP-Growth算法对药品进行“菜篮子”分析
|
1月前
|
算法
【算法学习--字符串】(不含KMP算法)
【算法学习--字符串】(不含KMP算法)
|
2天前
|
算法 数据安全/隐私保护 计算机视觉
基于二维CS-SCHT变换和LABS方法的水印嵌入和提取算法matlab仿真
该内容包括一个算法的运行展示和详细步骤,使用了MATLAB2022a。算法涉及水印嵌入和提取,利用LAB色彩空间可能用于隐藏水印。水印通过二维CS-SCHT变换、低频系数处理和特定解码策略来提取。代码段展示了水印置乱、图像处理(如噪声、旋转、剪切等攻击)以及水印的逆置乱和提取过程。最后,计算并保存了比特率,用于评估水印的稳健性。
|
3天前
|
存储 算法 数据可视化
基于harris角点和RANSAC算法的图像拼接matlab仿真
本文介绍了使用MATLAB2022a进行图像拼接的流程,涉及Harris角点检测和RANSAC算法。Harris角点检测寻找图像中局部曲率变化显著的点,RANSAC则用于排除噪声和异常点,找到最佳匹配。核心程序包括自定义的Harris角点计算函数,RANSAC参数设置,以及匹配点的可视化和仿射变换矩阵计算,最终生成全景图像。
|
3天前
|
算法 Serverless
m基于遗传优化的LDPC码NMS译码算法最优归一化参数计算和误码率matlab仿真
MATLAB 2022a仿真实现了遗传优化的归一化最小和(NMS)译码算法,应用于低密度奇偶校验(LDPC)码。结果显示了遗传优化的迭代过程和误码率对比。遗传算法通过选择、交叉和变异操作寻找最佳归一化因子,以提升NMS译码性能。核心程序包括迭代优化、目标函数计算及性能绘图。最终,展示了SNR与误码率的关系,并保存了关键数据。
12 1