【计算机视觉】OpenCV人脸识别facerec源码分析2

人脸识别

从OpenCV2.4开始,加入了新的类FaceRecognizer,我们可以使用它便捷地进行人脸识别实验。其源代码可以在OpenCV中的opencv\modules\contrib\doc\facerec\src下找到。 目前支持的算法有:

Eigenfaces特征脸createEigenFaceRecognizer() Fisherfaces createFisherFaceRecognizer() Local Binary Patterns Histograms局部二值直方图 createLBPHFaceRecognizer()

自动人脸识别就是如何从一幅图像中提取有意义的特征,把它们放入一种有用的表示方式,然后对他们进行一些分类。 特征脸方法描述了一个全面的方法来识别人脸:面部图像是一个点,这个点是从高维图像空间找到它在低维空间的表示,这样分类变得很简单。低维子空间低维是使用主元分析(Principal Component Analysis,PCA)找到的,它可以找拥有最大方差的那个轴。虽然这样的转换是从最佳重建角度考虑的,但是他没有把标签问题考虑进去。想象一个情况,如果变化是基于外部来源,比如光照。轴的最大方差不一定包含任何有鉴别性的信息,因此此时的分类是不可能的。因此,一个使用线性鉴别(Linear Discriminant Analysis,LDA)的特定类投影方法被提出来解决人脸识别问题。其中一个基本的想法就是,使类内方差最小的同时,使类外方差最大。 近年来,各种局部特征提取方法出现。为了避免输入的图像的高维数据,仅仅使用的局部特征描述图像的方法被提出,,提取的特征(很有希望的)对于局部遮挡、光照变化、小样本等情况更强健。有关局部特征提取的方法有盖伯小波(Gabor Waelets),离散傅立叶变换(Discrete Cosinus Transform,DCT),局部二值模式(Local Binary Patterns,LBP)。使用什么方法来提取时域空间的局部特征依旧是一个开放性的研究问题,因为空间信息是潜在有用的信息。

局部二值模式直方图Local Binary Patterns Histograms

由于Eigenfaces和Fisherfaces两种方法当引入新的人脸数据时需要重新进行训练,所以这里我着重介绍LBP特征的有关内容。

Eigenfaces和Fisherfaces使用整体方法来进行人脸识别[gm:直接使用所有的像素]。你把你的数据当作图像空间的高维向量。我们都知道高维数据是糟糕的,所以一个低维子空间被确定,对于信息保存可能很好。Eigenfaces是最大化总的散度,这样可能导致,当方差由外部条件产生时,最大方差的主成分不适合用来分类。所以为使用一些鉴别分析,我们使用了LDA方法来优化。Fisherfaces方法可以很好的运作,至少在我们假设的模型的有限情况下。 现实生活是不完美的。你无法保证在你的图像中光照条件是完美的,或者说1个人的10张照片。所以,如果每人仅仅只有一张照片呢?我们的子空间的协方差估计方法可能完全错误,所以识别也可能错误。 一些研究专注于图像局部特征的提取。主意是我们不把整个图像看成一个高维向量,仅仅用局部特征来描述一个物体。通过这种方式提取特征,你将获得一个低维隐式。一个好主意!但是你很快发现这种图像表示方法不仅仅遭受光照变化。你想想图像中的尺度变化、形变、旋转—我们的局部表示方式起码对这些情况比较稳健。正如SIFT,LBP方法在2D纹理分析中举足轻重。LBP的基本思想是对图像的像素和它局部周围像素进行对比后的结果进行求和。把这个像素作为中心,对相邻像素进行阈值比较。如果中心像素的亮度大于等于他的相邻像素,把他标记为1,否则标记为0。你会用二进制数字来表示每个像素,比如11001111。因此,由于周围相邻8个像素,你最终可能获取2^8个可能组合,被称为局部二值模式,有时被称为LBP码。第一个在文献中描述的LBP算子实际使用的是3*3的邻域。

算法描述

一个更加正式的LBP操作可以被定义为: 其中(xc,yc)是中心像素,亮度是ic;而in是相邻像素的亮度。s是一个符号函数。 这种描述方法使得你可以很好的捕捉到图像中的细节。实际上,研究者们可以用它在纹理分类上得到最先进的水平。正如刚才描述的方法被提出后,固定的近邻区域对于尺度变化的编码失效。所以,使用一个变量的扩展方法是使用可变半径的圆对近邻像素进行编码,这样可以捕捉到如下的近邻:

对一个给定的点(xc,yc),他的近邻点(xp,yp),p∈P可以由如下计算: 其中,R是圆的半径,而P是样本点的个数。

这个操作是对原始LBP算子的扩展,所以有时被称为扩展LBP(又称为圆形LBP)。如果一个在圆上的点不在图像坐标上,我们使用他的内插点。计算机科学有一堆聪明的插值方法,而OpenCV使用双线性插值。

LBP算子,对于灰度的单调变化很稳健。我们可以看到手工改变后的图像的LBP图像。

那么剩下来的就是如何合并空间信息用于人脸识别模型。对LBP图像成m个块,每个块提取直方图。通过连接局部特直方图(而不是合并)然后就能得到空间增强的特征向量。这些直方图被称为局部二值模式直方图。

源码分析LBPH类声明class LBPH : public FaceRecognizer{private:int _grid_x;int _grid_y;int _radius;int _neighbors;double _threshold;vector<Mat> _histograms;Mat _labels;train(InputArrayOfArrays src, InputArray labels, bool preserveData);public:using FaceRecognizer::save;using FaceRecognizer::load;LBPH(int radius_=1, int neighbors_=8,int gridx=8, int gridy=8,double threshold = DBL_MAX) :_grid_x(gridx),_grid_y(gridy),_radius(radius_),_neighbors(neighbors_),_threshold(threshold) {}LBPH(InputArrayOfArrays src,InputArray labels,int radius_=1, int neighbors_=8,int gridx=8, int gridy=8,double threshold = DBL_MAX) :_grid_x(gridx),_grid_y(gridy),_radius(radius_),_neighbors(neighbors_),_threshold(threshold) {train(src, labels);}~LBPH() { }train(InputArrayOfArrays src, InputArray labels);update(InputArrayOfArrays src, InputArray labels);// Predicts the label of a query image in src.int predict(InputArray src) const;// Predicts the label and confidence for a given sample.void predict(InputArray _src, int &label, double &dist) const;// See FaceRecognizer::load.void load(const FileStorage& fs);// See FaceRecognizer::save.void save(FileStorage& fs) const;// Getter functions.int neighbors() const { return _neighbors; }int radius() const { return _radius; }int grid_x() const { return _grid_x; }int grid_y() const { return _grid_y; }AlgorithmInfo* info() const;};构建LBPH实例//声明Ptr<FaceRecognizer> createLBPHFaceRecognizer(int radius=1, int neighbors=8, int grid_x=8, int grid_y=8, double threshold=DBL_MAX);//定义Ptr<FaceRecognizer> createLBPHFaceRecognizer(int radius, int neighbors,int grid_x, int grid_y, double threshold){return new LBPH(radius, neighbors, grid_x, grid_y, threshold);}诚实是人生绝妙的法宝。虽然对人诚实,

【计算机视觉】OpenCV人脸识别facerec源码分析2

相关文章:

你感兴趣的文章:

标签云: