Android で OpenCV のサンプル face-detection を試す

[AndroidStudio で OpenCV をインポートする](https://qiita.com/ohwada/items/71eb18296aac46f9f5ee)
の続きです。

### 概要

Android 用 OpenCV　には、
８個のサンプルが同封されている。
そのうち face-detection　について、解説する。

### face-detection

顔検出機能の最もシンプルなサンプルです。

2つの実行モードがある。
- Java APIを使う
- Native API を使う

どちらも、カスケード型分類器 を使用する。

Java　API　でも、Google Nexus Oneデバイスでほぼリアルタイムのパフォーマンスを表示できる。

メニューは２通りある。
- 顔のサイズを選択
- Java / Native Detector の切り替え

### カスケード型分類器 (Cascade Classifier) 

特徴分類ファイル (Classifier File) を利用したオブジェクト検出器です。

機械学習のCNN(Convolutional Neural Networks)に比べ、
検出精度は劣るが演算は高速です。

- [opencv : オブジェクト検出](
https://docs.opencv.org/3.4/db/d28/tutorial_cascade_classifier.html)

- [opencv : カスケード型分類器 
Haar Feature-based Cascade Classifier]
(http://opencv.jp/opencv-2svn/c/objdetect_cascade_classification.html)

- [OpenCVを使った顔認識 (Haar-like特徴分類器) ](
https://qiita.com/hitomatagi/items/04b1b26c1bc2e8081427)

- [Whats the Difference Between Haar-Feature Classifiers and Convolutional Neural Networks](https://towardsdatascience.com/whats-the-difference-between-haar-feature-classifiers-and-convolutional-neural-networks-ce6828343aeb)


### 特徴分類ファイル (Classifier File)　

カスケード型分類器 のための特徴を記述した XML ファイルです。
sdk/etc/ ディレクトリに２種類の特徴分類ファイルが用意されている。

- haarcascades ディレクトリ
haar-like 特徴で学習した特徴分類ファイル
- lbpcascades ディレクトリ
Local Binary Patterns特徴で学習した特徴分類ファイル

lbpcascades ディレクトリに下記のファイルが用意されている。

- lbpcascade_frontalface.xml (正面 顔）
- lbpcascade_frontalface_improved.xml (正面 顔）
- lbpcascade_profileface.xml (右向き顔)
- lbpcascade_frontalcatface.xml(猫の正面顔)
- lbpcascade_silverware.xml (銀製食器)

特徴分類ファイルは、機械学習により作成することができる。

- [OpenCVで顔検出](http://www.yasutomo57jp.com/2012/09/17/opencv%E3%81%A7%E9%A1%94%E6%A4%9C%E5%87%BA/)

- [wikipedia : Haar-like feature](https://en.wikipedia.org/wiki/Haar-like_feature)

- [wikipedia : Local binary patterns](https://en.wikipedia.org/wiki/Local_binary_patterns)


### アプリを作成する


まず、下記の記事をお読みください。

- [AndroidStudio で OpenCV をインポートする](https://qiita.com/ohwada/items/71eb18296aac46f9f5ee)

- [Android　で OpenCV のサンプル camerapreview を試す](https://qiita.com/ohwada/items/53305d29f33bd14e6683)

- [Android　で OpenCV のサンプル mixedprocessing を試す](https://qiita.com/ohwada/items/6991e8e3a37d03149b16)

下記を参考にした。

- [OpenCVを使って、簡単顔認識Androidアプリを作ってみた](https://qiita.com/Kuroakira/items/094ecb236da89949d702)

(1) 新規のプロジェクトを作成する
File -> New -> New Project -> Empty Activity

(2) OpenCV の Android SDK をインポートする
File -> New -> Import Module

(3) 依存関係を設定する
 File -> Project Structure 

(4) opencv/build.gradle を修正する

(5) AndroidManifest にカメラのアクセス許可を追加する。

(6) レイアウトファイルに、JavaCamera2View　を配置する。

(7) MainActivity.java を作成する。
samples/f/Users/ohwada/Desktop/opencvーandroid_face-detection.txtace-detection/src/org/opencv/samples/tutorial2/FdActivity.javaを
app/src/main にコピーして、
MainActivity.java にリネームする。

(8) DetectionBasedTracker.java を作成する。
samples/face-detection/src/org/opencv/samples/tutorial2/DetectionBasedTracker.java を
app/src/main にコピーする。

(9) 特徴分類ファイルを配置する
sdk/etc/lbpcascades/lbpcascade_frontalface.xml を
app/src/main/res/raw にコピーする。

(10) native コードを作成する。
samples/face-detection/jni ディレクトリを
app/src/main にコピーして、
cpp にリネームする。
プロジェクトのファイル構成に合わせて変更する。


```DetectionBasedTracker_jni.cpp
/**
 * org_opencv_samples_facedetect を
 * jp_ohwada_android_opencv48 に変更する
 */

JNIEXPORT jlong JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeCreateObject
(JNIEnv * jenv, jclass, jstring jFileName, jint faceSize)

JNIEXPORT void JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeDestroyObject
(JNIEnv * jenv, jclass, jlong thiz)

JNIEXPORT void JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeStart
(JNIEnv * jenv, jclass, jlong thiz)

JNIEXPORT void JNICALL Java_org_opencv_samples_facedetect_DetectionBasedTracker_nativeStop
(JNIEnv * jenv, jclass, jlong thiz)
```

(11) app/build.gradleを変更する

```app/build.gradle

defaultConfig {
        ndk {
            abiFilters 'armeabi-v7a'
        }
        externalNativeBuild {
            cmake {
                arguments "-DOpenCV_DIR=" + project(':opencv').projectDir + "/native/jni",
"-DANDROID_TOOLCHAIN=clang",
"-DANDROID_STL=c++_shared"
                targets "detection_based_tracker"
            }

buildTypes {
    externalNativeBuild {
        cmake {
            // 変更する
            // path 'jni/CMakeLists.txt'
            path 'src/main/cpp/CMakeLists.txt'
        }
```

(12) cmake を修正する

(13) Makeする
Build -> Make Projec

### アプリ の処理の流れ

(1) アプリが起動すると、
CameraActivity#onStart が呼ばれる。
Activity#requestPermissions を実行して、
カメラのアクセス許可を要求する。

(2) Activity#onResume が呼ばれる。
setupDetector() にて、
res/rawフォルダーから 特徴分類ファイル　lbpcascade_frontalface.xml が読み込まれ、
 アプリごとのファイル領域にコピーされる。
コピーした特徴分類ファイルのファイルパスを指定して
CascadeClassifier が生成される

(3) Activity#onCameraFrame が呼ばれる。
CascadeClassifier#detect にて、顔検出する。
検出した顔の位置を示すMatOfRectが得られる。
Imgproc#rectangle にて、検出した顔の位置に四角形を描画する。


[opencv : Class MatOfRect](https://docs.opencv.org/master/javadoc/org/opencv/core/MatOfRect.html)


[opencv : Class CascadeClassifier](https://docs.opencv.org/master/javadoc/org/opencv/objdetect/CascadeClassifier.html)


[opencv : Imgproc#rectangle](https://docs.opencv.org/master/javadoc/org/opencv/imgproc/Imgproc.html#rectangle(org.opencv.core.Mat,org.opencv.core.Rect,org.opencv.core.Scalar,int,int))

### アプリを実行する


下記の３つが同封されていることが確認できる。
- libopencv_java4.so
- libc++_shared.so
- libdetection_based_tracker.so
![opencv49_analyze_apk.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/ac307c47-51cd-0669-5ce4-ce76e592e34c.png)

アプリが起動すると、
カメラのアクセス許可を要求する。
![opencv49_permission.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/2e70f5ed-901d-ad09-e37f-eff5ac299f5c.png)

スクリーンショット
検出した顔の位置に四角形を描画する
![opencv49_face_detect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/ab0f651a-d888-9cf6-4e22-9feea33fb313.png)

Native API を使うモードも試してみたが、
Java APIと目立った差がなかった。
Native API を使うメリットがよくわからん。

サンプルコードをgithub に公開した。
 https://github.com/ohwada/Android_Samples/tree/master/Opencv49

### おまけ : 猫の顔を検出する

特徴分類ファイルに、
haarcascade_frontalcatface.xml を使用する

![opencv51_cat_detect.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/307d059a-51f7-7246-febc-6b71b81fd251.png)

サンプルコードはこちら
 https://github.com/ohwada/Android_Samples/tree/master/Opencv51

### おまけ : 特徴分類ファイルを自作する

特徴分類ファイルは機械学習により作成できます。

実践例

- [OpenCVで猫検出 (モデル配布)](https://qiita.com/wellflat/items/c6ffae99be35cecc5680)

- [OpenCVを用いたカワウソ分類器作成奮闘記](https://blog.aidemy.net/entry/2018/05/21/210100)