31
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

OpenCVで顔認識など特徴ある領域の検出

Posted at

はじめに

前回の記事では、肌色部分の抽出を行いました。今度はもう少し一歩進んで、顔など特徴をもった領域の認識をさせてみたいと思います。

なをOpenCVを初めて使う方は、事前に以下の記事をご参考にして頂きAndroid向けのOpenCVのセットアップをお願いします

OpenCV CascadeClassifier

特徴を持った領域の認識には、CascadeClassifierというクラスを利用します。このクラスは、カスケードファイルという物体の特徴を記述したXMLファイルが必要になります。

CascadeClassifier(java.lang.String filename) 

カスケードファイルは、SDK内の以下のディレクトリにあります。
OpenCV-android-sdk/sdk/etc/libpcascades

今回は顔認識を致しますので、lbpcascade_frontalface.xmlというファイルを顔認識させるアプリケーションのres/rawにコピーしておいて下さい。

CascadeClassifierクラスを使用する前の準備

残念ながらCascadeClassifierクラスはリソースを読み込めず、ファイルを作成してファイルパスを指定する必要があります。よって、XMLの内容を事前にファイルに書き出す必要があります。今回は、setupCascadeFile()という以下のメソッドを作成して、特定ディレクトリ以下にカスケードファイルがない場合は作成するという実装をします。

    private File setupCascadeFile() {
            File cascadeDir = mContext.getDir("cascade", Context.MODE_PRIVATE);
            File cascadeFile = null;
            InputStream is = null;
            FileOutputStream os = null;
            try {
                cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
                if (!cascadeFile.exists()) {
                    is = mContext.getResources().openRawResource(R.raw.lbpcascade_frontalface);
                    os = new FileOutputStream(cascadeFile);
                    byte[] buffer = new byte[4096];
                    int readLen = 0;
                    while ((readLen = is.read(buffer)) != -1) {
                        os.write(buffer, 0, readLen);
                    }
                }
            } catch (IOException e) {
                return null;
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (Exception e) {
                        // do nothing
                    }
                }
                if (os != null) {
                    try {
                        os.close();
                    } catch (Exception e) {
                        // do nothing
                    }
                }
            }
            return cascadeFile;
        }

CascadeClassifierインスタンスの作成

上記のカスケードファイルが作成されれば、CascadeClassifierクラスのインスタンス化は容易です。ここでは、OpenCVライブラリの読み込み後に呼び出される、onManagerConntected()メソッド内でCascadeClassifierのインスタンス化を行います。

        private CascadeClassifier setupFaceDetector() {
            File cascadeFile = setupCascadeFile();
            if (cascadeFile == null) {
                return null;
            }

            CascadeClassifier detector = new CascadeClassifier(cascadeFile.getAbsolutePath());
            if (detector.empty()) {
                return null;
            }
            return detector;
        }

        @Override
        public void onManagerConnected(int status) {
            super.onManagerConnected(status);
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                    mCameraView.enableView();
                    mFaceDetector = setupFaceDetector();
                    break;
                default:
                    break;
            }
        }

顔領域の認識

上記のインスタンス化されたCascadeClassifierを利用して領域を認識します。検出には、以下のdetectMultiScaleというメソッドを用います。入力画像にはグレースケールが必要です。

public void detectMultiScale(Mat image,
                             MatOfRect objects,
                             double scaleFactor,
                             int minNeighbors,
                             int flags,
                             Size minSize,
                             Size maxSize)

上記のメソッドを用いて獲得された顔領域に枠で囲む例が以下になります。ここでは、最低の領域サイズを画面の縦サイズの1/5と仮にしています。

        @Override
        public void onCameraViewStarted(int width, int height) {
            if (mMinFaceSize == null) {
                mMinFaceSize = new Size(height / 5, height / 5);
            }
        }

        @Override
        public void onCameraViewStopped() {

        }

        @Override
        public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
            Mat rgba = inputFrame.rgba();
            if (mFaceDetector != null) {
                MatOfRect faces = new MatOfRect();
                mFaceDetector.detectMultiScale(inputFrame.gray(), faces, 1.1, 2, 2, mMinFaceSize,
                        new Size());
                Rect[] facesArray = faces.toArray();
                for (int i = 0; i < facesArray.length; i++) {
                    Imgproc.rectangle(rgba, facesArray[i].tl(), facesArray[i].br(), FACE_RECT_COLOR, 3);
                }
            }
            return rgba;
        }
    }
スクリーンショット 2015-11-15 22.30.04.png

顔以外の領域の認識

上記のカスケードファイルを変更すれば他の領域を検出することも可能。例えば、以下のサイトからカスケードファイル(aGest.xml)をダウンロードして使用すると、握りこぶしを認識するようになる。

31
39
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?