めちゃくちゃ簡単　Amazon Rekognition

AIとか画像解析とか聞くとなんか難しそうだけど、Amazonが提供しているサービスを使うと簡単に実装できるので、試してみた！

## Amazon Rekognitionとは
Amazon Rekognition では、イメージ分析とビデオ分析をアプリケーションに簡単に追加することができます。Amazon Rekognition API にイメージやビデオを指定するだけで、このサービスによってモノ、人物、テキスト、シーン、アクティビティを識別できます。不適切なコンテンツも検出できます。また、Amazon Rekognition では、高精度な顔分析および顔認識も可能です。顔の検出、分析、比較は、ユーザー検証、カタログ作成、人数計数、公共安全など、多岐にわたって活用できます。

## ひとまず実装してみる
環境を作成するのが手間なのでLambdaを使って実装。
プログラムはLambdaで提供があるPython 3.7。

### 顔認識
人物が写っている2枚の写真から同一人物かどうかを判定する。
S3にアップされている写真を比較するサンプルプログラム。

```Python
from boto3 import Session

def lambda_handler(event, context):
    session = Session(region_name="ap-northeast-1")
    rekognition = session.client("rekognition")
    
    response=rekognition.compare_faces(
        SourceImage={'S3Object':{'Bucket':"XXXXX",'Name':"XXXXX"}},
        TargetImage={'S3Object':{'Bucket':"XXXXX",'Name':"XXXXX"}},
        SimilarityThreshold=80)

    return response
```

簡単にプログラムの解説。

```python
from boto3 import Session
```
AWSの各種サービスを簡単に仕様できるライブラリboto3を使って実装。
※ライブライはC++、Go、Java、JavaScript,.Net、Node.js、PHP、Rubyがある

```python
    session = Session(region_name="ap-northeast-1")
    rekognition = session.client("rekognition")
```
サービスを使用するためには必ずSessionというAWSとの接続情報が必要。
リージョンはアジア東京を指定。
rekognitionを使用するためのオブジェクト取得。


```python
    response=rekognition.compare_faces(
        SourceImage={'S3Object':{'Bucket':"XXXXX",'Name':"XXXXX"}},
        TargetImage={'S3Object':{'Bucket':"XXXXX",'Name':"XXXXX"}},
        SimilarityThreshold=80)
```

これがAmazonから提供されている「顔認証」関数。
API仕様 [こちらから](https://docs.aws.amazon.com/rekognition/latest/dg/API_CompareFaces.html)

SourceImageに認識したい顔だけが写っている写真
TargetImageに解析したい写真
SimilarityThresholdに認識度。高いほど厳しいチェックになる。0-100で指定。

responseは
FaceMatches に同一人物を判断した顔の情報
UnmatchedFaces　に違うと判断した顔の情報

Confidenceがその判断の信頼度

```json
{
  "SourceImageFace": {
    "BoundingBox": {
      "Width": 0.30209746956825256,
      "Height": 0.21446102857589722,
      "Left": 0.319732129573822,
      "Top": 0.23807010054588318
    },
    "Confidence": 99.99998474121094
  },
  "FaceMatches": [
    {
      "Similarity": 99.37952423095703,
      "Face": {
        "BoundingBox": {
          "Width": 0.21386872231960297,
          "Height": 0.16094279289245605,
          "Left": 0.6417301297187805,
          "Top": 0.6225799322128296
        },
        "Confidence": 99.99987030029297,
        "Landmarks": [
          {
            "Type": "eyeLeft",
            "X": 0.7082532644271851,
            "Y": 0.6811327934265137
          },
          {
            "Type": "eyeRight",
            "X": 0.7683542370796204,
            "Y": 0.7155389189720154
          },
          {
            "Type": "mouthLeft",
            "X": 0.6812899112701416,
            "Y": 0.7383925914764404
          },
          {
            "Type": "mouthRight",
            "X": 0.7310847640037537,
            "Y": 0.7682420015335083
          },
          {
            "Type": "nose",
            "X": 0.6889581680297852,
            "Y": 0.7370006442070007
          }
        ],
        "Pose": {
          "Roll": 38.84079360961914,
          "Yaw": -19.29507827758789,
          "Pitch": -41.210079193115234
        },
        "Quality": {
          "Brightness": 44.140357971191406,
          "Sharpness": 78.64350128173828
        }
      }
    }
  ],
  "UnmatchedFaces": [
    {
      "BoundingBox": {
        "Width": 0.01333685964345932,
        "Height": 0.013453098013997078,
        "Left": 0.9252238869667053,
        "Top": 0.4759874939918518
      },
      "Confidence": 97.7153091430664,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.9277710914611816,
          "Y": 0.4811204969882965
        },
        {
          "Type": "eyeRight",
          "X": 0.933621883392334,
          "Y": 0.4823104441165924
        },
        {
          "Type": "mouthLeft",
          "X": 0.9270203113555908,
          "Y": 0.4870522618293762
        },
        {
          "Type": "mouthRight",
          "X": 0.931785523891449,
          "Y": 0.4880983531475067
        },
        {
          "Type": "nose",
          "X": 0.9278116226196289,
          "Y": 0.484792023897171
        }
      ],
      "Pose": {
        "Roll": 13.193720817565918,
        "Yaw": -30.132854461669922,
        "Pitch": -10.473925590515137
      },
      "Quality": {
        "Brightness": 75.9936752319336,
        "Sharpness": 73.32209777832031
      }
    },
    {
      "BoundingBox": {
        "Width": 0.2887393832206726,
        "Height": 0.32251936197280884,
        "Left": 0.1142626702785492,
        "Top": 0.45462948083877563
      },
      "Confidence": 99.99995422363281,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.1551831066608429,
          "Y": 0.5991319417953491
        },
        {
          "Type": "eyeRight",
          "X": 0.25697842240333557,
          "Y": 0.6217619776725769
        },
        {
          "Type": "mouthLeft",
          "X": 0.14137881994247437,
          "Y": 0.7185965180397034
        },
        {
          "Type": "mouthRight",
          "X": 0.22245647013187408,
          "Y": 0.7383744716644287
        },
        {
          "Type": "nose",
          "X": 0.14210543036460876,
          "Y": 0.6684256792068481
        }
      ],
      "Pose": {
        "Roll": 17.434614181518555,
        "Yaw": -41.510498046875,
        "Pitch": -21.136119842529297
      },
      "Quality": {
        "Brightness": 41.628482818603516,
        "Sharpness": 95.51618957519531
      }
    },
    {
      "BoundingBox": {
        "Width": 0.007370786275714636,
        "Height": 0.008144599385559559,
        "Left": 0.6609883904457092,
        "Top": 0.49813687801361084
      },
      "Confidence": 83.50224304199219,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.6622864603996277,
          "Y": 0.5042642951011658
        },
        {
          "Type": "eyeRight",
          "X": 0.6650356650352478,
          "Y": 0.5022475719451904
        },
        {
          "Type": "mouthLeft",
          "X": 0.6650884747505188,
          "Y": 0.5060529112815857
        },
        {
          "Type": "mouthRight",
          "X": 0.6673902273178101,
          "Y": 0.5043438076972961
        },
        {
          "Type": "nose",
          "X": 0.6656265258789062,
          "Y": 0.505027174949646
        }
      ],
      "Pose": {
        "Roll": -43.10660934448242,
        "Yaw": -4.3733038902282715,
        "Pitch": -33.09136962890625
      },
      "Quality": {
        "Brightness": 73.02571868896484,
        "Sharpness": 53.330047607421875
      }
    },
    {
      "BoundingBox": {
        "Width": 0.009758301079273224,
        "Height": 0.010332607664167881,
        "Left": 0.966498851776123,
        "Top": 0.46405404806137085
      },
      "Confidence": 61.05154037475586,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.9691260457038879,
          "Y": 0.4726991653442383
        },
        {
          "Type": "eyeRight",
          "X": 0.9677429795265198,
          "Y": 0.4707190990447998
        },
        {
          "Type": "mouthLeft",
          "X": 0.9723362326622009,
          "Y": 0.4712704122066498
        },
        {
          "Type": "mouthRight",
          "X": 0.9711670279502869,
          "Y": 0.4696311056613922
        },
        {
          "Type": "nose",
          "X": 0.9699736833572388,
          "Y": 0.4713567793369293
        }
      ],
      "Pose": {
        "Roll": -119.80672454833984,
        "Yaw": -8.657889366149902,
        "Pitch": 21.94735336303711
      },
      "Quality": {
        "Brightness": 84.52898406982422,
        "Sharpness": 73.32209777832031
      }
    },
    {
      "BoundingBox": {
        "Width": 0.018424568697810173,
        "Height": 0.020794881507754326,
        "Left": 0.7489200830459595,
        "Top": 0.47518208622932434
      },
      "Confidence": 87.87468719482422,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.7618342638015747,
          "Y": 0.48698189854621887
        },
        {
          "Type": "eyeRight",
          "X": 0.7628127336502075,
          "Y": 0.4866960644721985
        },
        {
          "Type": "mouthLeft",
          "X": 0.7631105184555054,
          "Y": 0.4888738989830017
        },
        {
          "Type": "mouthRight",
          "X": 0.7637985944747925,
          "Y": 0.4886566698551178
        },
        {
          "Type": "nose",
          "X": 0.7641363143920898,
          "Y": 0.48711803555488586
        }
      ],
      "Pose": {
        "Roll": -34.46097946166992,
        "Yaw": 60.46308135986328,
        "Pitch": -14.032490730285645
      },
      "Quality": {
        "Brightness": 67.51453399658203,
        "Sharpness": 83.14741516113281
      }
    },
    {
      "BoundingBox": {
        "Width": 0.011087420396506786,
        "Height": 0.011487020179629326,
        "Left": 0.9760779142379761,
        "Top": 0.4641396105289459
      },
      "Confidence": 97.86558532714844,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.978825032711029,
          "Y": 0.469203919172287
        },
        {
          "Type": "eyeRight",
          "X": 0.9811084270477295,
          "Y": 0.4689272344112396
        },
        {
          "Type": "mouthLeft",
          "X": 0.9797573685646057,
          "Y": 0.47199031710624695
        },
        {
          "Type": "mouthRight",
          "X": 0.9815858006477356,
          "Y": 0.47177186608314514
        },
        {
          "Type": "nose",
          "X": 0.979856014251709,
          "Y": 0.47067731618881226
        }
      ],
      "Pose": {
        "Roll": -11.149984359741211,
        "Yaw": -42.128475189208984,
        "Pitch": -1.7187515497207642
      },
      "Quality": {
        "Brightness": 79.50706481933594,
        "Sharpness": 73.32209777832031
      }
    },
    {
      "BoundingBox": {
        "Width": 0.008290473371744156,
        "Height": 0.009163682349026203,
        "Left": 0.6165273785591125,
        "Top": 0.5080556273460388
      },
      "Confidence": 73.62310791015625,
      "Landmarks": [
        {
          "Type": "eyeLeft",
          "X": 0.6195554137229919,
          "Y": 0.5123717188835144
        },
        {
          "Type": "eyeRight",
          "X": 0.6210446357727051,
          "Y": 0.5128311514854431
        },
        {
          "Type": "mouthLeft",
          "X": 0.6189116835594177,
          "Y": 0.5142983794212341
        },
        {
          "Type": "mouthRight",
          "X": 0.6200852394104004,
          "Y": 0.5146732926368713
        },
        {
          "Type": "nose",
          "X": 0.6193997263908386,
          "Y": 0.5135700702667236
        }
      ],
      "Pose": {
        "Roll": 20.73882293701172,
        "Yaw": -33.038211822509766,
        "Pitch": -11.055394172668457
      },
      "Quality": {
        "Brightness": 41.28157424926758,
        "Sharpness": 67.22731018066406
      }
    }
  ],
  "ResponseMetadata": {
    "RequestId": "d638e263-eeb5-4cbf-807d-aa6328f8096b",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "content-type": "application/x-amz-json-1.1",
      "date": "Thu, 19 Dec 2019 12:20:36 GMT",
      "x-amzn-requestid": "d638e263-eeb5-4cbf-807d-aa6328f8096b",
      "content-length": "5545",
      "connection": "keep-alive"
    },
    "RetryAttempts": 0
  }
}
```

#### 導入事例
千株式会社の写真販売サービス｢はいチーズ｣。幼稚園や保育園でのイベントの写真販売の際に、スマホから｢自分の子どもが映った写真｣だけを選んで抽出できるサービスを提供。

### テキスト検出

```Python
from boto3 import Session

def lambda_handler(event, context):
    session = Session(region_name="ap-northeast-1")
    rekognition = session.client("rekognition")

    response=rekognition.detect_text(Image={'S3Object':{'Bucket':"XXXXX",'Name':"XXXXX"}})
    
    return response
```

簡単にプログラムの解説。

```python
from boto3 import Session
```

AWSの各種サービスを簡単に仕様できるライブラリboto3を使って実装。
※ライブライはC++、Go、Java、JavaScript,.Net、Node.js、PHP、Rubyがある

```python
    session = Session(region_name="ap-northeast-1")
    rekognition = session.client("rekognition")
```
サービスを使用するためには必ずSessionというAWSとの接続情報が必要。
リージョンはアジア東京を指定。
rekognitionを使用するためのオブジェクト取得。


```python
    response=rekognition.detect_text(Image={'S3Object':{'Bucket':"XXXXX",'Name':"XXXXX"}})
```

これがAmazonから提供されている「テキスト検出」関数。
API仕様 [こちらから](https://docs.aws.amazon.com/rekognition/latest/dg/API_DetectText.html)

Imageに解析したい画像を渡すだけ。

![demo2_car.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/79214/b117617c-18c0-f531-a0f2-593000628b09.jpeg)

この画像を解析した結果。
行と単語ごとに解析される。
「J389 NLT」は行(line)で「J389 NLT」、単語で「J389」「NLT」。
DetectedTextが検出したテキスト
Confidenceが信頼度

```json
{
  "TextDetections": [
    {
      "DetectedText": "C",
      "Type": "LINE",
      "Id": 0,
      "Confidence": 72.02649688720703,
      "Geometry": {
        "BoundingBox": {
          "Width": 0.04000072553753853,
          "Height": 0.022570611909031868,
          "Left": 0.25833332538604736,
          "Top": 0.1862500011920929
        },
        "Polygon": [
          {
            "X": 0.25833332538604736,
            "Y": 0.1862500011920929
          },
          {
            "X": 0.2983340620994568,
            "Y": 0.18744535744190216
          },
          {
            "X": 0.29803428053855896,
            "Y": 0.21001596748828888
          },
          {
            "X": 0.2580335736274719,
            "Y": 0.20882061123847961
          }
        ]
      }
    },
    {
      "DetectedText": "J389 NLT",
      "Type": "LINE",
      "Id": 1,
      "Confidence": 99.67211151123047,
      "Geometry": {
        "BoundingBox": {
          "Width": 0.16278892755508423,
          "Height": 0.054150763899087906,
          "Left": 0.47471365332603455,
          "Top": 0.7062126398086548
        },
        "Polygon": [
          {
            "X": 0.47471365332603455,
            "Y": 0.7062126398086548
          },
          {
            "X": 0.6375026106834412,
            "Y": 0.7274553775787354
          },
          {
            "X": 0.6343620419502258,
            "Y": 0.781606137752533
          },
          {
            "X": 0.4715730845928192,
            "Y": 0.7603633999824524
          }
        ]
      }
    },
    {
      "DetectedText": "C",
      "Type": "WORD",
      "Id": 2,
      "ParentId": 0,
      "Confidence": 72.02649688720703,
      "Geometry": {
        "BoundingBox": {
          "Width": 0.040019527077674866,
          "Height": 0.022515427321195602,
          "Left": 0.25833332538604736,
          "Top": 0.1862500011920929
        },
        "Polygon": [
          {
            "X": 0.25833332538604736,
            "Y": 0.1862500011920929
          },
          {
            "X": 0.2983333468437195,
            "Y": 0.1875
          },
          {
            "X": 0.29750001430511475,
            "Y": 0.20999999344348907
          },
          {
            "X": 0.25833332538604736,
            "Y": 0.20874999463558197
          }
        ]
      }
    },
    {
      "DetectedText": "J389",
      "Type": "WORD",
      "Id": 3,
      "ParentId": 1,
      "Confidence": 99.63874053955078,
      "Geometry": {
        "BoundingBox": {
          "Width": 0.08508982509374619,
          "Height": 0.05266508460044861,
          "Left": 0.4749999940395355,
          "Top": 0.706250011920929
        },
        "Polygon": [
          {
            "X": 0.4749999940395355,
            "Y": 0.706250011920929
          },
          {
            "X": 0.559166669845581,
            "Y": 0.71875
          },
          {
            "X": 0.5550000071525574,
            "Y": 0.7712500095367432
          },
          {
            "X": 0.4716666638851166,
            "Y": 0.7587500214576721
          }
        ]
      }
    },
    {
      "DetectedText": "NLT",
      "Type": "WORD",
      "Id": 4,
      "ParentId": 1,
      "Confidence": 99.70547485351562,
      "Geometry": {
        "BoundingBox": {
          "Width": 0.07040064036846161,
          "Height": 0.05260571464896202,
          "Left": 0.5674999952316284,
          "Top": 0.7200000286102295
        },
        "Polygon": [
          {
            "X": 0.5674999952316284,
            "Y": 0.7200000286102295
          },
          {
            "X": 0.637499988079071,
            "Y": 0.7275000214576721
          },
          {
            "X": 0.6341666579246521,
            "Y": 0.7799999713897705
          },
          {
            "X": 0.5649999976158142,
            "Y": 0.7724999785423279
          }
        ]
      }
    }
  ],
  "ResponseMetadata": {
    "RequestId": "b4280fa0-2982-4ac7-8ce3-02beb83b986f",
    "HTTPStatusCode": 200,
    "HTTPHeaders": {
      "content-type": "application/x-amz-json-1.1",
      "date": "Thu, 19 Dec 2019 13:26:41 GMT",
      "x-amzn-requestid": "b4280fa0-2982-4ac7-8ce3-02beb83b986f",
      "content-length": "2131",
      "connection": "keep-alive"
    },
    "RetryAttempts": 0
  }
}
```

## 料金
API を使用して画像を分析するたびに料金が発生。
だいたい、 1 か月あたり 100 万枚分析して 1000 USD。

料金例は　[こちらから](https://aws.amazon.com/jp/rekognition/pricing/)

## 捕捉
ACCESS_KEY、SECRET_KEYを指定せずに正常にsessionが取得できているのはLambdaを使っているからですね。
ポリシーを作成し、Lambda実行するロールに割り当ている。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "rekognition:DetectText",
                "rekognition:CompareFaces",
                "s3:*"
            ],
            "Resource": "*"
        }
    ]
}
```

rekognition:DetectText、rekognition:CompareFacesの使用とs3への全ての操作を許可。

これがないと下記のエラーが出る。

```
 "errorMessage": "An error occurred (AccessDeniedException) when calling the CompareFaces operation: User: arn:aws:sts::294326415501:assumed-role/testRekognitionPythonFace-role-jcjxzbmq/testRekognitionPythonFace is not authorized to perform: rekognition:CompareFaces",
```