1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 主成分分析-简单人脸识别(二)

主成分分析-简单人脸识别(二)

时间:2021-01-24 13:26:23

相关推荐

主成分分析-简单人脸识别(二)

一):人脸预准备

(文章说明:正常的人脸识别时,需要的是足够多的样本来进行训练,以期达到准确率高的目的。这里,只是尝试运用PCA算法基本上实现人脸的识别。)

那么我所使用到的人脸模板就是简单的12张处理过的人脸图像(很多是直接从网上下载的,有涉及到肖像权的请通知哈~_~!)。正常情况下,为了使算法更好,怎么也得好多个不同的人脸图片吧,对每张脸来说,怎么也得好几副不同的图像才可以达到很好的效果。(作为简单介绍性实验就先用这些单一的模板)。

对于每张人脸的大小和比例剪切将直接影响到结果的好坏,这里就尽量选取人脸中心的部分,避免图片中含有较多的头发、图片太暗等等。我这里把每张图片处理成150*180像素大小的,为了便于一次性显示,这里将图片叠在一起如下所示,想做同样实验的可以自己去找图片处理咯。

二):图片储存与预处理

在进行PCA分析图片之前,首先得明白图片作为一个样本的输入格式,怎么样输入便于函数的整体处理等等。我们知道,对于一副图像来说,它是一个矩阵形式存在,彩色图像更是复杂,所以在这里处理时,首先对图像进行灰度处理。既然一副图是一个矩阵,那么怎么把所有的人脸样本整合在一块呢?这里参考别人的做法,把一副M*N的图像重新变换成1*(M*N)的图像,matlab中的函数是reshape函数。这样每一个人脸变成1行多列的数据,在把所有的图像按行的形式叠加起来就形成了a*b的样本空间,其中a就表示样本个数,b就是样本的初始维度,而我们要做的不就是通过PCA方法来降低维度b吗?

根据上面对数据存储的方式编写程序如下(前提是你的图像得事先处理成相同大小的,并且导入到目录文件夹才行):

%--------------函数说明------------- % 整合输入的人脸样本% 输出:样本矩阵%----------------------------------- function ImgData = imgdata()%用法: ImgData = imgdata();namud = 0.5; %原始图片缩小倍数%分别导入图片pic1 = rgb2gray(imread('1.jpg')); pic1 = imresize(pic1,namud);pic2 = rgb2gray(imread('2.jpg')); pic2 = imresize(pic2,namud);pic3 = rgb2gray(imread('3.jpg')); pic3 = imresize(pic3,namud);pic4 = rgb2gray(imread('4.jpg')); pic4 = imresize(pic4,namud);pic5 = rgb2gray(imread('5.jpg')); pic5 = imresize(pic5,namud);pic6 = rgb2gray(imread('6.jpg')); pic6 = imresize(pic6,namud);pic7 = rgb2gray(imread('7.jpg')); pic7 = imresize(pic7,namud);pic8 = rgb2gray(imread('8.jpg')); pic8 = imresize(pic8,namud);pic9 = rgb2gray(imread('9.jpg')); pic9 = imresize(pic9,namud);pic10 = rgb2gray(imread('10.jpg')); pic10 = imresize(pic10,namud);pic11 = rgb2gray(imread('11.jpg')); pic11 = imresize(pic11,namud);pic12 = rgb2gray(imread('12.jpg')); pic12 = imresize(pic12,namud);[m,n] = size(pic1); %取图片大小% 下面采用一个细胞体结构的数据类型存储多个矩阵pic_all = {pic1,pic2,pic3,pic4,pic5,pic6,pic7,pic8,pic9,pic10,pic11,pic12};for i=1:12%把m*n的矩阵变换成1*(m*n)的矩阵ImgData(i,:) = reshape(pic_all{i},1,m*n);end%讲数据范围缩小到0到1之间ImgData = double(ImgData)/255;

说明一下,为什么要缩小一倍,后面在PCA求取协方差与提取特征向量的时候考虑到数据量太大的缘故,如果效果不好的话可以改变这个系数。这样就把原始数据图像所有样本全部存入到一个矩阵中。

三):主成分分析

得到了样本矩阵,接下来是对该矩阵进行特征值与特征向量的提取,以达到降维的目的。这部分原理基础在上一篇介绍过了:

/on2way/article/details/42175439

那么直接编程序实现:

<span style="font-size:18px;">%--------------函数说明------------- %-----简单主成分分析算法%-----输入:样本集合矩阵:img% 降维的维数 :k%-----输出:细胞结构体数据 :Cell_all%----------------------------------- function Cell_all = PCA(img,k)%reshape函数:改变句矩阵的大小,矩阵的总元素个数不能变%img = [1,2;2,1;3,3;3,6;6,3];% k = 2;% img = double(img);[m,n] = size(img); %取大小img_mean = mean(img); %求每列平均值img_mean_all = repmat(img_mean,m,1);%复制m行平均值至整个矩阵Z = img - img_mean_all;T = Z'*Z;%协方差矩阵 [V,D] = eigs(T,k);%计算T中最大的前k个特征值与特征向量img_new = img*V*D; %低维度下的各个脸的数据Cell_all = {img_new,V,D};</span>

可能会注意到上面的img_new=img*V*D;这里把特征值矩阵也乘上了,本质上特征值的大小代表的是这个向量方向上的对原始数据的影响程度,乘上以后个人理解就是加大了低维里面的不同维度之间的这种差异性。我也试过不乘这个D,发现效果还没有乘上好,索性就乘上了。

函数返回的是一个结构体的数据,这里比较有趣的是对特征向量V的分析。

如果我们选取的k=30的话,得到V的大小为6750*30(这里一副人脸变换后的大小是1*6750了),表示有30维的特征向量(取的是特征值最大的前30个)。

这里如果我们单把第一主分量、第二主分量等等对应的特征向量以图片的形式显示出来会怎样?比如选取V中的第一列所有数据(成分最大的向量方向),再把它变换成原图片的大小的样子,再显示出来,这就形成了所谓的特征脸,

程序如下(V已经知道了):

namud=0.5;

V=Cell_all{2};

V=V';

pic=V(1,:);%取第一个最大的主成分

pic=reshape(pic,180*namud,150*namud);%变换成图片大小

imshow(pic,[]);

运行后结果如下:

这就是第一主成分下的特征向量脸。

那么我们再把第二大特征向量、第三大特征向量等等都显示出来:

namud=0.5;

V=Cell_all{2};

V=V';

[m,n]=size(V);%取大小

fori=1:m

pic{i}=V(i,:);

pic{i}=reshape(pic{i},180*namud,150*namud);

end

p=pic{1};imshow(p,[]);

subplot(2,5,1);p=pic{1};imshow(p,[]);

subplot(2,5,2);p=pic{2};imshow(p,[]);

subplot(2,5,3);p=pic{3};imshow(p,[]);

subplot(2,5,4);p=pic{4};imshow(p,[]);

subplot(2,5,5);p=pic{5};imshow(p,[]);

subplot(2,5,6);p=pic{6};imshow(p,[]);

subplot(2,5,7);p=pic{7};imshow(p,[]);

subplot(2,5,8);p=pic{8};imshow(p,[]);

subplot(2,5,9);p=pic{9};imshow(p,[]);

subplot(2,5,10);p=pic{10};imshow(p,[]);

这里给出前10个的程序,再给出接着的后10的程序(省略了,只用改一下相关pic里面的数字就可以了),一共前20个特征向量的图像(30维里面,还有10个就不显示了),得到结果为:

前10个:

前11~20个:

可以看到,到13主分量以后的分量上的特征脸,基本上特征向量已经不再是表示一个人脸的某部分特征了,而是一些其他方面的噪声(可能吧),也就是说可能只是前13个分量在起作用,或者说其实把这些样本降维到13维下是不是最好的呢?

四):检验识别效果

有了上面计算出来的特征向量以及特征值的基础后,接下来我们来重新输入一个人脸图像,看看识别的怎么样。这里直接以上述人脸排列的序号作为识别的结果返回。

有一个问题就是怎么定义待检测的脸与样本中的脸的差别呢?我们上面计算了,原始样本脸在新维度(30维)下的脸的数据,是不是就是img_new=img*V*D;这个值,那么来一个新的脸,同样先预处理(先缩小,在拉申成1行数据),处理后假设为x(1行n列了),那么x在新的低维度空间里面的数据是什么呢?直接相乘V与D吧,也就是xx=x*V*D;有了原始样本和待检测样本在低维空间的数据,要判断待检测样本与哪个样本最相近,直接求取高维空间中点与点之间的欧氏距离不就可以了,想象一下三维坐标中,两个点如果很像,靠的很近,那么两个点之间的距离是不是很小?Matlab中求点距离直接用求范数的函数norm就可以。

基于此来编写程序如下:

<span style="font-size:18px;">%--------------函数说明------------- %-----人脸匹配%-----输入:细胞结构体数据Cell_all(包括样本集合,特征值与特征向量)% 想要识别的人脸(彩色图像)%-----输出:匹配的结果%----------------------------------- function FaceFind = facefind(Cell_all,img2find)%细胞结构体的调用img_all = Cell_all{1};[m1,n1] = size(img_all);V = Cell_all{2};D = Cell_all{3};namud = 0.5; %图片缩小的倍数%对需要识别的图像进行灰度等的处理pic = rgb2gray(img2find); %灰度处理pic = imresize(pic,namud); %变换大小[m2,n2] = size(pic); pic = reshape(pic,1,m2*n2); %重新排列pic = double(pic)/255; pic_done = pic*V*D; %处理完的数据%% 归一化 --》避免运算出现特别大的数据Ma = max(max(pic_done));Mi = min(min(pic_done));pic_done = pic_done/(Ma - Mi);%%for i=1:m1% 归一化 --》避免运算出现特别大的数据Ma1 = max(img_all(i,:));Mi1 = min(img_all(i,:));img_all(i,:) = img_all(i,:)/(Ma1 - Mi1);%求范数--》把他们之间的几何距离作为评判与哪一个人脸最近的标准error(i) = norm(img_all(i,:)-pic_done);end%找到其中最近的就认为是所要识别的人脸FaceFind = find(error == min(error));% FaceFind = error;</span><span style="font-size:14px;"></span>

上述中有一些需要对数据进行大小调整,避免数据太大运行慢。

准备完成了就来进行实验吧,试验之前得先找到要待测脸,并且又得与原始样本不一样,考虑样本难找(得去专业人脸数据库中去找),直接自己手工制作吧(把某副原始样本PS下,人为制造不同~—~)(第三个样本就不是PS了,而是博主直接自己贡献出来了,找了张不同的图片,哈哈!~—~!)。

对这三幅图像分别进行匹配,运行函数facefind如下:

>>FaceFind1=facefind(Cell_all,test2),

FaceFind2=facefind(Cell_all,test1),

FaceFind3=facefind(Cell_all,test)

FaceFind1=

1

FaceFind2=

10

FaceFind3=

2

对应的结果就是原始样本的下列:

从结果来看第一张和第三张正确,第二张错了(。。。话说样本中第一与第十的美女样本确实很像呀),原因是人为制造的干扰过多?当然主要还是样本量太少,训练不够所致,算法上也是最简单的实验那种,还可以有很多优化改进。有机会去下载人脸数据库来实验实验,兴许结果会好些。

补充:PCA人脸数据库下的实验

PCA实验人脸库-人脸识别(四)

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。