Reconocimiento de rostro inestable con OpenCV

Estoy desarrollando una aplicación android para el reconocimiento facial, usando JavaCV que es un contenedor no oficial de OpenCV. Después de importar com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer , aplico y compruebo los siguientes métodos conocidos:

  • LBPH usando el método createLBPHFaceRecognizer ()
  • FisherFace usando el método createFisherFaceRecognizer ()
  • EigenFace utilizando el método createEigenFaceRecognizer ()

Antes de reconocer el rostro detectado, corro el rostro girado y recorte la zona apropiada, inspirándome de este método

En general, cuando paso la cámara ya existe un rostro en la base de datos, el reconocimiento está bien. Pero esto no siempre es correcto. A veces se reconoce la cara desconocida (no se encuentra en la base de datos de muestras entrenadas) con una alta probabilidad. Cuando tenemos en el DB dos o más caras de características similares (barba, bigote, anteojos …) ¡el reconocimiento puede estar muy equivocado entre esas caras!

Para predecir el resultado usando la imagen de cara de prueba, aplico el código siguiente:

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

No puedo controlar el umbral de la probabilidad p, porque:

  • Pequeño p <50 podría predecir un resultado correcto.
  • Alto p> 70 podría predecir un resultado falso.
  • La media p podría predecir una correcta o falsa.

Además, no entiendo por qué la función predict () da alguna vez una probabilidad mayor de 100 en caso de usar LBPH ??? Y en el caso de Fisher y Eigen da valores muy grandes (> 2000) ?? ¿Puede alguien ayudar a encontrar una solución para estos problemas extraños? ¿Hay alguna sugerencia para mejorar la robustez del reconocimiento? Especialmente en caso de similitud de dos caras diferentes.

La siguiente es la clase completa usando 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; } } 

Creo que necesitas implementar algo para ser más robusto a los cambios de iluminación. Ver: La normalización de la iluminación en OpenCV

Entonces, con el fin de manejar la similitud entre las imágenes tal vez se puede utilizar algo como Análisis de componentes principales.

El contenedor oficial de Java de OpenCV no incluye métodos de coincidencia de rostros (sólo incluye detección de rostros):

  • LBPH usando el método createLBPHFaceRecognizer ()
  • FisherFace usando el método createFisherFaceRecognizer ()
  • EigenFace utilizando el método createEigenFaceRecognizer ()

En su lugar, debe utilizar el contenedor JavaCV para utilizar el reconocimiento facial.

Además, para tener un reconocimiento facial eficaz, debe realizar una buena base de datos de formación. Siga este práctico tutorial si desea obtener más información al respecto.

  • Detección de diferentes formas dinámicamente como (Círculo, cuadrado y Rectángulo) de la cámara?
  • Android OpenCV Encuentra la plaza o rectángulo más grande
  • OpenCV con Android NDK Referencias indefinidas
  • Dilatación y erosión en Android
  • Correspondencia de plantillas en Android usando openCV
  • Android - alternativa para OpenCV?
  • Filtrado de MatOfDMatch
  • Configurar el modo de escena de la cámara para OpenCV en Android
  • Abrir muestra de muestras de CV para OpenCV Manager descargar
  • Android OpenCV Mejora de la calidad de detección
  • Cómo detectar los límites de una página de pasaporte con OpenCV?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.