【初心者向け】AWS Rekognition+Lambda(python)で画像解析

今回はAWSの画像分析サービスのAWS Rekognitionを使って、S3バケットに格納した画像を解析・ラベリングし、ラベルデータをDynamoDBに格納する仕組みを作っていきます。

# 今回のゴール
S3バケットに画像ファイルをアップロードするとAmazon Rekognition imageで画像を解析し、どんな内容の画像なのかラベルを付けて、その中の3ラベルをDynamoDBに書き込みする。一連の処理はS3バケットへの画像格納をトリガーに、Lambdaで実行する。

構成図にするとこんな感じです。

![AWS環境.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/ad3694df-5ea6-6425-709b-192e5a1934f5.png)



最終的にDynamoDBにこんな感じで画像解析した結果のラベルが格納されていればOkとします。
　※解析に使った画像はモナリザなので、「Art」、「Painting」、「person」とラベリングされています。

![DynamoDB.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/be5d1771-1d2c-58c3-b7fc-a0d641fe7eb7.png)


# 前提条件（免責事項）
-Lambdaの処理はpython（この記事執筆時点の最新3.12）で記述します。※下手くそコードです
-設定にあたり、リソース使用時に課金が発生しますので使い終わったらリソース削除しましょう


# 設定の流れ
実際の設定ですが以下の流れになります。
①S3バケットの作成
②Lambdaの設定
③DynamoDBのテーブル作成
④動作確認




## ①S3バケットの作成
まずは画像でデータを格納するS3バケットを作成します。基本的にS3バケットには特に変わった設定はせず、デフォルトの状態で作成していきます。

バケットタイプは「汎用」を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/cda93c49-49cc-ca53-0f7d-5737d173d94e.png)

ACL設定やパブリックアクセスブロックはデフォルトのままで「バケットの作成」まで進めてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/83730959-9317-da3b-e28d-b7b74c54b674.png)



リージョンだけちゃんと利用する予定のリージョンになっているか確認しましょう。またバケット名は一意にする必要があるので他バケットと重複しなさそうな名前にしましょう。


## ②Lambdaの設定
Lambdaの作成は手動で内容を入れていきますので「一から作成」を選択します。関数名は任意のものを記入すます。ランタイムは今回Pythonを利用するので「Python」の任意のバージョンを選択してください。実行ロールは「基本的なLambdaアクセス権で新しいロールを作成」を選択しておきます。ロールの設定はあとから変えますのでいったんこのままでOKです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/4981df3e-3f88-4f11-795c-43dc2f3485a8.png)

これで関数を作成まで進めてください。



### ②-1 Lambda用ロールに権限追加

作成されたLambda関数を選択して、表示すると以下のような画面になります

![Lambda_ダッシュボード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/863755c4-386e-eec9-17e3-3cba3c9ad79d.png)

先ほど作成したLambda関数の実行ロールはデフォルトのままで、デフォルトだとCloudwatchしか実行権限が付与されていないのでS3バケットを読み取りしたり、DynamoDBに書き込みができないです。そのため必要なリソースへのアクセス権限を付与する必要があります。「設定タブ」をクリックすると実行ロールの現状設定が表示されます。ロール名のところがリンクになっているのでクリックして、IAMのロール設定とのところにアクセスします。

![デフォルトの実行ロール権限.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/5e07550a-bdfa-e84a-48bf-34c3df28a38f.png)


許可ポリシーのところで「許可を追加」で「ポリシーをアタッチ」をクリックしてください。
![ポリシーアタッチ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/7aaf05db-8238-3ceb-3edb-434254a44273.png)


どういうポリシーをアタッチするか設定する画面になるので、「AmazonS3FullAccess」と「AmazonDynamoDBFullAccess」をアタッチしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/70f8ff32-d616-1dbd-2b63-a34b85d51092.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/887aa753-5553-4636-7ae1-7d9949049e30.png)

アタッチ後は以下のようなポリシー設定になります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/d0749832-e747-2d87-ea66-2d862692c9e3.png)



### ②-2 トリガーの設定
Lambda関数が実行されるトリガーを設定していきます。今回は特定のS3バケットに指定のファイル名のJPGファイルをアップしたら動作するように設定していきます。Lambdaの設定画面で「+トリガーを追加」というボタンをクリックするとどのサービスをトリガーにするか選択できますので、「S3」を選択します。
![lambdaトリガー設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/e0453502-417c-a5f0-3e20-f61b035701f0.png)


「Bucket」のとことで手順①で設定したS3バケットを選択し、Event Typesは「All pbject create events」を選択します。Suffixのところは今回JPGファイルをアップする予定なので、".jpg"を記載します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/543ff53c-5ec0-8f2f-7fb1-709bc2f1e23b.png)

トリガー追加後はこんな感じになります。
![トリガー追加後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/f52fc0a6-e425-c130-1748-f58a5920e483.png)


### ②-3 ソースコードの記述
ここからはpythonで処理を記述していきます。コードタブをクリックし、「lambda_function.py」に記述していきます。
![Lambdaコード.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/41316e5c-2c5b-27b1-1828-354cbb1099ae.png)

Lambdaの処理コード内容は以下です。
次のパラーメータはご自身の環境の合わせて変更してください。

- "作成したS3バケット名" 
- "モナリザ.jpg"
- ”DynamoDBテーブル名”

```
import boto3
import json

def lambda_handler(event, context):
    
    rekognition = boto3.client("rekognition")
    bucket = "作成したS3バケット名" 
    key = "モナリザ.jpg" #ファイル名
    
    response = rekognition.detect_labels(
        Image={
            "S3Object": {
                "Bucket": bucket,
                "Name": key,
            }
        },
       MaxLabels = 3,
    )
    
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('DynamoDBテーブル名) # DynamoDBテーブル名
    labels = response['Labels']
    for i in range(len(labels)):
     label_name = labels[i]['Name']
     label_confidence = int(labels[i]['Confidence'])
        
    # 信頼度が80%以上のラベルのみDynamoDBに保存する
     if label_confidence >= 80:
          ret = table.put_item(
          Item={
          "image": key,
          "lable": label_name,
          "confidence": label_confidence,
          }
          )
          
    # ログ出力
    return ret
```

## ③DynamoDBのテーブル作成
Lambdaがデータを書き込むDynamoDBを作成していきます。管理コンソールにアクセスして、「テーブルの作成」をクリックして、テーブル名は任意の値を入力し、「パーティションキー」=「image」、「ソートキー」=「lable」と記載します。タイプは2つとも「文字列」とします。





![DymanoDB_作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/eaaf7e9e-1994-f058-71ca-f042c61de863.png)

作成後のテーブル項目はこんな感じになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/32bf89bf-bea7-818b-43e0-db892bbb7e0a.png)





## ④動作確認
Lambdaの設定画面でコードのテストを実行して、実行StatusがSuccessになっていればOKです。

![Lambda_実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/be96507b-4207-5576-6e97-eed93b00641a.png)

:::note info
実行Statusがエラーになる場合はエラーメッセージにエラー原因が書かれていますので確認しましょう。私はインデントがおかしかったりや処理分の最後に"："がないという凡ミスがよくあります。
:::

:::note warn
エラーメッセージ内容がAccessDenyとなっている場合はLambdaの実行ロールの権限の問題です。いったん付与ポリシーを「AdministratorAccess」にして実行して切り分けしてもよいと思います。実行ロールを「AdministratorAccess」に変更した場合、強力な権限になっているので注意してください。
:::

設定したS3バケットに指定ファイル名（私の環境ではモナリザ.jpg）をアップすると画像解析結果のラベリング情報がDynamoDBに格納されているか確認しましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655033/bcc4e74f-6563-633f-d5e3-1f4c90e26718.png)

DynamoDBで作成したテーブルを選択して、「テーブルアイテムを検索」を実行すると格納されたデータが確認できます。

# おわりに
サンプル画像がモナリザなので解析結果はそれなりの精度でした。でも犬・猫以外の動物の判別は微妙だったりします笑。Pythonコード内に個別ファイル名を記載していますが、書き方を工夫すればもっと自動化できるようになると思います。Pythonコードスキルが上がればそのうち書いてみようかな...


# 参考サイト

https://qiita.com/Otofuke/items/35f1ea884a3464bda247

https://docs.aws.amazon.com/rekognition/latest/APIReference/API_DetectLabels.html

https://analytics-note.xyz/aws/amazon-rekognition-labels/

https://www.aws-room.com/entry/recognition-image