<repo_name>gnlin/faceRecFW<file_sep>/Sources/fisherldautils.cpp
/* Modified version of Fisher LDA Alogrithm, <NAME> */
#include "fisherldautils.h"
#include "pcautils.h"

void fisher_lda_utils::flda_transfer(std::vector<cv::Mat> &pca_feature_list,
                                     std::vector<cv::Mat> &flda_feature_list,
                                     cv::Mat &flda_transfer_matrix,
                                     int sample_class_number, int sample_per_class,
                                     int dim_ref)
{
    /* make sure the input has valid pca feature input, which makes sure every */
    /* thing else possible. */
    assert(pca_feature_list.size() != 0 && pca_feature_list[0].cols == 1);

    std::vector<cv::Mat> mk_matrix;

    /* Sb, Between-calss scatter matrix, describles the dispersion between each */
    /* class and the total sample set. */
    cv::Mat Sb;

    /* Sw, Within-class scatter matrix, describles the dispersion within one class's */
    /* sample set. */
    cv::Mat Sw;

    /* calculate mean vectors of each sample set */
    calc_mean_vectors(pca_feature_list, mk_matrix, sample_class_number, sample_per_class);

    /* calculate Sb, the Between-calss scatter matrix */
    calc_between_class_scatter_matrix(Sb, mk_matrix, pca_feature_list, sample_class_number);

    /* calculate Sw, the Within-class scatter matrix */
    calc_within_class_scatter_matrix(Sw, mk_matrix, pca_feature_list, sample_class_number, sample_per_class);

    /* calculate transfer matrix */
    calc_transfer_matrix(Sb, Sw, flda_transfer_matrix, dim_ref, sample_class_number);

    /* claculate flda features */
    for (size_t i = 0; i < pca_feature_list.size(); i++) {
        cv::Mat flda_feature;

        flda_feature = flda_transfer_matrix * pca_feature_list[i];
        flda_feature_list.push_back(flda_feature);
    }
}

void fisher_lda_utils::calc_transfer_matrix(cv::Mat &Sb, cv::Mat &Sw,
                                            cv::Mat &flda_transfer_matrix, int dim_ref,
                                            int sample_class_number)
{
    cv::Mat Sw_inverse;
    cv::Mat SwSb;
    cv::Mat eigen_vector_matrix;
    cv::Mat eigen_value_matrix;

    cv::invert(Sw, Sw_inverse, cv::DECOMP_SVD);
    SwSb = Sw_inverse * Sb;

    cv::eigen(SwSb, eigen_value_matrix, eigen_vector_matrix);

    int range = (sample_class_number < dim_ref) ? sample_class_number : dim_ref;

    /* range selection algorithm */
    // 1. if (range < 2) range = 2;
    if (range < dim_ref) range = 2 * range;

    flda_transfer_matrix.create(range, eigen_vector_matrix.cols, CV_64FC1);

    for (int y = 0; y < range; y++) {
        for (int x = 0; x < eigen_vector_matrix.cols; x++) {
            flda_transfer_matrix.at<double>(y, x) =
                    eigen_vector_matrix.at<double>(y, x);
        }
    }
}

void fisher_lda_utils::calc_between_class_scatter_matrix(cv::Mat &Sb,
                                                         std::vector<cv::Mat> &mk_matrix,
                                                         std::vector<cv::Mat> &pca_feature_list,
                                                         int sample_class_number)
{
    int feature_len = pca_feature_list[0].rows;

    /* create matrix Sb */
    Sb.create(feature_len, feature_len, CV_64FC1);
    Sb.setTo(cv::Scalar(0.0));

    /* mean matrix of total sample set */
    cv::Mat mean_total;
    mean_sample_set(pca_feature_list, mean_total);

    /* calculate matrix Sb */
    for (int i = 0; i < sample_class_number; i++) {
        cv::Mat diff_vec, diff_vec_t;
        cv::Mat covariance;

        cv::subtract(mk_matrix[i], mean_total, diff_vec);
        cv::transpose(diff_vec, diff_vec_t);
        covariance = diff_vec * diff_vec_t;

        cv::add(Sb, covariance, Sb);
    }

    for (int x = 0; x < Sb.cols; x++) {
        for (int y = 0; y < Sb.rows; y++) {
            Sb.at<double>(y, x) = Sb.at<double>(y, x) / sample_class_number;
        }
    }
}

void fisher_lda_utils::calc_within_class_scatter_matrix(cv::Mat &Sw, std::vector<cv::Mat> &mk_matrix,
                                                        std::vector<cv::Mat> &pca_feature_list,
                                                        int sample_class_number, int sample_per_class)
{
    int feature_len = pca_feature_list[0].rows;

    /* create matrix Sw */
    Sw.create(feature_len, feature_len, CV_64FC1);
    Sw.setTo(cv::Scalar(0.0));

    for (int i = 0; i < sample_class_number; i++) {
        for (int j = 0; j < sample_per_class; j++) {
            cv::Mat diff_vec, diff_vec_t;
            cv::Mat covariance;

            cv::subtract(mk_matrix[i],
                         pca_feature_list[ (i * sample_per_class) + j ],
                         diff_vec);

            cv::transpose(diff_vec, diff_vec_t);

            covariance = diff_vec * diff_vec_t;

            cv::add(Sw, covariance, Sw);
        }
    }

    for (int x = 0; x < Sw.cols; x++) {
        for (int y = 0; y < Sw.rows; y++) {
            Sw.at<double>(y, x) =
                    Sw.at<double>(y, x) / (sample_class_number * sample_per_class);
        }
    }
}

void fisher_lda_utils::calc_mean_vectors(std::vector<cv::Mat> &pca_feature_list,
                                         std::vector<cv::Mat> &mk_matrix,
                                         int sample_class_number, int sample_per_class)
{
    int feature_len = pca_feature_list[0].rows;
    std::vector<cv::Mat> class_storage;

    /* a set of vectors to storage samples of each class at a time*/
    for (int i = 0; i < sample_per_class; i++) {
        cv::Mat local_matrix;
        local_matrix.create(feature_len, 1, CV_64FC1);
        class_storage.push_back(local_matrix);
    }

    /* M1, M2, ..., Mk, mean vector of each class's samples */
    for (int i = 0; i < sample_class_number; i++) {
        cv::Mat Mk;

        for (int j = 0; j < sample_per_class; j++) {
            pca_feature_list[ (i * sample_per_class) + j ]
                    .copyTo(class_storage[j]);
        }

        mean_sample_set(class_storage, Mk);

        mk_matrix.push_back(Mk);
    }
}

void fisher_lda_utils::mean_sample_set(std::vector<cv::Mat> &sample_set, cv::Mat &matrix_mean)
{
    assert(!sample_set.empty());

    int i, x, y;
    int sample_size = sample_set.size();

    matrix_mean.create(sample_set[0].rows, sample_set[0].cols, sample_set[0].type());
    matrix_mean.setTo(cv::Scalar(0.0));

    for (i = 0; i < sample_size; i++) {
        cv::add(matrix_mean, sample_set[i], matrix_mean);
    }

    for (x = 0; x < matrix_mean.cols; x++) {
        for (y = 0; y < matrix_mean.rows; y++) {
            matrix_mean.at<double>(y, x) =
                    matrix_mean.at<double>(y, x) / sample_size;
        }
    }
}
<file_sep>/Headers/fisherldautils.h
#ifndef FISHERLDAUTILS_H
#define FISHERLDAUTILS_H

#include "common.h"

namespace fisher_lda_utils {
    void flda_transfer(std::vector<cv::Mat> &pca_feature_list,
                       std::vector<cv::Mat> &flda_feature_list,
                       cv::Mat &flda_transfer_matrix,
                       int sample_class_number,
                       int sample_per_class,
                       int dim_ref);

    void calc_mean_vectors(std::vector<cv::Mat> &pca_feature_list,
                           std::vector<cv::Mat> &mk_matrix,
                           int sample_class_number, int sample_per_class);

    void calc_between_class_scatter_matrix(cv::Mat &Sb, std::vector<cv::Mat> &mk_matrix,
                                           std::vector<cv::Mat> &pca_feature_list,
                                           int sample_class_number);

    void calc_within_class_scatter_matrix(cv::Mat &Sw, std::vector<cv::Mat> &mk_matrix,
                                          std::vector<cv::Mat> &pca_feature_list,
                                          int sample_class_number, int sample_per_class);

    void mean_sample_set(std::vector<cv::Mat> &sample_set, cv::Mat &matrix_mean);

    void calc_transfer_matrix(cv::Mat &Sb, cv::Mat &Sw,
                              cv::Mat &flda_transfer_matrix, int dim_ref,
                              int sample_class_number);
}

#endif // FISHERLDAUTILS_H
<file_sep>/README.md
# faceRecFW
A face recognition program that implements basic human face detection and recognition function.

# Description
I wrote this program two years ago and I did not touch the code since then. The program runs 
well and all functions are okay, except a minor bug in facedetector.cpp, which will cause 
program crashes, but it happens very rare. I'll re-arrange the code when I have time, and
probably improve the algorithm a bit.
