有了网站源码怎么建站,云南凡科建站哪家好,宁波网站制作费用,二维码制作网站有哪些前言 OpenCV从版本2.4开始#xff0c;加入了一个类FaceRecognizer#xff0c;使用它可以方便的地进行人脸识别(源代码#xff0c;在opencv_contrib库的opencv_contrib/modules/face/src下)。
目前支持三种算法#xff1a; 1. Eigen Faces特征脸#xff1a;EigenFaceReco…前言 OpenCV从版本2.4开始加入了一个类FaceRecognizer使用它可以方便的地进行人脸识别(源代码在opencv_contrib库的opencv_contrib/modules/face/src下)。
目前支持三种算法 1. Eigen Faces特征脸EigenFaceRecognizer 2. Fisher FacesFisherFaceRecognizer 3. Local Binary Pattern Histograms局部二值直方图LBPHFaceRecognizer
Eigen Faces特征脸 特征脸EigenFace相当于把人脸从像素空间变换到另一个空间在另一个空间中做相似性的计算。这么说其实图像识别的基本思想都是一样的首先选择一个合适的子空间将所有的图像变换到这个子空间上然后再在这个子空间上衡量相似性或者进行分类学习。变换到另一个空间同一个类别的图像会聚到一起不同类别的图像会距离比较远或者在原像素空间中不同类别的图像在分布上很难用个简单的线或者面把他们切分开然后如果变换到另一个空间就可以很好的把他们分开了。有时候线性分类器就可以很容易的把他们分开了。 EigenFace选择的空间变换方法是PCA也就是大名鼎鼎的主成分分析。它广泛的被用于预处理中以消去样本特征维度之间的相关性。EigenFace方法利用PCA得到人脸分布的主要成分具体实现是对训练集中所有人脸图像的协方差矩阵进行本征值分解得对对应的本征向量这些本征向量特征向量就是“特征脸”。每个特征向量或者特征脸相当于捕捉或者描述人脸之间的一种变化或者特性。这就意味着每个人脸都可以表示为这些特征脸的线性组合。经过PCA后空间就是以每一个特征脸或者特征向量为基在这个空间或者坐标轴下每个人脸就是一个点这个点的坐标就是这个人脸在每个特征基下的投影坐标。
下面就直接给出基于特征脸的人脸识别实现过程
步骤一获取包含M张人脸图像的集合S。在我们的例子里有25张人脸图像如下图所示哦。每张图像可以转换成一个N维的向量是的没错一个像素一个像素的排成一行就好了至于是横着还是竖着获取原图像的像素随你自己只要前后统一就可以然后把这M个向量放到一个集合S里如下式所示。
步骤二在获取到人脸向量集合S后计算得到平均图像Ψ 至于怎么计算平均图像公式在下面。就是把集合S里面的向量遍历一遍进行累加然后取平均值。得到的这个Ψ 其实还挺有意思的Ψ 其实也是一个N维向量如果再把它还原回图像的形式的话可以得到如下的“平均脸”。
步骤三计算每张图像和平均图像的差值Φ 就是用S集合里的每个元素减去步骤二中的平均值。
步骤四找到M个正交的单位向量un 这些单位向量其实是用来描述Φ 步骤三中的差值分布的。un 里面的第kk1,2,3…M)个向量uk 是通过下式计算的
当这个λk原文里取了个名字叫特征值取最小的值时uk 基本就确定了。补充一下刚才也说了这M个向量是相互正交而且是单位长度的所以啦uk 还要满足下式
上面的等式使得uk 为单位正交向量。计算上面的uk 其实就是计算如下协方差矩阵的特征向量
其中
对于一个NxN比如100x100维的图像来说上述直接计算其特征向量计算量实在是太大了协方差矩阵可以达到10000x10000所以有了如下的简单计算。
步骤四另解如果训练图像的数量小于图像的维数比如M
OpenCV源码
eigen_faces.cpp
void Eigenfaces::train(InputArrayOfArrays _src, InputArray _local_labels) void Eigenfaces::predict(InputArray _src, Ptr collector)
显然10个特征向量备注1个特征向量可以变形成一个特征脸这里特征向量和特征脸概念有些近似是不够的50个特征向量可以有效的编码出重要的人脸特征。在ATT数据库中当使用300个特征向量时可以获取一个比较好的和重构结果。有定理可以给出出重构需要选择多少特征脸才合适但它严重依赖于输入数据。
Fisher Faces
Fisherface所基于的LDALinear Discriminant Analysis线性判别分析理论和特征脸里用到的PCA有相似之处都是对原有数据进行整体降维映射到低维空间的方法LDA和PCA都是从数据整体入手而不同于LBP提取局部纹理特征。
数据集是二类情况
通常情况下待匹配人脸要和人脸库内的多张人脸匹配所以这是一个多分类的情况。出于简单考虑可以先介绍二类的情况然后拓展到多类。假设有二维平面上的两个点集xx是包含横纵坐标的二维向量它们的分布如下图1分别以蓝点和红点表示数据
原有数据是散布在平面上的二维数据如果想用一维的量比如到圆点的距离来合理的表示而且区分开这些数据该怎么办呢一种有效的方法是找到一个合适的向量w和数据相同维数将数据投影到w上会得到一个标量直观的理解就是投影点到坐标原点的距离根据投影点来表示和区分原有数据。以数学公式给出投影点到到原点的距离ywTx。图1给出了两种w方案w以从原点出发的直线来表示直线上的点是原数据的投影点。直观判断右侧的w更好些其上的投影点能够合理的区分原有的两个数据集。但是计算机不知道这些所以必须要有确定的方法来计算这个w。
首先计算每类数据的均值中心点
这里的i是数据的分类个数Ni代表某个分类下的数据点数比如u1代表红点的中心u2代表蓝点的中心。
数据点投影到w上的中心为
如何判断向量w最佳呢可以从两方面考虑1、不同的分类得到的投影点要尽量分开2、同一个分类投影后得到的点要尽量聚合。从这两方面考虑可以定义如下公式
J(w)代表不同分类投影中心的距离它的值越大越好。
上式称之为散列值scatter matrixs代表同一个分类投影后的散列值也就是投影点的聚合度它的值越小代表投影点越聚合。
结合两个公式第一个公式做分子另一个做分母
上式是w的函数值越大w降维性能越好所以下面的问题就是求解使上式取最大值的w。
把散列函数展开
可以发现除w和w^T外剩余部分可以定义为
其实这就是原数据的散列矩阵了对不对。对于固定的数据集来说它的散列矩阵也是确定的。
另外定义
Sw称为Within-class scatter matrix。
回到并用上面的两个定义做替换得到 展开J(w)的分子并定义SBSB称为Between-class scatter。
这样就得到了J(w)的最终表示
上式求极大值可以利用拉格朗日乘数法不过需要限定一下分母的值否则分子分母都变怎么确定最好的w呢。可以令利用拉格朗日乘数法得到
其中w是矩阵所以求导时可以把当做。这点我也不懂
上式两边同乘以可以得到
可以发现w其实就是矩阵的特征向量了对不对。
通过上式求解w还是有些困难的而且w会有多个解考虑下式
将其带入下式
其中λw是以w为变量的数值因为(u1-u2)^T和w是相同维数的前者是行向量后者列向量。继续带入以前的公式
由于w扩大缩小任何倍不影响结果所以可以约去两遍的未知常数λ和λw存疑
到这里w就能够比较简单的求解了。
2、数据集是多类的情况
这部分是本博文的核心。假设有C个人的人脸图像每个人可以有多张图像所以按人来分可以将图像分为C类这节就是要解决如何判别这C个类的问题。判别之前需要先处理下图像将每张图像按照逐行逐列的形式获取像素组成一个向量和第一节类似设该向量为x设向量维数为n设x为列向量n行1列。
和第一节简单的二维数据分类不同这里的n有可能成千上万比如100x100的图像得到的向量为10000维所以第一节里将x投影到一个向量的方法可能不适用了比如下图 图2
平面内找不到一个合适的向量能够将所有的数据投影到这个向量而且不同类间合理的分开。所以我们需要增加投影向量w的个数当然每个向量维数和数据是相同的不然怎么投影呢设w为
w1、w2等是n维的列向量所以w是个n行k列的矩阵这里的k其实可以按照需要随意选取只要能合理表征原数据就好。x在w上的投影可以表示为
所以这里的y是k维的列向量。
像上一节一样我们将从投影后的类间散列度和类内散列度来考虑最优的w考虑图2中二维数据分为三个类别的情况。与第一节类似μi依然代表类别i的中心而Sw定义如下
其中
代表类别i的类内散列度它是一个nxn的矩阵。
所有x的中心μ定义为
类间散列度定义和上一节有较大不同
代表的是每个类别到μ距离的加和注意Ni代表类别i内x的个数也就是某个人的人脸图像个数。
上面的讨论都是投影之间的各种数据而J(w)的计算实际是依靠投影之后数据分布的所以有 分别代表投影后的类别i的中心所有数据的中心类内散列矩阵类间散列矩阵。与上节类似J(w)可以定义为 回想我们上节的公式J(w)分子是两类中心距分母是每个类自己的散列度。现在投影方向是多维了好几条直线分子需要做一些改变我们不是求两两样本中心距之和这个对描述类别间的分散程度没有用而是求每类中心相对于全样本中心的散列度之和。得到
最后化为
还是求解矩阵的特征向量然后根据需求取前k个特征值最大的特征向量。
另外还需注意
由于SB中的μi-μ秩为1所以SB的至多为C矩阵的秩小于等于各个相加矩阵的和。又因为知道了前C-1个μi后最后一个μc可以用前面的μi来线性表示因此SB的秩至多为C-1所以矩阵的特征向量个数至多为C-1。因为C是数据集的类别所以假设有N个人的照片那么至多可以取到N-1个特征向量来表征原数据。存疑
如果你读过前面的一篇文章PCA理论分析会知道PCA里求得的特征向量都是正交的但是这里的并不是对称的所以求得的K个特征向量不一定正交这是LDA和PCA最大的不同。
如前所述如果在一个人脸集合上求得k个特征向量还原为人脸图像的话就像下面这样 得到了k个特征向量如何匹配某人脸和数据库内人脸是否相似呢方法是将这个人脸在k个特征向量上做投影得到k维的列向量或者行向量然后和已有的投影求得欧式距离根据阈值来判断是否匹配。具体的方法在人脸识别经典算法一特征脸方法Eigenface里有可前往查看。需要说明的是LDA和PCA两种方法对光照都是比较敏感的如果你用光照均匀的图像作为依据去判别非均匀的那基本就惨了。
OpenCV源码
fisher_faces.cpp
void Fisherfaces::train(InputArrayOfArrays _src, InputArray _local_labels) void Fisherfaces::predict(InputArray _src, Ptr collector)
Local Binary Pattern Histograms Eigenfaces和Fisherfaces使用整体方法来进行人脸识别。你把你的数据当作图像空间的高维向量。我们都知道高维数据是糟糕的所以一个低维子空间被确定对于信息保存可能很好。Eigenfaces是最大化总的散度这样可能导致当方差由外部条件产生时最大方差的主成分不适合用来分类。所以为使用一些鉴别分析我们使用了LDA方法来优化。Fisherfaces方法可以很好的运作至少在我们假设的模型的有限情况下。 现实生活是不完美的。你无法保证在你的图像中光照条件是完美的或者说1个人的10张照片。所以如果每人仅仅只有一张照片呢我们的子空间的协方差估计方法可能完全错误所以识别也可能错误。是否记得Eigenfaces在ATT数据库上达到了96%的识别率对于这样有效的估计我们需要多少张训练图像呢下图是Eigenfaces和Fisherfaces方法在ATT数据库上的首选识别率这是一个简单的数据库 因此若你想得到好的识别率你大约需要每个人有8(7~9)张图像而Fisherfaces在这里并没有好的帮助。以上的实验是10个图像的交叉验证结果使用了facerec框架 https://github.com/bytefish/facerec。 LBPHLocal Binary Patterns Histograms局部二值模式是提取局部特征作为判别依据的。LBPH方法显著的优点是对光照不敏感但是依然没有解决姿态和表情的问题。不过相比于特征脸方法LBPH的识别率已经有了很大的提升。有些人脸库的识别率已经达到了98%。
LBP特征提取 最初的LBPH是定义在像素3x3邻域内的以邻域中心像素为阈值将相邻的8个像素的灰度值与其进行比较若周围像素值大于中心像素值则该像素点的位置被标记为1否则为0。这样3x3邻域内的8个点经比较可产生8位二进制数通常转换为十进制数即LBPH码共256种即得到该邻域中心像素点的LBPH值并用这个值来反映该区域的纹理信息。如下图所示
用比较正式的公式来定义的话
其中代表3x3邻域的中心元素它的像素值为icip代表邻域内其他像素的值。s(x)是符号函数定义如下
LBP的改进版本
1圆形LBP算子 基本的LBPH算子的最大缺陷在于它只覆盖了一个固定半径范围内的小区域这显然不能满足不同尺寸和频率纹理的需要。为了适应不同尺度的纹理特征并达到灰度和旋转不变性的要求Ojala等对 LBP 算子进行了改进将 3×3邻域扩展到任意邻域并用圆形邻域代替了正方形邻域改进后的 LBP 算子允许在半径为 R 的圆形邻域内有任意多个像素点。从而得到了诸如半径为R的圆形区域内含有P个采样点的LBP算子。比如下图定了一个5x5的邻域
上图内有八个黑色的采样点每个采样点的值可以通过下式计算
其中为邻域中心点为某个采样点。通过上式可以计算任意个采样点的坐标但是计算得到的坐标未必完全是整数所以可以通过双线性插值来得到该采样点的像素值
2LBP等价模式 一个LBP算子可以产生不同的二进制模式对于半径为R的圆形区域内含有P个采样点的LBP算子将会产生2^P种模式。很显然随着邻域集内采样点数的增加二进制模式的种类是急剧增加的。例如5×5邻域内20个采样点有2201,048,576种二进制模式。如此多的二值模式无论对于纹理的提取还是对于纹理的识别、分类及信息的存取都是不利的。同时过多的模式种类对于纹理的表达是不利的。例如将LBP算子用于纹理分类或人脸识别时常采用LBP模式的统计直方图来表达图像的信息而较多的模式种类将使得数据量过大且直方图过于稀疏。因此需要对原始的LBP模式进行降维使得数据量减少的情况下能最好的代表图像的信息。 为了解决二进制模式过多的问题提高统计性Ojala提出了采用一种“等价模式”Uniform Pattern来对LBP算子的模式种类进行降维。Ojala等认为在实际图像中绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变。因此Ojala将“等价模式”定义为当某个LBP所对应的循环二进制数从0到1或从1到0最多有两次跳变时该LBP所对应的二进制就称为一个等价模式类。如000000000次跳变00000111只含一次从0到1的跳变10001111先由1跳到0再由0跳到1共两次跳变都是等价模式类。除等价模式类以外的模式都归为另一类称为混合模式类例如10010111共四次跳变。比如下图给出了几种等价模式的示意图。 通过这样的改进二进制模式的种类大大减少而不会丢失任何信息。模式数量由原来的2P种减少为 P ( P-1)2种其中P表示邻域集内的采样点数。对于3×3邻域内8个采样点来说二进制模式由原始的256种减少为58种这使得特征向量的维数更少并且可以减少高频噪声带来的影响。 通过上述方法每个像素都会根据邻域信息得到一个LBP值如果以图像的形式显示出来可以得到下图明显LBP对光照有较强的鲁棒性。
LBP特征匹配
如果将以上得到的LBP值直接用于人脸识别其实和不提取LBP特征没什么区别会造成计算量准确率等一系列问题。文献[1]中将一副人脸图像分为7x7的子区域如下图并在子区域内根据LBP值统计其直方图以直方图作为其判别特征。这样做的好处是在一定范围内避免图像没完全对准的情况同时也对LBP特征做了降维处理。
对于得到的直方图特征有多种方法可以判别其相似性假设已知人脸直方图为Mi待匹配人脸直方图为Si那么可以通过:
(1)直方图交叉核方法
该方法的介绍在博文Histogram intersection(直方图交叉核,Pyramid Match Kernel)
(2)卡方统计方法
该方法的介绍在博文卡方检验(Chi square statistic)
OpenCV源码
lbph_faces.cpp
void LBPH::train(InputArrayOfArrays _in_src, InputArray _in_labels, bool preserveData) void LBPH::predict(InputArray _src, Ptr collector)
参考资料
http://blog.csdn.net/smartempire/article/details/21406005http://blog.csdn.net/zouxy09/article/details/45276053/http://blog.csdn.net/real_myth/article/details/52771136http://blog.csdn.net/smartempire/article/details/23377385http://blog.csdn.net/smartempire/article/details/23249517