Amazon RekognitionとJavaで作る顔認証アプリ

# はじめに

今回はAmazonのRekognitionという顔認識のサービスを使った簡単なアプリを作りたいと思います。顔認識と聞くと、難しいイメージがありますが、このRekoginitionを使うと簡単に作れちゃいますので、ぜひサンプルを通して使ってみてください。

記事内では抜粋したソースしか載せていないので、もし興味がある人は今回作ったソースを [ここ] (https://github.com/mr-hisa-child/RekognitionSample)に載せておきますので、参考にしてください。

# 前提

- AWSアカウントを持っていること。
- 「AmazonRekognitionFullAccess」のポリシーを持つIAMユーザのアクセスキー、シークレットキーが取得済みであること。

# 動作環境

- MacOS Mojave
- Java 8

# アプリ画面

今回作ったアプリの画面です。

![スクリーンショット_2019-03-19_10_21_24.png](https://qiita-image-store.s3.amazonaws.com/0/53830/a0055056-0fa1-7393-ba86-c8ca40ae1441.png)

# 開発の流れ

1. 比較元の画像（メタデータ）を格納するコレクションを作成
2. 比較元の画像をコレクションに格納
3. 認証時にカメラで撮影し、アップロード
4. 認証結果を表示

## コレクションを作成

```java:コレクション作成
ListCollectionsResult listCollectionsResult = rekognitionClient.listCollections(new ListCollectionsRequest());
if (!listCollectionsResult.getCollectionIds().contains(COLLECTION_ID)) {
    rekognitionClient.createCollection(new CreateCollectionRequest().withCollectionId(COLLECTION_ID));
}
```

単純にコレクションを作成するのではなく、なかったら作成するようにしています。

|Rekognition API|内容|
|:--|:--|
|[listCollections](https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/API_ListCollections.html)|コレクションの一覧を返却します。|
|[createCollection](https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/API_CreateCollection.html)|コレクションを作成します。|

## 比較元の画像をコレクションに格納

```java:比較元画像を格納
IndexFacesRequest indexFacesRequest = new IndexFacesRequest()
              .withCollectionId(COLLECTION_ID)
              .withExternalImageId(id)
              .withImage(new Image().withBytes(ByteBuffer.wrap(multipartFile.getBytes())));

IndexFacesResult indexFacesResult = rekognitionClient.indexFaces(indexFacesRequest);
```

|Rekognition API|内容|
|:--|:--|
|[indexFaces](https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/API_IndexFaces.html)|顔写真をコレクションに格納します。|

|プロパティ|説明|使用可能文字|
|:--|:--|:--|
|collectionId|作成したコレクション名|a-zA-Z0-9_.\-|
|externalImageId|任意のデータ|a-zA-Z0-9_.\-:|
|image|比較元画像（バイナリ）||

今回は、```externalImageId``` にユーザを一意に識別するIDを管理します。

## 認証時にカメラで撮影し、アップロード

```java
SearchFacesByImageRequest searchFacesByImageRequest = new SearchFacesByImageRequest()
          .withCollectionId(COLLECTION_ID)
          .withImage(new Image().withBytes(ByteBuffer.wrap(multipartFile.getBytes())))
          .withFaceMatchThreshold(90F)
          .withMaxFaces(1);

try {
    SearchFacesByImageResult searchFacesByImageResult = rekognitionClient.searchFacesByImage(searchFacesByImageRequest);
} catch (InvalidParameterException e) {
    // エラー処理
}
```
アップロードした画像から顔が認識できない場合は```InvalidParameterException```が発生しますので、注意してください。

|Rekognition API|内容|
|:--|:--|
|[searchFacesByImage](https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/API_SearchFacesByImage.html)|比較する顔写真を元にコレクションから検索します。|

|プロパティ|説明|使用可能文字|
|:--|:--|:--|
|collectionId|作成したコレクション名|a-zA-Z0-9_.\-|
|image|比較元画像（バイナリ）||
|faceMatchThreshold|類似度の閾値。デフォルトで70%||
|maxFaces|一致した顔の中から類似度が高い順に取得する件数||

今回のサンプルでは、類似度90%以上の中から最も類似度が高い１件を取得するようにしました。

## 認証結果を表示

SearchFacesByImageResultが以下の形式で取得できるので、その中から```externalFaceId```を取得します。

```json
{
   "FaceMatches": [ 
      { 
         "Face": { 
            "BoundingBox": { 
               "Height": number,
               "Left": number,
               "Top": number,
               "Width": number
            },
            "Confidence": number,
            "ExternalImageId": "string",  <-- これ
            "FaceId": "string",
            "ImageId": "string"
         },
         "Similarity": number
      }
   ],
   "FaceModelVersion": "string",
   "SearchedFaceBoundingBox": { 
      "Height": number,
      "Left": number,
      "Top": number,
      "Width": number
   },
   "SearchedFaceConfidence": number
}
```
画面で入力したIDと一致したら認証OKで、それ以外はNGとします。


# 参考サイト

- [Amazon Rekognitionで顔認証してみた](https://qiita.com/OMOIKANESAN/items/c5d1dfe5c00105739dcf)