图像处理之PCA(C++)

图像处理之PCA(C++)


文章目录


前言

在科研、工程应用中,我们往往所获取的数据都包含着很多冗余的信息,这些冗余的信息会对我们分析数据造成干扰。因此,我们可以采用PCA(主成分分析法)去除冗余信息,抓住主要特征,减少数据量。


一、PCA原理

1.原理思想

PCA(Principal Component Analysis),即主成分分析方法,是一种使用最广泛的数据降维算法。PCA的主要思想是将n维特征映射到k维上,这k维是全新的正交特征也被称为主成分,是在原有n维特征的基础上重新构造出来的k维特征。

PCA的工作就是从原始的空间中顺序地找一组相互正交的坐标轴,新的坐标轴的选择与数据本身是密切相关的。其中,第一个新坐标轴选择是原始数据中方差最大的方向,第二个新坐标轴选取是与第一个坐标轴正交的平面中使得方差最大的,第三个轴是与第1,2个轴正交的平面中方差最大的。
主要的应用是:数据压缩(降维)、可视化高维特征、缓解维度灾难、特征独立、降噪、计算物体的方向

2.实现步骤

假设m条n维数据。(使用PCA主成分分析得到的结果就是得到降维后的m条k维数据)

  1. 将原始数据按列组成n行m列矩阵X0(n*m)
  2. 将矩阵X0的每一行进行零均值化,得到矩阵X(n*m),即减去这一行的均值
  3. 求出协方差矩阵C(n*n)(m为矩阵X0的列数)
  4. 求出协方差矩阵的特征值及其对应的特征向量。得到n个特征值,对应n个特征向量,其中每个特征向量的长度又为n,也即所有特征向量组成n行n列的矩阵。
  5. 将特征向量按照特征值从大到小的顺序从上到下排列成矩阵,取前k行组成矩阵P(k*n)
  6. 根据Y=PX即可获得降维到k维后的数据矩阵Y(k*m)

二、代码实现

cpp 复制代码
#include <iostream>
#include <opencv.hpp>
using namespace std;
using namespace cv;


/*
* @param cv::Mat src 输入图像
* @param cv::Mat pca 输出图像
* @param int	k	 降维后的维度
* @brief pca主成分分析法降维
*/
void do_pca(cv::Mat src,cv::Mat& pca,int k)
{
	if (src.rows <= 1 || src.cols <= 1)
	{
		return;
	}

	k = k > src.rows ? src.rows : k;		//取src.rows和k的较小值

	int h = src.rows;
	int w = src.cols;

	// 1.求每一行的平均值
	std::vector<float> meanVec(src.rows,0);
	for (int i = 0; i < h; i++)
	{
		for (int j = 0; j < w; j++)
		{
			meanVec[i] += src.at<uchar>(i, j);
		}
		meanVec[i] /= w;
	}

	// 2.去平均处理
	src.convertTo(src, CV_32F);
	for (int i = 0; i < h; i++)
	{
		for (int j = 0; j < w; j++)
		{
			src.at<float>(i, j) -= meanVec[i];
		}
	}

	// 3.计算协方差矩阵
	cv::Mat covMat;
	covMat = src * src.t()/w;


	// 4\5.求出协方差矩阵的特征值和对应的特征向量
	cv::Mat eigenValues;	//特征值
	cv::Mat eigenVectors;	//特征值对应的特征向量
	cv::eigen(covMat, eigenValues, eigenVectors);	//cv::eigen()输入必须是CV_32F或者CV_64F类型的对称矩阵,
													//且该函数输出的eigenValues和eigenVectors已经按照从大到小的顺序排列

	// 5.取前k行的矩阵P
	cv::Mat kMat;
	eigenVectors(cv::Rect(0, 0, eigenVectors.cols, k)).copyTo(kMat);


	// 6.获得降维后的矩阵Y
	cv::Mat yMat;
	yMat = kMat * src;
	pca = yMat.clone();		//数据类型CV_32FC1
}

int main()
{
	string path = "F://work_study//algorithm_demo//";
	cv::Mat src = cv::imread(path + "baby.jpg", cv::IMREAD_GRAYSCALE);
	if (src.empty())
		return -1;

	//自己实现的pca
	cv::Mat pca_dst;
	int k = 100;	//降维后维度
	do_pca(src, pca_dst, k);

	//opencv实现的pca
	cv::PCA pca(src, Mat(), PCA::DATA_AS_COL, k);
	cv::Mat dst = pca.project(src);

	imshow("pca", pca_dst);
	imshow("opencv_pca", dst);
	cv::waitKey(0);
	return 0;
}

自己实现的pca

opencv实现的pca


总结

本文使用C++借助opencv实现了pca算法,介绍了pca原理、计算过程以及源代码的实现,主要核心是利用opencv中的cv::eigen()对协方差矩阵进行特征值和特征向量的计算,欢迎大家提出问题。

本文代码均已经在本地运行成功,欢迎阅读交流。

相关推荐
zh_xuan2 小时前
c++ 单例模式
开发语言·c++·单例模式
Blossom.1183 小时前
使用Python和Scikit-Learn实现机器学习模型调优
开发语言·人工智能·python·深度学习·目标检测·机器学习·scikit-learn
DFminer4 小时前
【LLM】fast-api 流式生成测试
人工智能·机器人
郄堃Deep Traffic4 小时前
机器学习+城市规划第十四期:利用半参数地理加权回归来实现区域带宽不同的规划任务
人工智能·机器学习·回归·城市规划
利刃大大5 小时前
【在线五子棋对战】二、websocket && 服务器搭建
服务器·c++·websocket·网络协议·项目
喜欢吃燃面5 小时前
C++刷题:日期模拟(1)
c++·学习·算法
SHERlocked935 小时前
CPP 从 0 到 1 完成一个支持 future/promise 的 Windows 异步串口通信库
c++·算法·promise
GIS小天5 小时前
AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月7日第101弹
人工智能·算法·机器学习·彩票
阿部多瑞 ABU5 小时前
主流大语言模型安全性测试(三):阿拉伯语越狱提示词下的表现与分析
人工智能·安全·ai·语言模型·安全性测试
cnbestec5 小时前
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
人工智能·线性代数·触觉传感器