人脸识别经过近 40 年的发展,取得了很大的发展,涌现出了大量的识别算法。这些算法的涉及面非常广泛,包括模式识别、图像处理、计算机视觉、人工智能、统计学习、神经网络、小波分析、子空间理论和流形学习等众多学科。所以很难用一个统一的标准对这些算法进行分类。根据输入数据形式的不同可分为基于静态图像的人脸识别和基于视频图像的人脸识别。因为基于静态图像的人脸识别算法同样适用于基于视频图像的人脸识别,所以只有那些使用了时间信息的识别算法才属于基于视频图像的人脸识别算法。接下来分别介绍两类人脸识别算法中的一些重要的算法。

特征脸

因为需要,花了一点时间写了下经典的基于特征脸(EigenFace)的人脸识别方法的Matlab代码。这里仅把该代码分享出来。其实,在较新版本的OpenCV中已经提供了FaceRecognizer这一个类,里面不仅包含了特征脸EigenFace,还有FisherFace和LBPHFace这三种人脸识别方法,有兴趣的可以参考OpenCV的API手册,里面都有很详细的使用例程了。

(1)思想

特征脸EigenFace从思想上其实挺简单。Eigenface 就是将人脸图像进行编码,映射到低维子空间中,在低维空间计算两幅人脸图像的距离,以此来进行人脸识别。就相当于把人脸从像素空间变换到另一个空间,在另一个空间中做相似性的计算。映射到低维子空间的方法采用主成分分析PCA。

拓展:图像识别的本质思想:

其实图像识别的基本思想都是一样的,首先选择一个合适的子空间,将所有的图像变换到这个子空间上,然后再在这个子空间上衡量相似性或者进行分类学习。那为什么要变换到另一个空间呢?当然是为了更好的做识别或者分类了。那为什么变换到一个空间就好识别或者分类了呢?因为变换到另一个空间,同一个类别的图像会聚到一起,不同类别的图像会距离比较远,或者在原像素空间中不同类别的图像在分布上很难用个简单的线或者面把他们切分开,然后如果变换到另一个空间,就可以很好的把他们分开了。有时候,线性(分类器)就可以很容易的把他们分开了。那既然人类看起来同类的图像本来就是相似的,不同类的图像就不太相似,那为什么在原始的像素空间他们同类不会很近,不同类不会很远,或者他们为什么不好分开呢?因为图像各种因素的影响,包括光照、视角、背景和形状等等不同,会造成同一个目标的图像都存在很大的视觉信息上的不同。如下图所示。

世界上没有存在任何两片完全相同的叶子,虽然他们都是叶子。万千世界,同一类事物都存在共性,也存在个性,这就是这个世界多彩的原因。那怎么办呢?很自然,只要在我们想要的粒度上把同一类目标的共性找出来就好了,而且这个共性最好和我们要区分的类是不一样的。什么叫我们想要的粒度?我理解和我们的任务相关的。例如我们要区分人和车,那人的共性就是有脸、有手、有脚等等。但如果我们要区分亚洲人和非洲人,那么亚洲人的共性就是黄色皮肤等等。回到刚才的问题,重头戏来了,要变换到什么空间,才具备上述这种良好类内相似、类间区分的效果?到这,我就只能say sorry了。计算机视觉领域发展了几十年,就为了这一个问题倾注了无数研究者的智慧与心血。当然了,也诞生和孕育了很多经典和有效的解答。(个人理解,上述说的实际上就是特征提取)。从一开始的颜色特征(颜色直方图)、纹理特征(Harr、LBP、HOG、SIFT等)、形状特征等到视觉表达Bag of Words,再到特征学习Deep Learning,技术的发展总能带给人希望,曙光也越来越清晰,但路还很远,是不?

(2)理论基础--PCA主成分分析

扯太多了,严重离题了。上面说到,特征脸EigenFace的思想是把人脸从像素空间变换到另一个空间,在另一个空间中做相似性的计算。EigenFace选择的空间变换方法是PCA,也就是大名鼎鼎的主成分分析。它广泛的被用于预处理中以消去样本特征维度之间的相关性。当然了,这里不是说这个。EigenFace方法利用PCA得到人脸分布的主要成分,具体实现是对训练集中所有人脸图像的协方差矩阵进行特征值分解,得到对应的特征向量,这些特征向量(特征向量)就是“特征脸”。每个特征向量或者特征脸相当于捕捉或者描述人脸之间的一种变化或者特性。这就意味着每个人脸都可以表示为这些特征脸的线性组合。实际上,空间变换就等同于“搞基”,原始像素空间的基就是单位“基”,经过PCA后空间就是以每一个特征脸或者特征向量为基,在这个空间(或者坐标轴)下,每个人脸就是一个点,这个点的坐标就是这个人脸在每个特征基下的投影坐标。哦噢,说得有点绕。

(3)实现过程:

下面就直接给出基于特征脸的人脸识别实现过程:

1)将训练集的每一个人脸图像都拉长一列,将他们组合在一起形成一个大矩阵A。假设每个人脸图像是MxM大小,那么拉成一列后每个人脸样本的维度就是d=MxM大小了。假设有N个人脸图像,那么样本矩阵A的维度就是dxN了。

2)将所有的N个人脸在对应维度上加起来,然后求个平均,就得到了一个“平均脸”。你把这个脸显示出来的话,还挺帅的哦。

3)将N个图像都减去那个平均脸图像,得到差值图像的数据矩阵Φ。

4)计算协方差矩阵C=ΦΦT。再对其进行特征值分解。就可以得到想要的特征向量(特征脸)了。

5)将训练集图像和测试集的图像都投影到这些特征向量上了,再对测试集的每个图像找到训练集中的最近邻或者k近邻啥的,进行分类即可。

算法说明白了都是不明白的,所以还是得去看具体实现。因此,可以对照下面的代码来弄清楚这些步骤。

另外,对于步骤4),涉及到求特征值分解。如果人脸的特征维度d很大,例如256x256的人脸图像,d就是65536了。那么协方差矩阵C的维度就是dxd=65536x65536。对这个大矩阵求解特征值分解是很费力的。那怎么办呢?如果人脸的样本不多,也就是N不大的话,我们可以通过求解C’=ΦTΦ矩阵来获得同样的特征向量。可以看到这个C’=ΦTΦ只有NxN的大小哦。如果N远远小于d的话,那么这个力气就省得很值了。那为什么求解C’=ΦTΦ矩阵的特征向量可以获得C=ΦΦT的特征向量?万众瞩目时刻,数学以完美舞姿登上舞台。证明如下:

其中,ei是C’=ΦTΦ的第i个特征向量,vi是C=ΦΦT的第i个特征向量,由证明可以看到,vi=Φei。所以通过求解C’=ΦTΦ的特征值分解得到ei,再左乘Φ就得到C=ΦΦT的特征向量vi了。也就是我们想要的特征脸。

二、Matlab实现

下面的代码主要是在著名的人脸识别数据库YaleB中进行实现。用的是裁切后的人脸数据库,可以点击CroppedYale下载。共有38个人的人脸,人脸是在不同的光照下采集的,每个人脸图像是32x32个像素。实验在每一个的人脸图像中随机取5个作为训练图像,剩下的作为测试图像。当然了,实际过程中这个过程需要重复多次,然后得到多次准确率的均值和方差才有参考意义,但下面的demo就不做这个处理了。计算相似性用的是欧氏距离,但编程实现的时候为了加速,用的是简化版,至于如何简化的,考验你的时候到了。

[cpp] view plaincopy
  1. % Face recognition using eigenfaces
  2. close all, clear, clc;
  3. %% 20 random splits
  4. num_trainImg = 5;
  5. showEigenfaces = true;
  6. %% load data
  7. disp('loading data...');
  8. dataDir = './CroppedYale';
  9. datafile = 'Yale.mat';
  10. if ~exist(datafile, 'file')
  11. readYaleDataset(dataDir, datafile);
  12. end
  13. load(datafile);
  14. %% Five images per class are randomly chosen as the training
  15. %% dataset and remaining images are used as the test dataset
  16. disp('get training and testing data...');
  17. num_class = size(unique(labels), 2);
  18. trainIdx = [];
  19. testIdx = [];
  20. for i=1:num_class
  21. label = find(labels == i);
  22. indice = randperm(numel(label));
  23. trainIdx = [trainIdx label(indice(1:num_trainImg))];
  24. testIdx = [testIdx label(indice(num_trainImg+1:end))];
  25. end
  26. %% get train and test data
  27. train_x = double(data(:, trainIdx));
  28. train_y = labels(trainIdx);
  29. test_x = double(data(:, testIdx));
  30. test_y = labels(testIdx);
  31. %% computing eigenfaces using PCA
  32. disp('computing eigenfaces...');
  33. tic;
  34. [num_dim, num_imgs] = size(train_x);   %% A: #dim x #images
  35. avg_face = mean(train_x, 2);             %% computing the average face
  36. X = bsxfun(@minus, train_x, avg_face); %% computing the difference images
  37. %% PCA
  38. if num_dim <= num_imgs
  39. C = X * X';
  40. [V, D] = eig(C);
  41. else
  42. C = X' * X;
  43. [U, D] = eig(C);
  44. V = X * U;
  45. end
  46. eigenfaces = V;
  47. eigenfaces = eigenfaces ./ (ones(size(eigenfaces,1),1) * sqrt(sum(eigenfaces.*eigenfaces)));
  48. toc;
  49. %% visualize the average face
  50. P = sqrt(numel(avg_face));
  51. Q = numel(avg_face) / P;
  52. imagesc(reshape(avg_face, P, Q)); title('Mean face');
  53. colormap('gray');
  54. %% visualize some eigenfaces
  55. figure;
  56. num_eigenfaces_show = 9;
  57. for i = 1:num_eigenfaces_show
  58. subplot(3, 3, i)
  59. imagesc(reshape(eigenfaces(:, end-i+1), P, Q));
  60. title(['Eigenfaces ' num2str(i)]);
  61. end
  62. colormap('gray');
  63. %% transform all training images to eigen space (each column for each image)
  64. disp('transform data to eigen space...');
  65. X = bsxfun(@minus, train_x, avg_face);
  66. T = eigenfaces' * X;
  67. %% transform the test image to eigen space
  68. X_t = bsxfun(@minus, test_x, avg_face);
  69. T_t = eigenfaces' * X_t;
  70. %% find the best match using Euclidean distance
  71. disp('find the best match...');
  72. AB = -2 * T_t' * T;       % N x M
  73. BB = sum(T .* T);         % 1 x M
  74. distance = bsxfun(@plus, AB, BB);        % N x M
  75. [score, index] = min(distance, [], 2);   % N x 1
  76. %% compute accuracy
  77. matchCount = 0;
  78. for i=1:numel(index)
  79. predict = train_y(index(i));
  80. if predict == test_y(i)
  81. matchCount = matchCount + 1;
  82. end
  83. end
  84. fprintf('**************************************\n');
  85. fprintf('accuracy: %0.3f%% \n', 100 * matchCount / numel(index));
  86. fprintf('**************************************\n');

下面是将CroppedYale的图像读入matlab的代码。

[cpp] view plaincopy
  1. function readYaleDataset(dataDir, saveName)
  2. dirs = dir(dataDir);
  3. data = [];
  4. labels = [];
  5. for i = 3:numel(dirs)
  6. imgDir = dirs(i).name;
  7. imgDir = fullfile(dataDir, imgDir);
  8. imgList = dir(fullfile(imgDir, '*.pgm'));
  9. for j = 1:numel(imgList)
  10. imgName = imgList(j).name;
  11. if strcmp('Ambient.pgm',  imgName(end-10:end))
  12. continue;
  13. end
  14. im = imread(fullfile(imgDir, imgName));
  15. if size(im, 3) ==3
  16. im = rgb2gray(im);
  17. end
  18. im = imresize(im, [32 32]);
  19. im = reshape(im, 32*32, 1);
  20. data = [data im];
  21. end
  22. labels = [labels ones(1, numel(imgList)-1) * (i-2)];
  23. end
  24. save(saveName, 'data', 'labels');
  25. end

三、实验结果

首先来个帅帅的平均脸:

然后来9个帅帅的特征脸:

在本实验中,实验结果是30.126%左右。如果加上了某些预处理,这个结果就可以跑到62%左右。只是这个预处理我有点解析不通,所以就没放在demo上了。

自动人脸识别基本原理 --基于静态图像的识别算法(一)特征脸相关推荐

  1. 人脸识别算法之特征脸方法(Eigenface)

    一.人脸识别算法之特征脸方法(Eigenface) 1.原理介绍及数据收集 特征脸方法主要是基于PCA降维实现. 详细介绍和主要思想可以参考 https://www.cnblogs.com/littl ...

  2. 【条形码识别】基于matlab条形码识别【含Matlab源码 403期】

    一.获取代码方式 获取代码方式1: 完整代码已上传我的资源: [条形码识别]基于matlab条形码识别[含Matlab源码 403期] (https://download.csdn.net/downl ...

  3. 生成常用验证码识别,基于PaddleOCR训练识别

    ★★★ 本文源自AlStudio社区精品项目,[点击此处]查看更多精品内容 >>> 生成常用验证码识别,基于PaddleOCR训练识别 零.背景 在一些传统网站或者App中登录需要验 ...

  4. 经典人脸识别算法(特征脸,FISHERFACE,LBP)

    首先,只是基于对算法的主要是想的介绍和理解,对于涉及到的PCA以及直方图比较提到的方法等等可以自己再去深入研究. 其次,只是用作笔记记录. 参考了CSDN博客:https://blog.csdn.ne ...

  5. 人脸识别经典算法:特征脸方法(Eigenface)

    https://www.toutiao.com/a6698955075127083527/ 这个算法需要数学知识特别好的人才会看得懂吧! 步骤一:获取包含M张人脸图像的集合S.在我们的例子里有25张人 ...

  6. mser python车牌识别_基于MSER与SVM算法的车牌定位识别方法

    基于 MSER 与 SVM 算法的车牌定位识别方法 胡成伟 ; 袁明辉 [期刊名称] <软件> [年 ( 卷 ), 期] 2020(041)002 [摘要] 针对实际车牌识别系统中车牌位置 ...

  7. 基于matlab车牌识别程序,基于MATLAB车牌识别系统设计

    基于MATLAB车牌识别系统设计(任务书,开题报告,毕业论文11200字) 摘要 社会的不断发展带动着经济也不断的增长,从而也提高了人们的生活水平.汽车的需求量也日渐增加,现代化交通管理的出现,解决了 ...

  8. python人脸识别特征脸法_人脸识别经典算法:特征脸方法(Eigenface)

    特征脸方法基本是将人脸识别推向真正可用的第一种方法,了解一下还是很有必要的.特征脸用到的理论基础PCA在之前的文章中已经讲过了.直接上特征脸方法的步骤: 步骤一:获取包含M张人脸图像的集合S.在我们的 ...

  9. python人脸识别特征脸法_人脸识别经典算法一 特征脸方法(Eigenface)

    这篇文章是撸主要介绍人脸识别经典方法的第一篇,后续会有其他方法更新.特征脸方法基本是将人脸识别推向真正可用的第一种方法,了解一下还是很有必要的.特征脸用到的理论基础PCA在另一篇博客里:特征脸(Eig ...

最新文章

  1. 自动输入runas密码的方法
  2. leetcode算法题--Minimum Depth of Binary Tree
  3. linux目录结果说明,Linux目录结构及文件说明
  4. 360 再次开源管理平台 Wayne:基于企业级 Kubernetes 集群
  5. “this”不能在常量表达式中使用报错的解决方法
  6. 京东购物车双11实战
  7. SpringCloud Ribbon的分析
  8. json decode php 二维,在json_decode /多维数组之后访问JSON数组
  9. winform仿QQ聊天气泡(c#代码+GDI绘图)
  10. 【必备知识】摄像机标定基础理论
  11. 上传大文件至阿里云服务器解决方案(理论上无限大文件,支持批量处理)
  12. 完全停止Oracle中正在运行的JOB
  13. Excel为图表指定横向坐标数据
  14. c语言syslog日志记录
  15. 【Codeforces 1392F】Omkar and Landslide | 思维、结论
  16. 《Android 应用案例开发大全(第二版)》——1.5节第一个Android程序——Hello Android...
  17. 神技—终端显示Linux系统信息
  18. 使用c3p0数据库连接池连接时出现错误:java.lang.NoClassDefFoundError: com/mchange/v2/ser/Indirector
  19. DRE FTR SCM
  20. 一篇文章让你了解ADAS-HIL测试方案

热门文章

  1. 佳能Canon PIXMA MX538 打印机驱动
  2. C语言小型项目答辩,C语言项目答辩(ATM).pdf
  3. gitLab迁移项目过程记录
  4. 楚留香手游无法获取服务器信息,楚留香手游无法登陆怎么解决 无法登陆原因及解决方案一览_3DM手游...
  5. SQL Server访问远程数据库,并把其中的一个数据库复制到本地
  6. k8s健康检查探针配置
  7. 使用c语言实现一个简单的易语言
  8. ApiPost 真香真强大,是时候丢掉 Postman、Swagger 了
  9. 【Java小游戏】小动物连连看由易到难
  10. python语言规定标识符_Python语法规则