Search code examples
opencvcomputer-visionface-detectionface-recognitionpca

How to use Mahalanobis Distance in libfacerec while preforming PCA in OPENCV v2 API?


I am working on a Face Recognition Project and I am using libfacerec. While predicting the labels the library uses norm() which calculates the absolute difference. How can I use Mahalanobis Distance to improve my accuracy? OpenCV2 has a function:

double Mahalanobis(InputArray vec1, InputArray vec2, InputArray icovar)

which requires me to calculate icovar by using

void calcCovarMatrix(InputArray samples, OutputArray covar, OutputArray mean, int flags, int ctype=CV_64F)

but, this function expects samples to be stored either as separate matrices or as rows/columns of a single matrix. I don't know how to provide data to this function, i.e. how to make samples separate matrices or as rows of a single matrix. Please Help. I wish to change the following code:

int Eigenfaces::predict(InputArray _src) const {
// get data
Mat src = _src.getMat();
// project into PCA subspace
Mat q = project(_eigenvectors, _mean, src.reshape(1,1));
double minDist = numeric_limits<double>::max();
int minClass = -1;
for(unsigned int sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {
    //Change Here------------------------------------------------
    Mat icovar;
    Mat mean;
    calcCovarMatrix(Mat(),icovar,mean,CV_COVAR_SCRAMBLED);
    double dist = Mahalanobis(q, sampleIdx, icovar);
    //-----------------------------------------------------------
    //double dist = norm(_projections[sampleIdx], q, NORM_L2);
    if(dist < minDist) {
        minDist = dist;
        minClass = _labels[sampleIdx];
    }
}
return minClass;
}

Solution

  • Introduction

    First of all this. From my personal experience I can tell you, that for a PCA the distance metric doesn't really have any significant impact on the recognition rate. I know some papers report it, but I can't acknowledge it on my image databases. As for your question on how to calculate the Mahalanobis distance. There's a close relationship between a PCA and the Mahalanobis distance, see "Improving Eigenfaces" at http://www.cognotics.com/opencv/servo_2007_series/part_5/page_5.html, which is also given in [1]. Just for sake of completeness, the project this post refers to is given at: https://github.com/bytefish/libfacerec.

    Code

    Without any further testing I would rewrite the cognotics thing into:

    int cv::Eigenfaces::predict(InputArray _src) const {
      // get data
      Mat src = _src.getMat();
      // project into PCA subspace
      Mat q = subspace::project(_eigenvectors, _mean, src.reshape(1,1));
      double minDist = numeric_limits<double>::max();
      int minClass = -1;
      for(int sampleIdx = 0; sampleIdx < _projections.size(); sampleIdx++) {
        Mat diff0, diff1;
        // perform element wise multiplication and division
        multiply(q - _projections[sampleIdx], q - _projections[sampleIdx], diff0);
        divide(diff0.reshape(1,1), _eigenvalues.reshape(1,1), diff1);
        double dist = sum(diff1).val[0];
        if(dist < minDist) {
          minDist = dist;
          minClass = _labels[sampleIdx];
        }
      }
      return minClass;
    }
    

    References

    [1] Moghaddam, B. and Pentland, A. "Probabilistic Visual Learning for Object Representation" In Pattern Analysis and Machine Intelligence, IEEE Transactions on Vol. 19, No. 7. (1997), pp. 696-710