OpenCVの非公式なラッパーであるJavaCVを使用して、顔認識のためのアンドロイドアプリケーションを開発しています。OpenCVを使用した不安定な顔認識
- LBPH使用createLBPHFaceRecognizer()メソッド
- FisherFace使用createFisherFaceRecognizer()メソッド
- 固有顔createEigenFaceRecognizerを使用して()メソッド
:com.googlecode.javacv.cpp.opencv_contrib.FaceRecognizer
、 をインポートした後、私は、次の既知の方法を適用してテスト検出された顔を認識する前に、回転した顔を修正して適切な領域を切り抜いて、this method
一般的に、私がカメラに乗るとき、顔はすでにデータベースに存在していますが、認識はOKです。しかし、これは必ずしも正しいとは限りません。時には、未知の顔(訓練されたサンプルのデータベースには見つかりません)が高い確率で認識されることがあります。 DBに2つ以上の同様の機能(ひげ、口髭、眼鏡など)の顔があると、顔の認識が間違っている可能性があります。
試験顔画像を使用して結果を予測するために、私は、次のコードを適用する。ので、私は、確率pのしきい値を制御することができない
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 < 50は正しい結果を予測することができた。
- 高いp> 70は、誤った結果を予測する可能性があります。
- 中pは、正しいか誤っているかを予測できます。
また、私はpredict()関数がLBPHを使用している場合に100を超える確からしい確率を与える理由を理解していませんか?フィッシャーとエイゲンの場合、それは非常に大きな値を与える(> 2000)? 誰かがこのような奇妙な問題の解決策を見つける手助けをすることができますか? 認識の堅牢性を改善する提案はありますか?特に2つの異なる顔の類似性の場合には、
以下が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つの異なる*しきい値は、それぞれの方法ごとに1つずつ必要です。それらのすべての機能スペースが異なるからです。また、予測の 'p'値は確率ではありませんが、テスト画像からdb内の最も近い一致までの距離*(したがって、その逆数)は、[[ 0.001]の範囲である。 – berak
@berak私は、iplimage、int []、double []を予測するために3つのパラメータを渡します。さて、私たちはIplimageを渡し、距離は二倍になりましたが、int []は何ですか?それが表すもの。私はそれを本当に理解していないので、私は1,4,8のようにそれに異なる価値を得ています。 – umerk44
これはあなたの人のIDであるクラスラベルです。あなたはそのコードを書いたのですか? – berak