使用OpenCV的不稳定人脸识别
2022-09-02 02:04:53
						我正在开发一个用于人脸识别的Android应用程序,使用JavaCV,它是OpenCV的非官方包装器。导入后,我应用并测试以下已知方法:com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer
- LBPH 使用 createLBPHFaceRecognizer() 方法
 - FisherFace using createFisherFaceRecognizer() method
 - 使用 createEigenFaceRecognizer() 方法的 EigenFace
 
在我识别检测到的人脸之前,我纠正了旋转的脸并裁剪了适当的区域,从这种方法中汲取灵感
一般来说,当我在相机上传递数据库中已经存在的人脸时,识别是可以的。但这并不总是正确的。有时它以很高的概率识别未知的人脸(在训练样本数据库中找不到)。当我们在DB中有两张或更多张具有相似特征的面孔(胡须,胡须,眼镜......)时,这些面孔之间的识别可能会有很大的误区!
为了使用测试人脸图像预测结果,我应用以下代码:
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()函数在使用LBPH的情况下有时会给出大于100的概率???在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;
    }
}