TOP 顔認識 機械学習 Eigenfaces

OpenCV for Android

Eigenfaces

顔識別技術としてEigenfacesを使ってみる。

顔1=基準顔1×変数A+基準顔2×変数B+基準顔3×変数C+・・・のような感じで、すべての入力した顔写真を変数の組み合わせで作れるようにして、変数の近さで顔を識別する。

Microsoft Visual StudioでEigenfacesのサンプルプログラムをビルドする。

顔画像は27人28枚を使用した。


画像ファイルリストは以下のフォーマットで、セミコロンの後ろに、人物のIDをつける。同じ番号であれば同じ人物の写真であることを示す。最後の26_1.jpgと26_2.jpgのみ、同一人物で異なる写真。最後の写真1枚(26_2.jpg)はトレーニングに使用されず、テストに使われる。
./faces/000_1.jpg;0
./faces/001_1.jpg;1
./faces/002_1.jpg;2
./faces/003_1.jpg;3
./faces/004_1.jpg;4
./faces/005_1.jpg;5
./faces/006_1.jpg;6
./faces/007_1.jpg;7
./faces/008_1.jpg;8
./faces/009_1.jpg;9
./faces/010_1.jpg;10
./faces/011_1.jpg;11
./faces/012_1.jpg;12
./faces/013_1.jpg;13
./faces/014_1.jpg;14
./faces/015_1.jpg;15
./faces/016_1.jpg;16
./faces/017_1.jpg;17
./faces/018_1.jpg;18
./faces/019_1.jpg;19
./faces/020_1.jpg;20
./faces/021_1.jpg;21
./faces/022_1.jpg;22
./faces/023_1.jpg;23
./faces/024_1.jpg;24
./faces/025_1.jpg;25
./faces/026_1.jpg;26
./faces/026_2.jpg;26

実行コマンドは以下。outputは出力ファイルフォルダ。

D:¥ドキュメント¥Visual Studio 2015¥Projects¥eigenfaces¥x64¥Debug>eigenfaces.exe facelist.txt output
Predicted class = 26 / Actual class = 26.
Eigenvalue #0 = 11450386.23945
Eigenvalue #1 = 5581722.32239
Eigenvalue #2 = 3671017.20937
Eigenvalue #3 = 2693774.57220
Eigenvalue #4 = 2088823.91652
Eigenvalue #5 = 1465460.40608
Eigenvalue #6 = 1345912.99003
Eigenvalue #7 = 1168820.11379
Eigenvalue #8 = 1029193.83296
Eigenvalue #9 = 897022.50187

トレーニングで使用していない26番の写真026_2.jpgが、26番として認識成功している。

OpenCV for Androidをソースからビルドする

WindowsでEigenfacesの動作を確認できたが、OpenCVのAndroidパッケージはExtra moduleを含まないので、Androidでfaceモジュールを使うためには、ソースからAndroid用にビルド(Windows OS上で、Android OS用にクロスコンパイル)する必要がある。

Camera2BasicのOpenCVライブラリを差し替える

ソースからビルドしたライブラリに差し替える。

EigenFaceRecognizer

まずトレーニング画像とラベルを定義する。

    private static final int IMAGENUM = 26;
    List<Mat> sourceimages = new ArrayList<Mat>(IMAGENUM);
    static String[] labelstr={"省略",・・・};
    static int[] labelint = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25};

onCreate()に以下追加。drawableリソースから顔画像を取得し、グレー画像に変更する。ここで、BitmapFactory.decodeResourceで読み込むと画像サイズが元ファイルとは変わることがあるので、resizeする必要がある。さらに、normalizeが必要。normalizeしないと画像どうしの明るさの差に影響されて正常にトレーニングできない。また、トレーニング画像は事前にカスケード分類器で顔認識される枠サイズにトリミングしておく。

        Mat srcmat = new Mat();
        Mat srcmatgray = new Mat();
        Mat srcmatgray100 = new Mat();
        int[] imageid={R.drawable.p000_1,R.drawable.p003_1,R.drawable.p004_1,R.drawable.p005_1,
                R.drawable.p006_1,R.drawable.p007_1,R.drawable.p008_1,R.drawable.p010_1,R.drawable.p011_1,
                R.drawable.p012_1,R.drawable.p013_1,R.drawable.p014_1,R.drawable.p015_1,R.drawable.p016_1,R.drawable.p017_1,
                R.drawable.p018_1,R.drawable.p019_1,R.drawable.p020_1,R.drawable.p021_1,R.drawable.p022_1,R.drawable.p023_1,
                R.drawable.p024_1,R.drawable.p025_1,R.drawable.p026_1,R.drawable.p027_1,R.drawable.p028_1};
        Mat labels = new Mat(1,IMAGENUM,CvType.CV_32SC1);
        org.opencv.core.Size sz = new org.opencv.core.Size(EIGENFACEX,EIGENFACEY);
        int count=0;
        for (int id:imageid) {
            Utils.bitmapToMat(BitmapFactory.decodeResource(getResources(), id), srcmat);
            Imgproc.cvtColor(srcmat, srcmatgray, Imgproc.COLOR_BGR2GRAY);
            Imgproc.resize(srcmatgray, srcmatgray100, sz);
            Core.normalize(srcmatgray100, srcmatgray100, 0,255, Core.NORM_MINMAX);
            sourceimages.add(new Mat());
            srcmatgray100.copyTo(sourceimages.get(count));
            count=count+1;
        }
        labels.put(0,0,labelint);
        model = EigenFaceRecognizer.create();
        model.train(sourceimages, labels);

カスケード分類器で顔の枠を取得後、以下のように枠を抜き出してFaceRecognizerでテストする。ここでもnormalizeする。これでlabel[0]にEigenfacesによる顔の識別結果が入る。

        int fx,fy,fw,fh;
        fx=(int)facesArray[i].tl().x;
        fy=(int)facesArray[i].tl().y;
        fw=(int)(facesArray[i].br().x-facesArray[i].tl().x);
        fh=(int)(facesArray[i].br().y-facesArray[i].tl().y);
        Mat face0 = new Mat(rgbamat, new Rect(fx,fy,fw,fh));
        Mat face100 = new Mat(EIGENFACEX,EIGENFACEY,CvType.CV_8UC4);
        Mat face100gray = new Mat(EIGENFACEX,EIGENFACEY,CvType.CV_8UC1);
        org.opencv.core.Size sz = new org.opencv.core.Size(EIGENFACEX,EIGENFACEY);
        Imgproc.resize(face0, face100, sz);
        Imgproc.cvtColor(face100,face100gray,Imgproc.COLOR_RGB2GRAY);
        Core.normalize(face100gray, face100gray, 0,255, Core.NORM_MINMAX);
        int[] label={99,0};
        double[] confidence={0.0,0.0};
        model.predict(face100gray, label, confidence);

有名人の写真26枚をトレーニング画像に使い、PCに適当なフリー素材写真を表示して、ビルドしたアプリでリアルタイム認識している結果が下のキャプチャ。パーセント値は適当。confidence[0]の値は該当人物の写真までのdistanceで、完全一致でゼロだが、完全間違いの数値は難しくて不明。フリー素材の人物はトレーニングに入れてないので、一番近い有名人が表示される。取り込んだ有名人の写真そのものをPCに表示して認識させると、26人ほぼ常時正しく認識する。どちらかというと、識別を間違える瞬間はカスケード分類器の顔認識枠がずれるのが原因。


TOP 顔認識 機械学習 Eigenfaces