【问题标题】:Improve Face Recognition提高人脸识别
【发布时间】:2014-05-15 13:31:53
【问题描述】:

我正在尝试在 android 中开发人脸识别应用程序。我正在使用 JavaCv FaceRecognizer。但到目前为止,我的结果很差。它可以识别受过训练的人的图像,但它也可以识别未知图像。对于已知的面孔,它给了我很大的距离值,大部分时间在 70-90 之间,有时是 90+,而未知图像也得到 70-90。

那么如何提高人脸识别的性能呢?有哪些技巧?正常情况下,您可以获得多少成功率?

我从未从事过图像处理工作。我将不胜感激任何指导方针。

代码如下:

 public  class PersonRecognizer {

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

     static  final int WIDTH= 70;
     static  final int HEIGHT= 70;
     private static final String TAG = "PersonRecognizer";
     private int mProb=999;


    PersonRecognizer(String path)
    {
      faceRecognizer =  com.googlecode.javacv.cpp.opencv_contrib.createLBPHFaceRecognizer(2,8,8,8,100);
     // 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);

        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 = 0;
            try
            {
               icount=Integer.parseInt(p.substring(i2+1,i3)); 
            }
            catch(Exception ex)
            {
                ex.printStackTrace();
            }
            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];
        //conver Mat to black and white
        /*Mat gray_m = new Mat();
        Imgproc.cvtColor(m, gray_m, Imgproc.COLOR_RGBA2GRAY);*/
        IplImage ipl = MatToIplImage(m, WIDTH, HEIGHT);

        faceRecognizer.predict(ipl, n, p);

        if (n[0]!=-1)
        {
         mProb=(int)p[0];
         Log.v(TAG, "Distance = "+mProb+"");
         Log.v(TAG, "N = "+n[0]);
        }
        else
        {
            mProb=-1;
            Log.v(TAG, "Distance = "+mProb);
        }



        if (n[0] != -1)
        {
            return labelsFile.get(n[0]);
        }
        else
        {
            return "Unknown";
        }
    }




      IplImage MatToIplImage(Mat m,int width,int heigth)
      {
          Bitmap bmp;

         try
         {
           bmp = Bitmap.createBitmap(m.width(), m.height(), Bitmap.Config.RGB_565);
         }
         catch(OutOfMemoryError er)
         {
             bmp = Bitmap.createBitmap(m.width()/2, m.height()/2, Bitmap.Config.RGB_565);
             er.printStackTrace();

         }

           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;
    }


    }

【问题讨论】:

  • 我猜你在这里不会得到好的答案。人脸识别是困难,人们已经写了关于这个主题的博士学位。您最好搜索各种 OpenCV 邮件列表和讨论论坛,而不是在这里询问目标受众主要是程序员。因此,这并不是一个真正的“编程”问题,而是一个关于如何将 openCV 的“魔力”应用于特定问题的问题。
  • @berak 是的,我已经尝试过了,但没有取得任何可衡量的成功。
  • 您可以使用替代方案,例如 face++ API。
  • 从数学的角度来看,为什么不增加图像来训练模型。您说它可以很好地识别已知图像,那么为什么不将它们中的大多数设为已知图像呢?当然,这种方法的可行性将取决于您用于检测的模型。
  • 你用了多少训练图像?

标签: opencv image-processing javacv


【解决方案1】:

我最近遇到了类似的挑战,以下是帮助我取得更好成绩的事情:

  1. 从图像中裁剪人脸 - 这将在推理时删除不必要的像素
  2. 调整裁剪的人脸图像的大小 - 这会影响检测人脸地标,在测试集上尝试不同的比例以了解最有效的方法。此外,这也会影响推理时间,尺寸越小,推理速度越快。
  3. 提高人脸图像的亮度 - 我发现这真的很有帮助,在较暗的图像中检测人脸地标并不太好,这主要是由于该模型预先训练了大多数白脸 -了解训练数据将有助于处理偏见。
  4. 转换为灰度图像 - 我在很多论坛上都看到过,并说,这将有助于有效地找到边缘 - 与彩色图像(3 通道 -RGB)相比,处理时间更短 -但是,这并没有太大帮助。
  5. 尝试以不同的角度、光照和其他变化为单个人捕获(注册)尽可能多的图像 - 这确实有助于与存储图像的编码进行比较。
  6. 尝试实现1-1比对进行人脸验证 - 例如,在我的系统中,我为每个人拍摄了10张图片,在验证时,我正在与10张图片进行比较,而不是存储在系统中的所有人员的所有编码。这将提供误报,但此设置中的用例有限,我将其用于人脸身份验证,并将新人脸与手机号码相同的现有人脸进行比较。

到目前为止,我的理解是,人脸识别系统效果很好,但不是 100% 准确,我们必须了解模型架构、训练数据和我们的要求并相应地部署它才能获得更好的结果。以下是帮助我改进整个系统的几点:

  1. 实施后备方法 - 为用户提供选项,当我们的系统未能正确检测到他们时,例如,如果面部身份验证由于某种原因失败,则显示他们输入 PIN 选项
  2. 在关键系统中 - 添加定期 人工干预 以确认系统结果 - 例如,如果系统根据 FR 结果不允许用户 - 与人工代理验证失败结果并允许用户
  3. 实施多种身份验证因素 - 将人脸识别系统部署为现有系统的补充 - 例如,在用户使用凭据登录后 - 使用人脸识别系统验证其目标人
  4. 以某种方式设计您的用户界面,在验证时,用户应该如何表现如睁眼、闭嘴等,而不影响用户体验
  5. 向用户提供明确的指示,当他们与系统打交道时 - 例如,让用户知道,FR 系统集成,他们需要在良好的照明条件下露脸等。李>

【讨论】:

    猜你喜欢
    • 2012-03-18
    • 2011-12-14
    • 1970-01-01
    • 2020-10-18
    • 2018-06-14
    • 2015-03-25
    • 2014-10-30
    • 2018-06-28
    • 2023-03-06
    相关资源
    最近更新 更多