使用 OpenCV 进行不稳定的人脸识别
Posted
技术标签:
【中文标题】使用 OpenCV 进行不稳定的人脸识别【英文标题】:Unstable face recognition using OpenCV 【发布时间】:2014-01-23 02:04:09 【问题描述】:我正在使用JavaCV 开发一个用于人脸识别的安卓应用程序,它是 OpenCV 的非官方包装器。导入com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer
后,
我应用并测试了以下已知方法:
在识别检测到的人脸之前,我会校正旋转的人脸并裁剪适当的区域,灵感来自this method
一般来说,当我通过相机时,数据库中已经存在一张人脸,识别是可以的。但这并不总是正确的。有时它以很高的概率识别出未知人脸(未在训练样本数据库中找到)。当我们在 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 高 p > 70 可能预测错误结果。 中间 p 可以预测正确或错误。同样,我不明白为什么在使用 LBPH 的情况下 predict() 函数有时给出大于 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;
【问题讨论】:
是的,您需要 3 个不同的阈值,每种方法一个,因为它们的特征空间不同。此外,您在预测中的“p”值不是概率,而是从您的测试图像到数据库中最近找到的匹配的 距离(所以,有点相反),所以这不是完全在 [0..100] 范围内。 @berak 我们传递三个参数来预测 iplimage、int[]、double[]。好的,我们通过了 Iplimage,我们在 double[] 中得到了距离,但是 int[] 是什么?它代表什么。因为我不太了解它,所以我得到了不同的价值,比如 1,4,8。 这是类标签,你的人的 id。这段代码是你写的吗? dervish,你必须对你的数据进行测试。老实说,让代码运行是很容易的部分。优化结果才是真正的工作开始。 我同意 berak,您需要来自同一个人的适量不同图像,以便可以使用它来训练模型。最后预测更好。 【参考方案1】:我认为您需要实现一些对照明变化更加稳健的东西。见:Illumination normalization in OpenCV
然后,为了管理图像之间的相似性,也许您可以使用主成分分析之类的东西。
【讨论】:
为什么-1,我给了你一些技巧,在存在可能干扰识别的因素的情况下提高识别率。我已经在一个类似的项目中使用过它们,以便更加健壮并且它们工作得很好。以上是关于使用 OpenCV 进行不稳定的人脸识别的主要内容,如果未能解决你的问题,请参考以下文章