人脸识别-再识

来源:互联网 发布:传奇app源码 编辑:程序博客网 时间:2024/06/09 16:00

这里是识别,而不是人脸检测,检测部分前面我已经说过,是一种基于adaboost的级联决策算法,能够高精度的检测出人脸所在的区域。
前面我们转载了几篇人脸识别网上的资源,大家可能知道如何在OpenCV中使用人脸识别这个库,但是对于其中算法的深层含义还远没有彻底弄懂。所以我通过一篇论文的阅读《基于LBP和Fisher face的人脸算法研究》讲解现在人脸识别算法的具体含义。

    CV_EXPORTS_W Ptr<FaceRecognizer> **createEigenFaceRecognizer**(int num_components = 0, double threshold = DBL_MAX);    CV_EXPORTS_W Ptr<FaceRecognizer> **createFisherFaceRecognizer**(int num_components = 0, double threshold = DBL_MAX);    CV_EXPORTS_W Ptr<FaceRecognizer> **createLBPHFaceRecognizer**(int radius=1, int neighbors=8,                                                            int grid_x=8, int grid_y=8, double threshold = DBL_MAX);

OpenCV中比较好认识的就是 基于LBP算子的人脸识别算法。我们首先讲解这个算子的过程。
还是先看下OpenCV下的结果,我们使用的是ORL人脸数据库,每个人有10张,包含了40个人。

vector<Mat> images;      vector<int> labels;      // images for first person      images.push_back(imread("ORL\\s1\\1.bmp", CV_LOAD_IMAGE_GRAYSCALE));      labels.push_back(1);      images.push_back(imread("ORL\\s1\\2.bmp", CV_LOAD_IMAGE_GRAYSCALE));       labels.push_back(1);      images.push_back(imread("ORL\\s1\\3.bmp", CV_LOAD_IMAGE_GRAYSCALE));      labels.push_back(1);      images.push_back(imread("ORL\\s1\\4.bmp", CV_LOAD_IMAGE_GRAYSCALE));       labels.push_back(1);      images.push_back(imread("ORL\\s1\\5.bmp", CV_LOAD_IMAGE_GRAYSCALE));      labels.push_back(1);      images.push_back(imread("ORL\\s1\\6.bmp", CV_LOAD_IMAGE_GRAYSCALE));       labels.push_back(1);      images.push_back(imread("ORL\\s1\\7.bmp", CV_LOAD_IMAGE_GRAYSCALE));      labels.push_back(1);      images.push_back(imread("ORL\\s1\\8.bmp", CV_LOAD_IMAGE_GRAYSCALE));       labels.push_back(1);  

这是第一个人的信息,大家可以按照这个规律进行人脸的扩展。

    Ptr<FaceRecognizer> model = createEigenFaceRecognizer();    model->train(images, labels);      Mat img = imread("ORL\\s1\\8.bmp", CV_LOAD_IMAGE_GRAYSCALE);      double confidence;    int predicted;    model->predict(img,predicted,confidence);  

confidence是预测的置信度。可以在构造createEigenFaceRecognizer的时候设置阈值参数,如果超过了这个参数,那么得到的结果就是-1,表示没有合适的分类。

基于LBP的人脸识别
LBP是local binary pattern的简写,局部二值模式。
原始LBP算子最初是在3*3的矩形窗口上定义的,以矩形窗口心中点的灰度值作为阈值,将邻域内各像素点像素值与阈值进行比较,将比较结果进行二值化处理,然后各邻域像素点根据位置的不同进行加权求和和到该窗口中心的LBP值(为了满足旋转性,将该二值串进行循环移动,然后使用权值加权–如下)。
这里写图片描述
对所有情况中选择值最小的作为这个点的LBP值。
当然后面提出了基于圆形的任意半径只是一个扩展,也很好理解。
接着,在圆形LBP的基础上,发现局部二值模式在提取局部纹理特征过程中,二进制模式种类数是对着采样像素点的个数增加而增加的。比如3*3的矩形框中的二进制模式就有28=256种,当变成5*5的时候,二进制模式的值会成指数增加。(实际上模式的个数就是对应了最终的特征直方图的维数,维数大,那么处理起来就比较费时了)。为了解决这一问题,Ojala等人提出了一致性模式方法(Uniform Pattern)方法。他们认为当某个二进制串相连成环状时,如果二进制位数变换至多2次,那么就是一致性模式,其余的则就是非一致性模式。
这里写图片描述
注意:对于3×3邻域内8个采样点来说,二进制模式由原始的256种减少为58种,即:它把值分为59类,58个uniform pattern为一类,其它的所有值为第59类。

当我们知道某一个点属于哪个模式后,接下来我们基于这些LBP值进行人脸识别。
LBP被运用于计算机人脸识别领域时,提取出来的人脸特征通常是以LBP直方图向量进行表达的。
1. 对预处理后的人脸图像进行分块
2. 对分块后的各小块图像区域进行LBP特征提取变换
3. 使用LBP直返图向量作为人脸特征的描述。

一般分块数越多,人脸表达的效果就会越好,但是分块数越多,会直接导致特征向量维数的增加,会增加计算的复杂度。对每个分块计算LBP值的直方图,然后将所有分块直方图进行连接得到最终的直方图特征向量,这个特征向量代表原来的人脸图像,可以用来描述整体图像。
这里写图片描述

对于这个融合的直方图,我们进行特征分类。
如果训练样本数量越大,分类的效果也会越好,在基于LBP的人脸识别中,通常采用基于直方图的相似性度量的最近邻分类方法来分类。
我们可以在 OpenCV源码中找到他的实现“sources
\modules\contrib\src\facerec.cpp”函数

void LBPH::predict(InputArray _src, int &minClass, double &minDist) const 

部分源码如下:

   // find 1-nearest neighbor    minDist = DBL_MAX;    minClass = -1;    for(size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) {        double dist = compareHist(_histograms[sampleIdx], query, CV_COMP_CHISQR);        if((dist < minDist) && (dist < _threshold)) {            minDist = dist;            minClass = _labels.at<int>((int) sampleIdx);        }    }

可以看出是在所有图像的直方图中找出距离最近的作为返回值。

0 0
原创粉丝点击