Ask Your Question
0

Is it possible to get multiple prediction from FaceRecognizer

asked 2015-10-13 06:07:14 -0600

comdiv gravatar image

The task:

1) We have 1000+ face image database

2) For given image, we must detect top 10 most similar faces from database - in most cases face will not be exactly in database so large value for treshhold used, we must to get SIMILAR (but top 10), not exactly SAME (but 1)

We start implement it with opencv Face recognition.

But with it's API we just can get ONE BEST result for algorightm choise with minimal distance with PREDICT method.

model->predict(...);

Is it possible to get TOP N of results in descending order of distance?

I'm almost sure that internally FR algorithms "knows" weights for all matches.

edit retag flag offensive close merge delete

Comments

just calculate one to all, all the distances, then sort them out and then take the top 10?

StevenPuttemans gravatar imageStevenPuttemans ( 2015-10-13 07:48:14 -0600 )edit

It require rewrite face module itself - no API for "to all, all the distances", it's not much hard, but i don't like to grow own forks and make entropy on code that i want just to use, not contribute.

comdiv gravatar imagecomdiv ( 2015-10-13 21:25:59 -0600 )edit

You could look at it the other way, this problem has been stated many times before, why not implement it, dig into the code, contribute it back and be greatful for the fact that you can use this very decent open source computer vision library for free. We would all be thankful.

StevenPuttemans gravatar imageStevenPuttemans ( 2015-10-14 01:13:40 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
1

answered 2015-10-15 12:25:16 -0600

updated 2015-10-16 03:06:35 -0600

I modified the predict functions from LBPH part (the same code can be applied to eigenfaces and fisherfaces parts):

    void LBPH::predict(InputArray _src, std::vector<int> &minClass, std::vector<double> &minDist, int maxN) const {
    if (_histograms.empty()) {
        // throw error if no data (or simply return -1?)
        String error_message = "This LBPH model is not computed yet. Did you call the train method?";
        CV_Error(Error::StsBadArg, error_message);
    }
    Mat src = _src.getMat();
    // get the spatial histogram from input image
    Mat lbp_image = elbp(src, _radius, _neighbors);
    Mat query = spatial_histogram(
        lbp_image, /* lbp_image */
        static_cast<int>(std::pow(2.0, static_cast<double>(_neighbors))), /* number of possible patterns */
        _grid_x, /* grid size x */
        _grid_y, /* grid size y */
        true /* normed histograms */);

    // find first maxN nearest neighbors
    // using priority for keeping maxN min distances and maxN min classes
    // remember to include queue header file and algorithm for greater<double>
    std::priority_queue<double, std::vector<double>, std::greater<double>> minDist1;
    std::priority_queue<int, std::vector<int>, std::greater<int>> minClass1;

    for (size_t sampleIdx = 0; sampleIdx < _histograms.size(); sampleIdx++) {
        double dist = compareHist(_histograms[sampleIdx], query, HISTCMP_CHISQR_ALT);
        if (dist < _threshold)
        {
            if (minDist1.size() < maxN)
            {
                minDist1.push(dist);
                minClass1.push(_labels.at<int>((int)sampleIdx));
            }
            else if (dist < minDist1.top())
            {
                minDist1.pop();
                minClass1.pop();
                minDist1.push(dist);
                minClass1.push(_labels.at<int>((int)sampleIdx));
            }
        }
    }
    minDist = std::vector<double>(minDist1.size());
    minClass = std::vector<int>(minClass1.size());
    // storing the results back to vector objects
    while (!minDist1.empty())
    {
        minDist.emplace_back(minDist1.top());
        minClass.emplace_back(minClass1.top());
        minDist1.pop();
        minClass1.pop();
    }
}

std::vector<std::pair<int, double>> LBPH::predict(InputArray _src, int maxN) const {
    std::vector<int> label;
    std::vector<double> weight;
    predict(_src, label, weight, maxN);
    std::vector<std::pair<int, double>> result(label.size());
    for (int i = 0; i < label.size(); i++)
        result[i] = std::make_pair(label[i], weight[i]);
    return result;
}

Hope this helps.

edit flag offensive delete link more

Comments

1

isn't it vector< pair<int,double> > result(label.size()) ? and where is greater<double> ?

berak gravatar imageberak ( 2015-10-15 20:13:26 -0600 )edit
2

Thanks @berak. Yes, it is std::vector<std::pair<int, double>>. And std::greater<double> is in the header file algorithm. I updated the code. But for recompiling the face module (in the contribution part) to use these functions, it needs more effort to add code to other files (face.hpp, fisher_faces.cpp and eigen_faces.cpp). So I uploaded the face module's code to my Google drive at this link.

tuannhtn gravatar imagetuannhtn ( 2015-10-16 03:05:28 -0600 )edit
1

ah, ok. thanks. tbh, i did not bother to look up 'greater' .

and yes, modifying the interface means, it needs implementation for all 3 classes.

berak gravatar imageberak ( 2015-10-16 03:12:51 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2015-10-13 06:07:14 -0600

Seen: 973 times

Last updated: Oct 16 '15