快捷搜索:  汽车  科技

人脸识别算法通俗易懂(最简单的人脸识别算法)

人脸识别算法通俗易懂(最简单的人脸识别算法)string = strcat(a b)b = 'goodbye';下面简单介绍一下哦。首先,说一下提取特征的方法。图像的每个像素都表征了图像某个位置的灰度值,可以作为图像的识别特征。但是,考虑到对于一幅100x100的图像来说,图像的像素数是10000,如果直接使用所有像素作为图像的特征,一方面肯定存在很多的冗余信息,另一方面计算量也很大。缩小图像尺寸是解决这个问题的不错方法。将100x100的图像缩小到10x10,特征点数就从10000将到100了,大大的降低了运算量。②strcat() 字符粘连。简单说,该函数参数必须是字符,它的作用就是将各个参数按次序粘连起来。例如:a = 'hello ';

目标

目的:为了让大家了解图像识别和检索的算法开发过程,以及加深对特征和分类器的理解。

概要

对于图像分类和检索来说,最重要的有两个内容,一个是特征提取方法,另一个是分类方法。图像识别就是先提取图像的特征,然后根据图像的特征进行分类识别的过程。为了让大家最快的了解图像识别算法的开发过程,我特意使用“图像尺寸缩小 欧式距离”的思想编写了相应的程序。算法实现的流程图如下图所示。

人脸识别算法通俗易懂(最简单的人脸识别算法)(1)

下面简单介绍一下哦。首先,说一下提取特征的方法。图像的每个像素都表征了图像某个位置的灰度值,可以作为图像的识别特征。但是,考虑到对于一幅100x100的图像来说,图像的像素数是10000,如果直接使用所有像素作为图像的特征,一方面肯定存在很多的冗余信息,另一方面计算量也很大。缩小图像尺寸是解决这个问题的不错方法。将100x100的图像缩小到10x10,特征点数就从10000将到100了,大大的降低了运算量。

②strcat() 字符粘连。简单说,该函数参数必须是字符,它的作用就是将各个参数按次序粘连起来。例如:

a = 'hello ';

b = 'goodbye';

string = strcat(a b)

以上代码是定义2个字符变量a和b,然后将这2个字符变量粘连起来。运行结果如下所示:

人脸识别算法通俗易懂(最简单的人脸识别算法)(2)

③num2str() 将数值型数据转换成字符型。例如,像1是数值型数据,而‘1’就是字符型数据。该函数就是实现从1到‘1’的转换。帮助文件中的一个例子:

num2str(pi);

以上代码是将数值型

转换成字符的形式。运算结果如下所示:

人脸识别算法通俗易懂(最简单的人脸识别算法)(3)

人脸识别算法通俗易懂(最简单的人脸识别算法)(4)

想了解更多的话,请打命令“doc num2str”,回车,查看帮助文件。或者baidu or google一下,或者去Matlab中文论坛查询帮助。

④imread() 读入图像文件。以前给大家讲过了,这里再说一点研一不知道的东东。原来使用这个命令,参数就是文件的名字,这样做有个前提,就是该图像文件必须在当前工作路径或搜索路径(what is it ? go to baidu for answer!),否则程序报错,说没有该文件。现在就有一个问题,如果我想导入一个图像,它不在当前路径下,也不再搜索路径下,而我还不想切换工作路径,

人脸识别算法通俗易懂(最简单的人脸识别算法)(5)

?imread函数本身就可以解决这个问题。imread的参数改成“路径 文件名 格式”,如下所示:

I = imread(‘F:\科研\人脸识别\人脸数据库\ORL\1_1.pgm’);

以上代码就解决图像文件不在当前路径或搜索路径下的问题。注意:文件夹之间的分割符是反斜杠“\”,而不是斜杠“/”。想了解更多,doc一下!!!

⑤imresize() 图像尺变化。即原图像尺寸是100x100,但是我们现在需要10x10的图像,使用该函数就可以实现。即,该函数可以将100x100的图像变换为10x10的图像。

I = imread('rice.png');

J = imresize(I [128 128]);

以上代码的功能是,’先读入rice.png’图像,原图像的尺寸是256x256的,然后将原图像的尺寸变换为128x128,然后存储在J变量中。运算的结果是:

人脸识别算法通俗易懂(最简单的人脸识别算法)(6)

当然imresize还有其它的调用形式,想了解的话,请doc一下。(养成一个doc的习惯,就提高了自学的能力哦!)

⑥reshape() 变换矩阵的形状。假如一个矩阵为10x10的尺寸,现在想将这个矩阵变换为100x1的列向量,但是原矩阵的数据都保留下来。例如:

a=[1 2 3;4 5 6];

b=reshape(a [1 6]);

以上代码功能是,先建立一个2x3的矩阵a,然后将它变为一个1x6的行向量并存储在b中。程序的运行结果:

人脸识别算法通俗易懂(最简单的人脸识别算法)(7)

人脸识别算法通俗易懂(最简单的人脸识别算法)(8)

⑦转置运算 简单的说,就是行和列交换。例如

a=[1 2 3;4 5 6];

b = a'

a是一个2x3的矩阵,交换它的行和列,得到3x2的矩阵b。结果如下所示:

人脸识别算法通俗易懂(最简单的人脸识别算法)(9)

人脸识别算法通俗易懂(最简单的人脸识别算法)(10)

基础之欧式距离判别法

文中使用的函数介绍完了,下面介绍一下欧式距离判别法,即最近距离法。简单的说,欧式距离就是空间中2个点之间的距离。在立体空间中,两点之间距离的计算公式是:

这就是三维空间中的欧式距离计算公式。同理,如果有2个n维向量,分别是

。则a和b两向量之间的距离是什么呢?类比三维空间中的距离公式,知a和b每个对应分量相减并平方,求所有平方的和,然后开根号,就得到了n维向量a和b之间的距离。计算公式如下所示:

想要了解更多关于“欧式距离分类器”的同学,可以去图书馆借张学工的《模式识别》这本书(或任何一本《模式识别》),分类器的东东肯定会出现在模式识别方面的书籍中。而作为最经典的分类器,欧式距离分类器一定会出现在每一本《模式识别》中,还等什么,借一本看看长啥样子啊!!!

大家在学习的时候,不要只见树木,不见森林。就是说,这里虽然主要讲欧式距离判别法,但是,其中还隐含了很多其它的信息,要学会提出问题,然后通过各种途径来解决问题,这就是提升自己的最好的方法。(上面这句话说了两点,第一点,学会题问题,如果没问题那就说明一点不懂,所以提不出来;第二点,通过什么途径来解决问题呢?其实最好的方法是自己查阅资料,收集相关信息,然后悟透;不过我个人认为baidu 和 google 在解决一些问题时,是最好的老师,也是知识最渊博的老师。{大家对这句话理解的越深,你会发现进步的越快!!!}

人脸识别算法通俗易懂(最简单的人脸识别算法)(11)

,这都告诉你们了,感觉损失大了)

为了实现本文的算法,我特意使用上面的公式编写了一个欧式距离分类器。即edpredict.m文件。下面简单的介绍一下该函数文件。

该函数文件的源代码如下所示:

function [index accuracy] = edpredict(dtrain dtest ltrain ltest)

---------------------------------------------------------------------------------------------------------------标记1

if nargin ~= 4

disp('输入的参数必须是4个');

return;

end

if length(size(dtrain)) ~= 2

disp('训练样本必须是二维矩阵!');

return;

end

if length(size(dtest)) ~= 2

disp('测试样本必须是二维矩阵!');

return;

end

if size(dtrain 2) ~= size(dtest 2)

disp('测试样本特征向量维度应该和训练样本特征向量维数相同!');

end

--------------------------------------------------------------------------------------------------------------标记2

dtrain = double(dtrain); % 训练数据

dtest = double(dtest); % 测试数据

ltrain = double(ltrain); % 训练样本标签

ltest = double(ltest); % 测试样本标签

-------------------------------------------------------------------------------------------------------------标记3

[m1 ~] = size(dtrain);

[m2 ~] = size(dtest);

index = zeros(m2 1);

-------------------------------------------------------------------------------------------------------------标记4

for i = 1:m2

distance = 1000000;

for j = 1:m1

temp = sqrt(norm(dtest(i :) - dtrain(j :)));

if distance > temp

distance = temp;

index(i) = ltrain(j); % 预测标签

end

end

end

-------------------------------------------------------------------------------------------------------------标记5

accuracy = 100*sum(index == ltest)/m2; % 准确度

str = strcat('accuracy = ' num2str(accuracy) '%' ' (classify)');

disp(str);

end

首先说function。MATLAB的m文件有两种,一种是脚本文件,一种是函数文件。它们的相同点都是由一系列的命令组成的,但是,脚本文件不能返回变量哦,函数文件可以啊!即,调用脚本文件时,它能实现一定的功能并产生一些结果,但是不能返回任何东东到调用的位置。但是当调用函数文件时,处理完成脚本文件的功能外,还能返回变量到调用位置。大家明白没有?没有的话baidu或看看matlab教程。不过话说回来,大家不明白也就算了,这里其实就想说function的功能是:声明本文件是函数文件,不是脚本文件。(脚本文件的话,开头没有标志性的语句,直接开始写自己的代码就可以了)

第一行“function [index accuracy] = edpredict(dtrain dtest ltrain ltest)”叫函数头,function声明这是函数文件,等号左边是函数的返回变量,即[index accuracy];等号右边是函数名(edpredict)和输入参数” (dtrain dtest ltrain ltest)”。注意几点:①定义函数时,函数的名字一定想好,不要和MATLAB自带函数重名;②参数之间都是用逗号间隔开的,记住哦!!!

从第二行开始下面是4个if条件语句。第一个if语句,如下所示:

if nargin ~= 4

disp('输入的参数必须是4个');

return;

end

它的功能是:判断输入变量个数是不是4个,nargin表示输入变量个数,当nargin不等于4时,在命令窗口中显示“输入的参数必须是4个”,并终止整个程序(由return实现)。注意:if语句和for循环都是用end结束的。

第2个if语句的功能是:判断输入变量dtrain的维数是否是2维,如果不是2维的话,就报错,并终止程序。

第3个if语句的功能和第2个if语句几乎相同,只不过这里判断的变量是dtest。

第4个if语句的功能是判断训练样本的特征向量维数和测试样本的特征向量维数是否相等。如果不相等,欧氏距离也就没有办法计算了!!!

思考:为什么加这些if语句?

编写函数文件是为了实现一定的功能的,但它只能处理特定的数据。如果输入的数据不符合程序的需要,程序执行过程中也会报错(这还是好事,如果不报错,你的程序按照错误的方式执行,你还以为结果是正确的,这才真悲剧!)。所以,为了程序的正常运行,有必要在正式执行程序前,检测一下输入变量是否符号要求。

下面就是程序的主要内容了,就像脚本文件中一样写代码就可以了。标记2下面的四行语句的功能是将输入变量都变成double型,目的是为了防止有的输入变量不是双精度。这四行分别将训练样本、测试样本、训练样本标签和测试样本标签变成双精度数据。

标记3和标记4之间的代码如下所示:

[m1 ~] = size(dtrain);

[m2 ~] = size(dtest);

index = zeros(m2 1);

第一行代码计算了dtrain的尺寸,m1即dtrain的行数;同理,第2行代码计算dtest的行数m2。第3行生成的全0变量index,是用来存储测试样本的预测标签的。

标记4下面的for循环实现了欧式距离分类器的功能。其中,i=1:m2分别对应每一个测试样本,即最外边的循环执行一次,就处理一个测试样本。”distance = 1000000;”设定了初始距离(该距离必须足够大)。内部的for循环j = 1:m1 是对所有的训练样本进行了遍历,其实就是一个测试样本和所有的训练样本做了次比较。“temp = sqrt(norm(dtest(i :) - dtrain(j :)));”就是利用上面的公式计算欧式距离。下面的if语句实现的功能是:判断刚刚计算的欧式距离temp和参考距离distance的大小关系,当temp小于distance时,说明这两个样本之间的距离更近(欧式距离又称为最近距离法,当然认为最近的两个样本为同一类了),就把temp的值赋给distance,并将该训练样本的标签放到index中,作为该测试样本的预测标签。总的来说,就是先拿出一个测试样本,然后计算它和所有训练样本之间的距离,与它距离最近的训练样本的标签就是该测试样本的预测值。

标记5下面的语句就是实现计算准确度,并在命令窗口中显示准确度。第一个语句计算了准确度,index是测试样本的预测值,ltest是测试样本的实际值,如果它们相等,就说明预测结果对呗。求预测对的个数sum()并除以总数m2,就得到了准确度。

最简人脸识别程序

最简单的人脸识别算法的实现程序在FaceED1.m文件中,当然为了便于大家观察,还是将代码贴在下面吧。

% ORL人脸库 欧式距离分类器

% 有均值化

clear;

clc;

-------------------------------------------------------------------------------------------------------------标记1

M=40; @个人

N=5; %选每个人的前五幅图片

row=8; %图像尺寸归一化后的行数

clum=7; %图像尺寸归一化后的列数

pho=zeros(row*clum M*N); %用来存储训练样本

pic=zeros(row*clum M*(10-N)); %用来存储测试样本

-------------------------------------------------------------------------------------------------------------标记2

% 导入训练样本

t=1; %赋值t的值为1

for i=1:M

for j=1:N

str=strcat('F:\科研\人脸识别\人脸数据库\ORL\' num2str(i) '_' num2str(j) '.pgm');%获得图像的路径

I1=imread(str); %读入图像

I2=imresize(I1 [row clum]); % 尺寸变换

pho(: t) = reshape(I2 [row*clum 1]); % 形状变换

t=t 1; %计数变量t加1

end

end

dtrain = pho'; % 转置,dtrain中每一行表示一个样本

-------------------------------------------------------------------------------------------------------------标记3

% 导入测试样本

t = 1;

for i=1:M

for j=N 1:10

str=strcat('F:\科研\人脸识别\人脸数据库\ORL\' num2str(i) '_' num2str(j) '.pgm');%获得图像的路径

I1=imread(str); %读入图像

I2=imresize(I1 [row clum]); % 尺寸变换

pic(: t) = reshape(I2 [row*clum 1]); % 形状变换

t=t 1; %计数变量t加1

end

end

dtest = pic';

-------------------------------------------------------------------------------------------------------------标记4

% 获取标签

ltrain = zeros(M*N 1); % 存储训练样本的标签

ltest = zeros(M*(10-N) 1); % 存储测试样本的标签

for i=0:M-1

ltrain((N*i 1):(N*i N) 1)=i 1; % 添训练样本加标签

ltest(((10-N)*i 1):(10-N)*(i 1) 1)=i 1; % 添加测试样本标签

end

-------------------------------------------------------------------------------------------------------------标记5

[pre accuracy] = edpredict(dtrain dtest ltrain ltest);

上面的程序中已添加了必要的注释,为了更好的理解本程序,下面给出了简要的说明。标记1上面的东东就是清空工作空间和命令窗口的。这也是MATLAB写脚本文件的常识,其实,就是为了防止工作空间中的变量影响程序的运行。当然,这不是硬性的要求,不过还是建议添加,这样子更专业点哦!

对了,忘了说了,这个就是一个脚本文件,开头没有function引导哦。知道区别了吧!不知道的话google去吧~

标记1和标记2之间的东东就是设置一个参数,“M=40;”限定了使用40个人的图像,当然也可以改成20,或10,分别表示使用20个人或10个人的样本图像。“N=5;”限定了每个人的训练样本数量,就是说,每个人有10个样本图像,取前5个作为训练样本(剩下的呢,当然是用来做测试样本了)。“row=8; clum=7; ”限定了图像的尺寸变换后的尺寸。前面讲到,使用imresize()函数变换图像的尺寸,row和clum分别是尺寸变换后的行数和列数。“pho=zeros(row*clum M*N);”预定义变量pho,用来存储训练样本数据;同理,pic用来存储测试样本数据。对zeros函数有任何疑问,可以看前面的讲解,也可以到网络中寻求帮助。

在讲解下面的内容之前,需先说明一个问题。前面的流程图中,是先将ORL人脸库进行尺寸变换和形状变化,然后才将其分成训练样本和测试样本。在编写程序的时候,为了方便,我先将ORL库分成了训练样本和测试样本,然后在分别对其进行尺寸变换。即标记2和标记3之间导入的是训练样本;标记3和标记4之间时导入的测试样本。

下面先说如何导入训练样本,见标记2和标记3之间的代码。“t = 1;”t是计数变量,这里是对其赋初值,它的作用就是指定样本数据放在pho矩阵的位置。for循环有2层,外边的循环是对每个人进行遍历,里面的for循环是对某个人的样本图像进行遍历。简单的说,就是先固定一个人,然后将它的样本(用作训练的N个)都导入,接着进行第2人,…,直到第M个人。“t=t 1;”的位置在最内层,它的作用是每导入一幅图像,则t的值就增加1。前面提到t决定样本数据放置在pho矩阵中的位置,假如当前导入的图像放在pho的第t列,则下一幅图像就要放在t 1列,否则,数据就会覆盖掉原来的数据,understand???

同理,标记3和标记4之间的程序实现将测试样本导入到MATLAB中。注意:“j=N 1:10”,j变量啥意思来?为什么从N 1开始,而不是从1开始???思考一下。

前面提到ORL库中一个人有十幅样本图像,选前N个(1:N)个作为训练样本,剩余的(N 1:10)作为测试样本。明白没?

标记4到标记5间的代码功能是:获取标签。标签分为训练样本标签ltrain和测试样本标签ltest。前两行代码是预定义变量ltrain和ltest。下面的for循环是生成标签。其中,训练样本标签和训练样本是对应的;测试样本标签和测试样本对应的。这里一定要理解好,第一个人的标签是1,第2个人的标签是2,…,第40个人的标签是40。理解这里,还要理解ltrain和ltest中数据的排列方式,在ltrain中,每一行存储了一个样本图像的数据,而且还有一点特点,那就是同一个的N幅训练样本在ltrain中式连续排列的,例如,ltrain中前5行对应第1个人的样本图像,ltrain中6-10行对应第2个人的样本图像。同理ltest也是如此。添加标签的时候,也是按照这种连续性添加的,当然也不反对你手工一个个添加,只要你不嫌麻烦!

标记5下面的语句就是调用edpredict()函数,使用欧式距离判别法分类识别。其中,返回变量pre是返回的测试样本的预测标签,accuracy是测试样本预测的准确度。

至此,最简人脸识别算法讲完了,大家赶快学习吧!!!

猜您喜欢: