转载至:http://blog.csdn.net/u011001084/article/details/51363892
转载至:http://blog.csdn.net/jinshengtao/article/details/18599165
PCA人脸识别
将PCA用于人脸识别的过程如下:
1.假设有400幅尺寸为100*100的图像,构成10000*400的矩阵;
2.计算均值,令;
3.根据定义,计算协方差矩阵;
4.计算的特征值与特征向量,取前h个最大特征值所对应的特征向量,构成矩阵;
5.矩阵可对数据降维:,Y是h行400列的矩阵,也就是将数据从10000维降为h维。
这种做法一个明显的缺陷在于,的维度为10000×10000,直接进行奇异值分解计算量非常大。利用QR分解,作间接的奇异值分解,可以减小计算量。
利用QR分解减小计算量
基于QR分解的PCA算法步骤如下:
1.已知,其中为d*d,H为d*n,d代表原始数据的维数,n代表样本数,d远大于n;
2.对H作QR分解,,其中Q为d*t,R为t*n,;
3.则,对作奇异值分解,其中U为n*t,V为t*t,;
4.于是,其中;
5.由于,所以QV可将对角化,QV为的特征向量矩阵,为的特征值矩阵;
6.选取D前h个最大对角元所对应于V中的h个列,构成t*h的矩阵,则降维矩阵;
1。加载数据, 计算均值,生成协相关矩阵void load_data(double *T,IplImage *src,int k)
{
int i,j;
//一副图像压缩成一维的,存在T的一列里
for (i=0;iimageData[i*IMG_WIDTH+j];
}
}
}
void calc_mean(double *T,double *m)
{
int i,j;
double temp;
for (i=0;i
2.计算生成矩阵P的特征值和特征向量,并挑选合适的特征值和特征向量,构造特征子空间变化矩阵。
void cstrq(double a[],int n,double q[],double b[],double c[])
{
int i,j,k,u,v;
double h,f,g,h2;
for (i=0; i<=n-1; i++)
for (j=0; j<=n-1; j++)
{ u=i*n+j; q[u]=a[u];}
for (i=n-1; i>=1; i--)
{ h=0.0;
if (i>1)
for (k=0; k<=i-1; k++)
{ u=i*n+k; h=h+q[u]*q[u];}
if (h+1.0==1.0)
{ c[i]=0.0;
if (i==1) c[i]=q[i*n+i-1];
b[i]=0.0;
}
else
{ c[i]=sqrt(h);
u=i*n+i-1;
if (q[u]>0.0) c[i]=-c[i];
h=h-q[u]*c[i];
q[u]=q[u]-c[i];
f=0.0;
for (j=0; j<=i-1; j++)
{ q[j*n+i]=q[i*n+j]/h;
g=0.0;
for (k=0; k<=j; k++)
g=g+q[j*n+k]*q[i*n+k];
if (j+1<=i-1)
for (k=j+1; k<=i-1; k++)
g=g+q[k*n+j]*q[i*n+k];
c[j]=g/h;
f=f+g*q[j*n+i];
}
h2=f/(h+h);
for (j=0; j<=i-1; j++)
{ f=q[i*n+j];
g=c[j]-h2*f;
c[j]=g;
for (k=0; k<=j; k++)
{ u=j*n+k;
q[u]=q[u]-f*c[k]-g*q[i*n+k];
}
}
b[i]=h;
}
}
for (i=0; i<=n-2; i++) c[i]=c[i+1];
c[n-1]=0.0;
b[0]=0.0;
for (i=0; i<=n-1; i++)
{ if ((b[i]!=0.0)&&(i-1>=0))
for (j=0; j<=i-1; j++)
{ g=0.0;
for (k=0; k<=i-1; k++)
g=g+q[i*n+k]*q[k*n+j];
for (k=0; k<=i-1; k++)
{ u=k*n+j;
q[u]=q[u]-g*q[k*n+i];
}
}
u=i*n+i;
b[i]=q[u]; q[u]=1.0;
if (i-1>=0)
for (j=0; j<=i-1; j++)
{ q[i*n+j]=0.0; q[j*n+i]=0.0;}
}
return;
}
//q:特征向量,b:特征值
int csstq(int n,double b[],double c[],double q[],double eps,int l)
{
int i,j,k,m,it,u,v;
double d,f,h,g,p,r,e,s;
c[n-1]=0.0; d=0.0; f=0.0;
for (j=0; j<=n-1; j++)
{ it=0;
h=eps*(fabs(b[j])+fabs(c[j]));
if (h>d) d=h;
m=j;
while ((m<=n-1)&&(fabs(c[m])>d)) m=m+1;
if (m!=j)
{ do
{ if (it==l)
{ printf("fail\n");
return(-1);
}
it=it+1;
g=b[j];
p=(b[j+1]-g)/(2.0*c[j]);
r=sqrt(p*p+1.0);
if (p>=0.0) b[j]=c[j]/(p+r);
else b[j]=c[j]/(p-r);
h=g-b[j];
for (i=j+1; i<=n-1; i++)
b[i]=b[i]-h;
f=f+h; p=b[m]; e=1.0; s=0.0;
for (i=m-1; i>=j; i--)
{ g=e*c[i]; h=e*p;
if (fabs(p)>=fabs(c[i]))
{ e=c[i]/p; r=sqrt(e*e+1.0);
c[i+1]=s*p*r; s=e/r; e=1.0/r;
}
else
{ e=p/c[i]; r=sqrt(e*e+1.0);
c[i+1]=s*c[i]*r;
s=1.0/r; e=e/r;
}
p=e*b[i]-s*g;
b[i+1]=h+s*(e*g+s*b[i]);
for (k=0; k<=n-1; k++)
{ u=k*n+i+1; v=u-1;
h=q[u]; q[u]=s*q[v]+e*h;
q[v]=e*q[v]-s*h;
}
}
c[j]=s*p; b[j]=e*p;
}
while (fabs(c[j])>d);
}
b[j]=b[j]+f;
}
for (i=0; i<=n-1; i++)
{ k=i; p=b[i];
if (i+1<=n-1)
{ j=i+1;
while ((j<=n-1)&&(b[j]<=p))
{ k=j; p=b[j]; j=j+1;}
}
if (k!=i)
{ b[k]=b[i]; b[i]=p;
for (j=0; j<=n-1; j++)
{ u=j*n+i; v=j*n+k;
p=q[u]; q[u]=q[v]; q[v]=p;
}
}
}
return(1);
}
void matrix_reverse(double *src,double *dest,int row,int col) //转置
{
int i,j;
for(i = 0;i < col;i++)
{
for(j = 0;j < row;j++)
{
dest[i * row + j] = src[j * col + i];
}
}
}
void matrix_mutil(double *c,double *a,double *b,int x,int y,int z) //矩阵乘法
{
int i,j,k;
for (i=0;i
3.挑选合适的特征值和特征向量,其实就是挑特征值大于1的
void pick_eignevalue(double *b,double *q,double *p_q,int num_q)
{
int i,j,k;
k=0;//p_q的列
for (i=0;i1)
{
for (j=0;j
4计算Q的特征向量和样本集像子空间投影的代码
void get_eigenface(double *p_q,double *T,int num_q,double *projected_train,double *eigenvector)
{
double *temp;
double tmp;
int i,j,k;
//IplImage *projected;
//char res[20]={0}; //file name
projected = cvCreateImage(cvSize(IMG_WIDTH,IMG_HEIGHT),IPL_DEPTH_8U,1);
//temp = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);//按列存取
memset(eigenvector,0,sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);
memset(projected_train,0,sizeof(double)*TRAIN_NUM*num_q);
//求特征脸
//matrix_mutil(temp,T,p_q,IMG_WIDTH*IMG_HEIGHT,TRAIN_NUM,num_q);
/*for (i=0;iimageData[j*IMG_WIDTH+k] = (unsigned char)abs(temp[(j*IMG_WIDTH+k)*num_q+i]);
}
}
cvSaveImage(res,projected);
}*/
//求Q的特征向量X*e,矩阵相乘
temp = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);
matrix_mutil(temp,T,p_q,IMG_HEIGHT*IMG_WIDTH,TRAIN_NUM,num_q);
//投影到子空间
matrix_reverse(temp,eigenvector,IMG_WIDTH*IMG_HEIGHT,num_q);
matrix_mutil(projected_train,eigenvector,T,num_q,IMG_WIDTH*IMG_HEIGHT,TRAIN_NUM);
free(temp);
}
#include "stdafx.h"
#include "Process.h"
#include "My_Matrix.h"
int _tmain(int argc, _TCHAR* argv[])
{
double *T,*L,*m,*b,*q,*c,*p_q,*projected_train,*T_test,*projected_test,*eigenvector,*Euc_dist;
double eps,temp;
int i,j,flag,iteration,num_q;
char res[20];
IplImage *tmp_img,*test_img;
T = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*TRAIN_NUM); //原始数据
T_test = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*1); //测试数据
m = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH); //平均值
L = (double *)malloc(sizeof(double)*TRAIN_NUM*TRAIN_NUM); //L=T'*T,协方差矩阵
b = (double *)malloc(sizeof(double)*TRAIN_NUM); //L的特征值
q = (double *)malloc(sizeof(double)*TRAIN_NUM*TRAIN_NUM); //L特征值对应的特征向量
c = (double *)malloc(sizeof(double)*TRAIN_NUM); //实对称三对角矩阵的次对角线元素
eps = 0.000001;
memset(L,0,sizeof(double)*TRAIN_NUM*TRAIN_NUM);
//存储图像数据到T矩阵
for (i=1;i<=TRAIN_NUM;i++)
{
sprintf(res,".\\TrainDatabase\\%d.jpg",i);
tmp_img = cvLoadImage(res,CV_LOAD_IMAGE_GRAYSCALE);
load_data(T,tmp_img,i);
}
//求T矩阵行的平均值
calc_mean(T,m);
//构造协方差矩阵
calc_covariance_matrix(T,L,m);
//求L的特征值,特征向量
iteration = 60;
cstrq(L,TRAIN_NUM,q,b,c);
flag = csstq(TRAIN_NUM,b,c,q,eps,iteration); //数组q中第j列为数组b中第j个特征值对应的特征向量
if (flag<0)
{
printf("fucking failed!\n");
}else
{
printf("success to get eigen value and vector\n");
}
//对L挑选合适的特征值,过滤特征向量
num_q=0;
for (i=0;i1)
{
num_q++;
}
}
p_q = (double *)malloc(sizeof(double)*TRAIN_NUM*TRAIN_NUM); //挑选后的L的特征向量,仅过滤,未排序
projected_train = (double *)malloc(sizeof(double)*TRAIN_NUM*num_q); //投影后的训练样本特征空间
eigenvector = (double *)malloc(sizeof(double)*IMG_HEIGHT*IMG_WIDTH*num_q);//Pe=λe,Q(Xe)=λ(Xe),投影变换向量
pick_eignevalue(b,q,p_q,num_q);
get_eigenface(p_q,T,num_q,projected_train,eigenvector);
//读取测试图像
test_img = cvLoadImage(".\\TestDatabase\\4.jpg",CV_LOAD_IMAGE_GRAYSCALE);
projected_test = (double *)malloc(sizeof(double)*num_q*1);//在特征空间投影后的测试样本
for (i=0;iimageData[i*IMG_WIDTH+j] - m[i*IMG_WIDTH+j];
}
}
//将待测数据投影到特征空间
memset(projected_test,0,sizeof(double)*num_q);
matrix_mutil(projected_test,eigenvector,T_test,num_q,IMG_WIDTH*IMG_HEIGHT,1);
return 0;
}