Нестабилно разпознаване на лица с помощта на OpenCV

Разработвам приложение за Android за разпознаване на лица, използвайки JavaCV, което е неофициална обвивка на OpenCV . След като импортирах com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer, прилагам и тествам следните известни методи:

  • LBPH с помощта на метода createLBPHFaceRecognizer().
  • FisherFace използва метод createFisherFaceRecognizer().
  • EigenFace с помощта на метод createEigenFaceRecognizer().

Преди да разпозная откритото лице, коригирам завъртеното лице и изрязвам правилната зона, вдъхновявайки се от този метод

Като цяло, когато предам на камера лице, което вече съществува в базата данни, разпознаването е наред. Но това не винаги е правилно. Понякога разпознава непознатото лице (не е намерено в базата данни с обучени проби) с голяма вероятност. Когато имаме в БД две или повече лица с подобни характеристики (брада, мустаци, очила...) разпознаването може да бъде много погрешно между тези лица!

За да предвидя резултата с помощта на изображението на тестовото лице, прилагам следния код:

public String predict(Mat m) {

        int n[] = new int[1];
        double p[] = new double[1];
        IplImage ipl = MatToIplImage(m,WIDTH, HEIGHT);

        faceRecognizer.predict(ipl, n, p);

        if (n[0]!=-1)
         mProb=(int)p[0];
        else
            mProb=-1;
            if (n[0] != -1)
            return labelsFile.get(n[0]);
        else
            return "Unkown";
    }

Не мога да контролирам прага на вероятността p, защото:

  • Малко p ‹ 50 може да предвиди правилен резултат.
  • Високо p > 70 може да предвиди грешен резултат.
  • Средното p може да предвиди правилно или невярно.

Освен това не разбирам защо функцията predict() дава понякога вероятност, по-голяма от 100 в случай на използване на LBPH??? и в случай на Fisher и Eigen дава много големи стойности (>2000) ?? Може ли някой да помогне в намирането на решение за тези странни проблеми? Има ли някакво предложение за подобряване на устойчивостта на разпознаването? особено в случай на сходство на две различни лица.

Следва целият клас, използващ Facerecognizer:

package org.opencv.javacv.facerecognition;

import static  com.googlecode.javacv.cpp.opencv_highgui.*;
import static  com.googlecode.javacv.cpp.opencv_core.*;

import static  com.googlecode.javacv.cpp.opencv_imgproc.*;
import static com.googlecode.javacv.cpp.opencv_contrib.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.util.ArrayList;

import org.opencv.android.Utils;
import org.opencv.core.Mat;

import com.googlecode.javacv.cpp.opencv_imgproc;
import com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import com.googlecode.javacv.cpp.opencv_core.MatVector;

import android.graphics.Bitmap;
import android.os.Environment;
import android.util.Log;
import android.widget.Toast;

public  class PersonRecognizer {

    public final static int MAXIMG = 100;
    FaceRecognizer faceRecognizer;
    String mPath;
    int count=0;
    labels labelsFile;

     static  final int WIDTH= 128;
     static  final int HEIGHT= 128;;
     private int mProb=999;


    PersonRecognizer(String path)
    {
      faceRecognizer =  com.googlecode.javacv.cpp.opencv_contrib.createLBPHFaceRecognizer(2,8,8,8,200);
     // path=Environment.getExternalStorageDirectory()+"/facerecog/faces/";
     mPath=path;
     labelsFile= new labels(mPath);


    }

    void changeRecognizer(int nRec)
    {
        switch(nRec) {
        case 0: faceRecognizer = com.googlecode.javacv.cpp.opencv_contrib.createLBPHFaceRecognizer(1,8,8,8,100);
                break;
        case 1: faceRecognizer = com.googlecode.javacv.cpp.opencv_contrib.createFisherFaceRecognizer();
                break;
        case 2: faceRecognizer = com.googlecode.javacv.cpp.opencv_contrib.createEigenFaceRecognizer();
                break;
        }
        train();

    }

    void add(Mat m, String description) {
        Bitmap bmp= Bitmap.createBitmap(m.width(), m.height(), Bitmap.Config.ARGB_8888);

        Utils.matToBitmap(m,bmp);
        bmp= Bitmap.createScaledBitmap(bmp, WIDTH, HEIGHT, false);

        FileOutputStream f;
        try {
            f = new FileOutputStream(mPath+description+"-"+count+".jpg",true);
            count++;
            bmp.compress(Bitmap.CompressFormat.JPEG, 100, f);
            f.close();

        } catch (Exception e) {
            Log.e("error",e.getCause()+" "+e.getMessage());
            e.printStackTrace();

        }
    }

    public boolean train() {

        File root = new File(mPath);
        Log.i("mPath",mPath);
        FilenameFilter pngFilter = new FilenameFilter() {
            public boolean accept(File dir, String name) {
                return name.toLowerCase().endsWith(".jpg");

        };
        };

        File[] imageFiles = root.listFiles(pngFilter);

        MatVector images = new MatVector(imageFiles.length);

        int[] labels = new int[imageFiles.length];

        int counter = 0;
        int label;

        IplImage img=null;
        IplImage grayImg;

        int i1=mPath.length();


        for (File image : imageFiles) {
            String p = image.getAbsolutePath();
            img = cvLoadImage(p);

            if (img==null)
                Log.e("Error","Error cVLoadImage");
            Log.i("image",p);

            int i2=p.lastIndexOf("-");
            int i3=p.lastIndexOf(".");
            int icount=Integer.parseInt(p.substring(i2+1,i3)); 
            if (count<icount) count++;

            String description=p.substring(i1,i2);

            if (labelsFile.get(description)<0)
                labelsFile.add(description, labelsFile.max()+1);

            label = labelsFile.get(description);

            grayImg = IplImage.create(img.width(), img.height(), IPL_DEPTH_8U, 1);

            cvCvtColor(img, grayImg, CV_BGR2GRAY);

            images.put(counter, grayImg);

            labels[counter] = label;

            counter++;
        }
        if (counter>0)
            if (labelsFile.max()>1)
                faceRecognizer.train(images, labels);
        labelsFile.Save();
    return true;
    }

    public boolean canPredict()
    {
        if (labelsFile.max()>1)
            return true;
        else
            return false;

    }

    public String predict(Mat m) {
        if (!canPredict())
            return "";
        int n[] = new int[1];
        double p[] = new double[1];
        IplImage ipl = MatToIplImage(m,WIDTH, HEIGHT);
//      IplImage ipl = MatToIplImage(m,-1, -1);

        faceRecognizer.predict(ipl, n, p);

        if (n[0]!=-1)
         mProb=(int)p[0];
        else
            mProb=-1;
    //  if ((n[0] != -1)&&(p[0]<95))
        if (n[0] != -1)
            return labelsFile.get(n[0]);
        else
            return "Unkown";
    }




      IplImage MatToIplImage(Mat m,int width,int heigth)
      {


           Bitmap bmp=Bitmap.createBitmap(m.width(), m.height(), Bitmap.Config.ARGB_8888);


           Utils.matToBitmap(m, bmp);
           return BitmapToIplImage(bmp,width, heigth);

      }

    IplImage BitmapToIplImage(Bitmap bmp, int width, int height) {

        if ((width != -1) || (height != -1)) {
            Bitmap bmp2 = Bitmap.createScaledBitmap(bmp, width, height, false);
            bmp = bmp2;
        }

        IplImage image = IplImage.create(bmp.getWidth(), bmp.getHeight(),
                IPL_DEPTH_8U, 4);

        bmp.copyPixelsToBuffer(image.getByteBuffer());

        IplImage grayImg = IplImage.create(image.width(), image.height(),
                IPL_DEPTH_8U, 1);

        cvCvtColor(image, grayImg, opencv_imgproc.CV_BGR2GRAY);

        return grayImg;
    }



    protected void SaveBmp(Bitmap bmp,String path)
      {
            FileOutputStream file;
            try {
                file = new FileOutputStream(path , true);

            bmp.compress(Bitmap.CompressFormat.JPEG,100,file);  
            file.close();
            }
            catch (Exception e) {
                // TODO Auto-generated catch block
                Log.e("",e.getMessage()+e.getCause());
                e.printStackTrace();
            }

      }


    public void load() {
        train();

    }

    public int getProb() {
        // TODO Auto-generated method stub
        return mProb;
    }


}

person Y.AL    schedule 05.01.2014    source източник
comment
да, ще ви трябват 3 различни прагови стойности, по една за всеки метод, тъй като функционалното пространство за всички тях се различава. също така, вашата 'p' стойност в прогнозата не е вероятност, а разстоянието от вашето тестово изображение до най-близкото намерено съвпадение в db (така че нещо обратното на него), така че това не е изобщо в диапазона [0..100].   -  person berak    schedule 13.05.2014
comment
@berak Предаваме три параметъра за прогнозиране на iplimage, int[], double[]. Добре, преминаваме Iplimage, имаме разстояние в double[], но какво int[]? какво представлява. Тъй като наистина не го разбирам, получавам различна стойност като 1,4,8.   -  person umerk44    schedule 14.05.2014
comment
това е етикетът на класа, идентификаторът на вашия човек. ти ли написа този код?   -  person berak    schedule 14.05.2014
comment
не, това не е моят код   -  person umerk44    schedule 14.05.2014
comment
@berak Благодаря за отговора. Тогава как можем да знаем прага на фалшивото разпознаване, за да отхвърлим всички тези фалшиво разпознати лица?   -  person Y.AL    schedule 19.05.2014
comment
dervish, ще трябва да проведеш тестове на данните си. честно казано, стартирането на кода е лесната част. оптимизирането на резултата е мястото, където започва истинската работа.   -  person berak    schedule 19.05.2014
comment
Съгласен съм да berak, имате нужда от подходящо количество различни изображения от едно и също лице, така че моделът да може да се обучава с него. В крайна сметка прогнозата е по-добра.   -  person Spindizzy    schedule 22.04.2016
comment
получавам същия проблем някой разрешил ли е този проблем през 2018 г.?   -  person Innocent    schedule 08.10.2018


Отговори (1)


Мисля, че трябва да приложите нещо, което да бъде по-устойчиво на промените в осветеността. вижте: Нормализиране на осветеността в OpenCV

След това, за да управлявате сходството между изображенията, може би можете да използвате нещо като анализ на главния компонент.

person user3529407    schedule 05.11.2014
comment
Защо -1, дадох ви някои техники за подобряване на степента на разпознаване при наличие на фактори, които могат да нарушат разпознаването. Използвал съм ги в подобен проект, за да бъдат по-здрави и работят страхотно. - person user3529407; 05.11.2014