zoukankan      html  css  js  c++  java
  • OpenCV学习(38) 人脸识别(3)

         

          前面我们学习了基于特征脸的人脸识别,现在我们学习一下基于Fisher脸的人脸识别,Fisher人脸识别基于LDA(线性判别算法)算法,算法的详细介绍可以参考下面两篇教程内容:

    http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html

    LDA算法细节参考:

    http://www.cnblogs.com/mikewolf2002/p/3435750.html

     

    程序代码:

    #include "opencv2/core/core.hpp"
    #include "opencv2/contrib/contrib.hpp"
    #include "opencv2/highgui/highgui.hpp"

    #include <iostream>
    #include <fstream>
    #include <sstream>

    using namespace cv;
    using namespace std;

    static Mat norm_0_255(InputArray _src)
    {
    Mat src = _src.getMat();
    Mat dst;
    switch(src.channels())
    {
    case 1:
    cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
    break;
    case 3:
    cv::normalize(_src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
    break;
    default:
    src.copyTo(dst);
    break;
    }
    return dst;
    }

    static void read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator = ';')
    {
    std::ifstream file(filename.c_str(), ifstream::in);
    if (!file)
    {
    string error_message = "No valid input file was given, please check the given filename.";
    CV_Error(CV_StsBadArg, error_message);
    }
    string line, path, classlabel;
    while (getline(file, line))
    {
    stringstream liness(line);
    getline(liness, path, separator);
    getline(liness, classlabel);
    if(!path.empty() && !classlabel.empty())
    {
    images.push_back(imread(path, 0));
    labels.push_back(atoi(classlabel.c_str()));
    }
    }
    }

    int main(int argc, const char *argv[])
    {

    string fn_csv = string("facerec_at_t.txt");
    vector<Mat> images;
    vector<int> labels;

    try
    {
    read_csv(fn_csv, images, labels);
    } catch (cv::Exception& e)
    {
    cerr << "Error opening file "" << fn_csv << "". Reason: " << e.msg << endl;
    exit(1);
    }

    if(images.size() <= 1)
    {
    string error_message = "This demo needs at least 2 images to work. Please add more images to your data set!";
    CV_Error(CV_StsError, error_message);
    }

    int height = images[0].rows;

    Mat testSample = images[images.size() - 1];
    int testLabel = labels[labels.size() - 1];

    images.pop_back();
    labels.pop_back();

    Ptr<FaceRecognizer> model = createFisherFaceRecognizer();
    model->train(images, labels);
    int predictedLabel = model->predict(testSample);

    string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
    cout << result_message << endl;

    Mat eigenvalues = model->getMat("eigenvalues");
    Mat W = model->getMat("eigenvectors");
    Mat mean = model->getMat("mean");
    imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));

    for (int i = 0; i < min(16, W.cols); i++)
    {
    string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
    cout << msg << endl;
    Mat ev = W.col(i).clone();
    Mat grayscale = norm_0_255(ev.reshape(1, height));
    Mat cgrayscale;
    applyColorMap(grayscale, cgrayscale, COLORMAP_BONE);
    imshow(format("fisherface_%d", i), cgrayscale);

    }

    for(int num_component = 0; num_component < min(16, W.cols); num_component++)
    {

    Mat ev = W.col(num_component);
    Mat projection = subspaceProject(ev, mean, images[0].reshape(1,1));
    Mat reconstruction = subspaceReconstruct(ev, mean, projection);
    reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
    imshow(format("fisherface_reconstruction_%d", num_component), reconstruction);

    }

    while(1)
    waitKey(0);
    return 0;
    }

          从代码中我们可以看到,最大的区别就是创建人脸识别模式类时候,调用的函数不一样,其它代码和特征脸识别的代码一样,对于train和predict函数来说,调用方式完全一样,只是底层的具体算法细节不一样。

        Ptr<FaceRecognizer> model = createFisherFaceRecognizer();

      

         下面是Fisher人脸识别类的train函数,从中可以看到,函数会先调用PCA算法进行降维,之后再执行LDA算法,求得Fisher特征值和特征向量。注意投影矩阵是PCA算法的特征向量和LDA算法特征向量的乘积

        // 先用PCA算法降维perform a PCA and keep (N-C) components

        PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, (N-C));

        // 把数据投影到 PCA空间,再对该数据执行LDA算法

        LDA lda(pca.project(data),labels, _num_components);

       // 保存总的均值向量

        _mean = pca.mean.reshape(1,1);

        _labels = labels.clone();

        lda.eigenvalues().convertTo(_eigenvalues, CV_64FC1);

       //计算投影矩阵=pca.eigenvectors * lda.eigenvectors.

        // Note: OpenCV stores the eigenvectors by row, so we need to transpose it!

        gemm(pca.eigenvectors, lda.eigenvectors(), 1.0, Mat(), 0.0, _eigenvectors, GEMM_1_T);

        //把原始矩阵投影到新的投影空间

        for(int sampleIdx = 0; sampleIdx < data.rows; sampleIdx++) {

            Mat p = subspaceProject(_eigenvectors, _mean, data.row(sampleIdx));

            _projections.push_back(p);

        }

     

        在程序中,我们仍然使用AT&T Facedatabase数据库的图片,原教程中推荐用Yale Facedatabase A,但是它的图像格式是gif,OpenCV不支持,只好放弃。

    程序代码:FirstOpenCV34

  • 相关阅读:
    Ajax基础:3.Json
    Head First Design Patterns State Pattern
    Head First Design Patterns Template Method Pattern
    Articles For CSS Related
    Head First Design Patterns Decorator Pattern
    代码审查工具
    How To Be More Active In A Group
    Head First Design Patterns Factory Method Pattern
    Head First Design Patterns Composite Pattern
    Tech Articles
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/3436777.html
Copyright © 2011-2022 走看看