C++编程:PCA降维算法实现简单人脸识别

C++编程:PCA降维算法实现简单人脸识别


.

前言

优快云从以前开始就一直使用(学习),但是当博主还是第一次~
也没有保存项目的习惯,但这次突然心血来潮想着把以后做的东西都保存下来以供未来的我复习使用,如果在下面的叙述中有发现错误的地方,请帮助我指出,谢谢!

正题

这次刚好补了PCA降维用于人脸识别的代码,原理很简单,代码也很简单;
虽然网上确实都有很多类似的例子,但我认为自己写一下还是很有必要的!
废话不多说,下面直接上代码(码文真的好辛苦啊(x),暂时先贴代码好惹
原理的话,我个人认为下面这位博主所叙述的方式很好理解(绝对不是因为懒)看一遍就能懂!
链接:主成分分析(PCA)
使用的图集是ORL_92x112;网上很容易找,就不贴上啦(懒)
如果转载博文涉及侵权请联系我删除

代码


#include "pch.h"
#include "opencv2/highgui/highgui.hpp" 
#include <opencv.hpp>
#include <iostream>


using namespace std;
using namespace cv;

//To Do:calculate the mean value of each rows
void Cal_horizon_mean(Mat_<double> A, Mat_<double> B)
{
}
//矩阵转置.t()
void decrease(Mat_<double> A, Mat_<double> B)
{
	//可以用.t()直接代替啦,之前忘记了转置的方法才自己写了一个函数...
}
//To Do:计算矩阵模
double cal(Mat_<double> A) {
}
//To Do:矩阵拼接
cv::Mat LeftRightMerge(cv::Mat A, cv::Mat B)
{
}

int main()
{
	Mat_<double> img,aim,img2;
	Mat_<double> face, face_aim;
	Mat_<double> face_all;
	Mat_<double> face_mean,face_mean_single;
	Mat_<double> face_zeromean;
	Mat_<double> Mat_cov;
	Mat_<double> eValuesMat;
	Mat_<double> eVectorsMat;
	Mat_<double> basic_mat;
	Mat_<double> Mat_transto;
	int simple_class_num = 40;
	int simple_single_num = 5;
	double value1 = 0, value2 = 0;
	int k = 0;
	double percent = 0.8;
	double d = 1, temp = 0;
	int aim_class = 0, aim_order = 0;
	int class_c = 2, order = 3;
	cout << "请输入要判别的图片类别:S" ;
	cin >> class_c;
	cout << "请输入要判别的图片序列:_" ;
	cin >> order;
	ostringstream ott;
	ostringstream oss;
	char readPath[50]= "你的子路径";
	char readPath2[] = "_";
	char readPath4[] = ".bmp";
	for (int i = 1; i <= simple_class_num; i++) {
		for (int j = 1; j <= simple_single_num; j++) {
			oss << readPath << i << readPath2 << j << readPath4;
			img = imread(oss.str(), IMREAD_GRAYSCALE);
			oss.str("");
			if (i == 1&& j ==1) {
				face = img.reshape(0, 1).t();
				face_all = face;
			}
			else {
				face = img.reshape(0, 1).t();
				face_all = LeftRightMerge(face_all, face);
			}
		}
	}
	/**
	To Do:Initial each Mats;
	*/
	face.copyTo(face_mean_single);
	face_all.copyTo(face_mean);
	face_all.copyTo(face_zeromean); 
	face_all.copyTo(Mat_cov);
	
	/**To Do: 零均值化所有行
	Target: Let the  variance become (1/m)*a^2 ,m is the number of each rows; 
	        In this way, we can find the direction vector to transform the original data;
			And finally we can get the variance(Max);
	方差可以直接用每个元素的平方和除以元素个数表示
	*/
	Cal_horizon_mean(face_all, face_mean);
	face_zeromean = face_all - face_mean; 
	/**
	To Do:将一组N维向量降为K维(K大于0,小于N),其目标是选择K个单位(模为1)正交基
	      使得原始数据变换到这组基上后,各字段两两间协方差为0,而字段的方差则尽可能大
		  (在正交的约束下,取最大的K个方差)
	*/
	//计算协方差矩阵有函数可以用calcCovarMatrix(...)
	//calcCovarMatrix(face_zeromean, eValuesMat, Mat_cov, CV_COVAR_NORMAL | CV_COVAR_ROWS);
	//用直接计算的方法比较直观,如下式所示:
	//Mat_cov = ;
	eigen((face_zeromean*face_zeromean.t()) / (simple_single_num*simple_class_num - 1)
		, eValuesMat, eVectorsMat); // eVectorsMat为特征向量; 并且无须再调整顺序,Opencv中的eigen已排序;

	/**
	To Do:Tansform the original Mat to lower dimension
	      Then We can calculate the value of the Mat tansformed minus the Mat original;
	*/

	/*降维开始*/
	for (int i = 0; i < eValuesMat.rows; i++) {
		value1 += eValuesMat[i][0];
	}
	for (int i = 0; i < eValuesMat.rows; i++) {
		value2 += eValuesMat[i][0];
		if ((value2 / value1)>= percent) {
			k = i;
			break;
		}
	}
	for (int i = 0; i < eValuesMat.rows; i++) {
		if (i > k) {
			for (int j = 0; j < eValuesMat.cols; j++) {
				eValuesMat[i][j] = 0;
			}
		}
	}
	/*降维结束*/
	
	ott << readPath << class_c << readPath2 << order << readPath4;
	aim = imread(ott.str(), IMREAD_GRAYSCALE);
	face_aim = aim.reshape(0, 1).t();
	face_all.copyTo(basic_mat);
	face_aim.copyTo(Mat_transto);
	basic_mat = eVectorsMat;
	decrease(face_mean, face_mean_single);//10304*5的face_mean->10304*1的face_mean_single
	Mat_transto = eVectorsMat * (face_aim - face_mean_single)  ;
	//d = determinant(Mat_transto - face_aim);
	cout << "行数: " << face_mean_single.rows << endl;
	cout << "列数: " << face_mean_single.cols << endl;
	cout << "行数: " << face_aim.rows << endl;
	cout << "列数: " << face_aim.cols << endl;
	//cout << eValuesMat << endl;
	ott.str("");
	for (int i = 1; i <= simple_class_num; i++) {
		for (int j = 1; j <= simple_single_num; j++) {
			oss << readPath << i << readPath2 << j << readPath4;
			img2 = imread(oss.str(), IMREAD_GRAYSCALE);
			face_aim = img2.reshape(0, 1).t();
			oss.str("");
			if (i == 1 && j == 1) {
				d = cal(Mat_transto - eVectorsMat * (face_aim - face_mean_single));
				aim_class = i;
				aim_order = j;
				//cout << d << endl;
			}
			else {
				temp = cal(Mat_transto - eVectorsMat *(face_aim- face_mean_single));
				if (temp <= d) {
					d = temp;
					//cout << d << endl;
					aim_class = i;
					aim_order = j;
				}
			}
		}
	}
	cout << "当前k为:" << k << endl;
	cout << "识别成功!结果:第" << aim_class << "类 : 第 " << aim_order << "张图" << endl;
	cout << "当前降维率为:" << percent << endl;
	//imshow("图片", img);
	//waitKey(0);
	return 0;
}

结论

PCA降维呢,在这篇人脸识别的过程也有明显体现的地方,仔细看看就能明白
其中几个算法的具体代码我就不贴了,代码效率太低;
这个代码有很多需要完善的地方,包括读取像素矩阵、判断相应的识别图片等等地方,使用的方法都很简单暴力
暂时先这么多,日后如果想起来再补充
因为是第一次学习这东西嘛~如果有原理上理解错误的地方或者值得改进的地方,欢迎大佬指出,感谢!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值