Ask Your Question

Revision history [back]

Add method in cvextern.dll in a FaceRecognition project

Hi,

I'm implementing a little FaceRecognition program using Emgu as a wrapper of OpenCV libraries. It seems to work fine, but I need a function that returns all the distances between the image sample and the faces in the database (the FaceRecognizer.Predict method implemented only returns the smallest distance and label).

So I built Emgu from Git, in order to adapt functions in the unmanaged code (cvextern.dll) to my needs.

Here's the original in face_c.cpp

void cveFaceRecognizerPredict(cv::face::FaceRecognizer* recognizer, cv::_InputArray* image, int* label, double* dist)
{ 
    int l = -1;
    double d = -1; 
    recognizer->predict(*image, l, d); 
    *label = l; 
    *dist = d; 
}

that stores minimum distance and corresponding label in l and d, thanks to predict.

The method I wrote, following the summary in opencv face.hpp:

void cveFaceRecognizerPredictCollector(cv::face::FaceRecognizer * recognizer, cv::_InputArray * image, std::vector<int>* labels, std::vector<double>* distances)
{
    std::map<int, double> result_map = std::map<int, double>();
    cv::Ptr<cv::face::StandardCollector> collector = cv::face::StandardCollector::create();

    recognizer->predict(*image, collector);

    result_map = collector->getResultsMap();

    for (std::map<int, double>::iterator it = result_map.begin(); it != result_map.end(); ++it) {
        distances->push_back(it->second);
        labels->push_back(it->first);
    }
}

And the caller in c#

using (Emgu.CV.Util.VectorOfInt labels = new Emgu.CV.Util.VectorOfInt())
using (Emgu.CV.Util.VectorOfDouble distances = new Emgu.CV.Util.VectorOfDouble())
using (InputArray iaImage = image.GetInputArray())
{
    FaceInvoke.cveFaceRecognizerPredictCollector(_ptr, iaImage, labels, distances);
}

[DllImport(CvInvoke.ExternLibrary, CallingConvention = CvInvoke.CvCallingConvention)]
internal extern static void cveFaceRecognizerPredictCollector(IntPtr recognizer, IntPtr image, IntPtr labels, IntPtr distances);

The application works in real-time, so the function in c# is called continuously. I have only two faces and one label (same person) stored in my database, so the first call returns correctly the only possible label and stores it in labels. Keeping the application running, returned labels and the size of labels vector keep growing, filled with unregistered labels that I don't know where he takes. It seems to me like the collector in c++ is not well referenced, so that every time the function is called it keeps storing data without releasing the previous ones, overwriting them. But it's only my guess, I'm not very good with c++.

In addition, turns out OpenCV already provides a sort of smart pointer class (cv::Ptr). So, as I understand it, my collector should be automatically cleaned up once his scope block has ended, right? I also tried to use Ptr with result_map but keeps me returning random labels.

What else could possily be wrong?

I know that's not really a Opencv problem, but I believe the issues are in the unmanaged code or in autogenerated code I get while building, so I hope you can help