Android の Camera2 API と　Mobile Vision API を使って 顔検出する

[Android の Mobile Vision API を使って 顔検出する](https://qiita.com/ohwada/items/34e98fa6f4c49bccfffb)
の続きです。

### 概要

前回の記事では、画像ファイルから顔検出した。
今回の記事では、カメラからの連続画像から顔検出する。

公式サンプルコードでは、カメラの制御に
Mobile Vision API の CamearaSource を使っている。

この記事では、CamearaSource と同様の機能を持つ Cameara2Source を自作する。

[reference: CameraSource](https://developers.google.com/android/reference/com/google/android/gms/vision/CameraSource)

[Android の Camera2 API を使って カメラのプレビュー画面を表示する](https://qiita.com/ohwada/items/7bb65a566114066c8ced)
にて紹介し下記のコードを参考にした

[Basic functionalities of both Camera1 API and Camera2 API with a Google Vision Face Detector added](https://github.com/EzequielAdrianM/Camera2Vision)

### カメラからの連続画像から顔検出する

画像ファイルから顔検出する場合は、Frame.Builder#setBitmap を使用した。

カメラからの連続画像から顔検出する場合は、Frame.Builder#setImageData を使用する。

[reference: Frame.Builder#setImageData](https://developers.google.com/android/reference/com/google/android/gms/vision/Frame.Builder.html#setImageData(java.nio.ByteBuffer,%20int,%20int,%20int))

画像は、NV21形式のバイト配列で指定する。

カメラからは YUV_420_888 形式で取得し、 NV21形式に変換する。

### ImageReader

カメラからの連続画像をキャプチャーするための ImageReader を生成する。

ImageReader の使い方は、下記の記事を参考に。
[Android の Camera2 API を使って 写真を撮る](https://qiita.com/ohwada/items/9943deb61b8883b12aac)


```
// YUV_420_888 形式の画像の大きさを取得する
    StreamConfigurationMap map = characteristics.get(
        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
    Size imagePreviewSize = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea());

// YUV_420_888 形式のImageReader を生成する
    ImageReade imageReaderPreview = ImageReader.newInstance( imagePreviewSizegetWidth(), imagePreviewSize.getHeight(), ImageFormat.YUV_420_888, 4);

// リスナーを設定する
    imageReaderPreview.setOnImageAvailableListener(previewAvailableListener, mBackgroundHandler);

// リスナー
    ImageReader.OnImageAvailableListener previewAvailableListener = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
    // 連続画像を FrameProcessor に渡す
            frameProcessor.setNextImage(reader.acquireNextImage());
        } 
    }; 
```

### FrameProcessor

カメラからの連続画像を受け取り FaceDetector に渡すためのクラスです。
基底となるクラスはないので、スクラッチから自作する。

```
class Camera2FrameProcessor implements Runnable {

    public void setNextImage(Image image ) {
        // カメラからの連続画像を受け取る
    }

    @Override
    public void run() {
        // 連続画像を FaceDetector に渡す
        detector.receiveFrame(outputFrame);
    }
}
```

### FaceTracker

FaceDetector から顔検出の結果を受け取るためのクラスです。
Tracker を継承して FaceTracker クラスを作成する。

[reference: Tracker](https://developers.google.com/android/reference/com/google/android/gms/vision/Tracker)

onUpdate に結果が入る。

```
class FaceTracker extends Tracker<Face> {

        @Override
        public void onUpdate(FaceDetector.Detections<Face> detectionResults, Face face) {
            // 顔検出の結果の処理
        }
}
```

### 検出した顔の上にランドマークを表示する

下記の記事と同じような処理を行う。
[Android の Camera2 API を使って 顔検出する](https://qiita.com/ohwada/items/94105a7ea134ab4d2734)

ViewGroup を継承した CameraSourcePreview を作成する。
CameraSourcePreview の子のビューとして、カメラのプレビュー画面を表示する TextureView とランドマークを表示するオーバーレイ用の View を作成する。

View の大きさに合うように、View と ImageReader の大きさの比率を求め、ランドマークの位置を調整する。

### スクリーンショット
![vision2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/64075/37b75417-f91d-d27f-c780-82581124507b.png)

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