opencv学习之路(40)、人脸识别算法——EigenFace、FisherFace、LBPH

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

一、原理介绍及数据收集

特征脸方法主要是基于PCA降维实现。算法

详细介绍和主要思想能够参考数据库

http://blog.csdn.net/u010006643/article/details/46417127app

上述博客的人脸数据库打不开了,你们能够去下面这个博客下载ORL人脸数据库测试

http://blog.csdn.net/xdzzju/article/details/50445160spa

下载后,ORL人脸数据库有40我的,每人10张照片。.net

二、流程

三、相关图示

 

四、代码

  1 #include <opencv2/opencv.hpp>
  2 #include <opencv2/face.hpp>
  3 
  4 using namespace cv;
  5 using namespace cv::face;
  6 using namespace std;
  7 
  8 //对原图归一化
  9 Mat normal(Mat src, Mat dst) {
 10     if (src.channels() == 1)//若原图单通道
 11         normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
 12     else //不然,原图三通道
 13         normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
 14     return dst;
 15 }
 16 
 17 void main() {
 18     //读取文件,转换为数据流
 19     string filename = string("at.txt");
 20     ifstream file(filename.c_str(), ifstream::in);
 21     if (!file)
 22         cout << "error" << endl;
 23 
 24     string line, path, classlabel;
 25     vector<Mat>image;
 26     vector<int>labels;
 27     char separator = ';';
 28     while (getline(file,line))
 29     {
 30         stringstream liness(line);
 31         getline(liness, path, separator);
 32         getline(liness, classlabel);
 33         if (!path.empty()&&!classlabel.empty())
 34         {
 35             //cout << "path:" << path<< endl;
 36             image.push_back(imread(path, 0));
 37             labels.push_back(atoi(classlabel.c_str()));
 38         }
 39     }
 40 
 41     if (image.size() < 1 || labels.size() < 1)
 42         cout << "invalid image path..." << endl;
 43 
 44     int height = image[0].rows;
 45     int width = image[0].cols;
 46     //cout << "height:" << height << ",width:" << width<<endl;
 47 
 48     //最后一我的为测试样本
 49     Mat testSample = image[image.size() - 1];
 50     int testLabel = labels[labels.size() - 1];
 51     image.pop_back();
 52     labels.pop_back();
 53 
 54     //训练
 55     Ptr<BasicFaceRecognizer>model = createEigenFaceRecognizer();
 56     model->train(image, labels);
 57 
 58     //识别
 59     int predictLabel = model->predict(testSample);
 60     cout << "actual label:" << testLabel << ",predict label:" << predictLabel << endl;
 61 
 62     //得到特征值,特征向量,均值    平均脸
 63     Mat eigenvalues = model->getEigenValues();
 64     Mat eigenvectors = model->getEigenVectors();
 65     Mat mean = model->getMean();
 66     Mat meanFace = mean.reshape(1,height);
 67     Mat dst;
 68     dst= normal(meanFace,dst);
 69     imshow("Mean Face", dst);
 70     
 71     //特征脸
 72     for (int i = 0; i < min(10,eigenvectors.cols); i++)
 73     {
 74         Mat ev = eigenvectors.col(i).clone();
 75         Mat eigenFace = ev.reshape(1, height);
 76         Mat grayscale;
 77         grayscale = normal(eigenFace, grayscale);
 78         Mat colorface;
 79         applyColorMap(grayscale, colorface, COLORMAP_BONE);
 80         char* winTitle = new char[128];
 81         sprintf(winTitle, "eigenface_%d", i);
 82         imshow(winTitle, colorface);
 83     }
 84 
 85     //重建人脸
 86     for (int num = min(10, eigenvectors.cols); num < min(300, eigenvectors.cols); num+=15)
 87     {
 88         Mat evs = Mat(eigenvectors, Range::all(), Range(0, num));
 89         Mat projection = LDA::subspaceProject(evs, mean, image[0].reshape(1, 1));
 90         Mat reconstruction= LDA::subspaceReconstruct(evs, mean, projection);
 91 
 92         Mat result = reconstruction.reshape(1, height);
 93         reconstruction = normal(result, reconstruction);
 94         char* winTitle = new char[128];
 95         sprintf(winTitle, "recon_face_%d", num);
 96         imshow(winTitle, reconstruction);
 97     }
 98     
 99     waitKey(0);
100 }

2、FisherFace(LDA线性判别分析)

一、理论介绍

http://blog.csdn.net/feirose/article/details/395529973d

 

二、流程

三、PCA和LDA的对比

 

四、代码(与特征脸代码几乎一致)

此处只列出修改部分code

55行模型训练    Ptr<BasicFaceRecognizer>model = createFisherFaceRecognizer();

72行显示特征脸  for (int i = 0; i < min(16,eigenvectors.cols); i++)
                   Mat ev = eigenvectors.col(i).clone();

86行重建人脸    for (int num = 0; num < min(16, eigenvectors.cols); num++)

3、LBPH

 一、原理介绍

你们能够参考http://blog.csdn.net/xiaomaishiwoa/article/details/46640377orm

2、流程

三、代码

#include <opencv2/opencv.hpp>
#include <opencv2/face.hpp>

using namespace cv;
using namespace cv::face;
using namespace std;

//对原图归一化
Mat normal(Mat src, Mat dst) {
    if (src.channels() == 1)//若原图单通道
        normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
    else //不然,原图三通道
        normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
    return dst;
}

void main() {
    //读取文件,转换为数据流
    string filename = string("at.txt");
    ifstream file(filename.c_str(), ifstream::in);
    if (!file)
        cout << "error" << endl;

    string line, path, classlabel;
    vector<Mat>image;
    vector<int>labels;
    char separator = ';';
    while (getline(file,line))
    {
        stringstream liness(line);
        getline(liness, path, separator);
        getline(liness, classlabel);
        if (!path.empty()&&!classlabel.empty())
        {
            //cout << "path:" << path<< endl;
            image.push_back(imread(path, 0));
            labels.push_back(atoi(classlabel.c_str()));
        }
    }

    if (image.size() < 1 || labels.size() < 1)
        cout << "invalid image path..." << endl;

    int height = image[0].rows;
    int width = image[0].cols;
    //cout << "height:" << height << ",width:" << width<<endl;

    //最后一我的为测试样本
    Mat testSample = image[image.size() - 1];
    int testLabel = labels[labels.size() - 1];
    image.pop_back();
    labels.pop_back();

    //训练
    Ptr<LBPHFaceRecognizer>model = createLBPHFaceRecognizer();
    model->train(image, labels);

    //识别
    int predictLabel = model->predict(testSample);
    cout << "actual label:" << testLabel << ",predict label:" << predictLabel << endl;

    //打印参数
    int radius = model->getRadius();    //中心像素点到周围像素点的距离
    int neibs = model->getNeighbors();    //周围像素点的个数
    int grad_x = model->getGridX();        //将一张图片在x方向分红几块
    int grad_y = model->getGridY();        //将一张图片在y方向分红几块
    double t = model->getThreshold();    //类似度阈值    
    cout << "radius:" << radius << endl;
    cout << "neibs:" << neibs << endl;
    cout << "grad_x:" << grad_x << endl;
    cout << "grad_y:" << grad_y << endl;
    cout << "threshold:" << t<<endl;
    
    waitKey(0);
}