pythonでAmazon Rekognition カスタムラベルを利用して画像認識をやってみた。

# はじめに
本記事が自身初投稿になります。拙い文章ですが、ぜひご覧頂けますと幸いです。

# きっかけ
業務で開発中のwebアプリにて、ユーザーが身分証明書の画像をアップロードし、管理者が画像を閲覧できる機能を追加しました。(画像はweb画面に組み込まれて表示されます。)
web画面で定められた横長の画像領域に対して縦画面で撮影された画像が見づらく表示されるということがあったため、縦画面または横画面どちらで撮影された画像でも**身分証部分を識別してトリミングする機能**があればなあと思いました。

また、先日AWS SAA認定試験に合格し、AWSで何かできないかなと考えたときに、特に上司からの指示はないのですが上記の機能が実現できないか挑戦してみました。

# Amazon Rekognition とは
AWSが提供する画像分析、動画分析サービスになります。特に機械学習の知識がなくとも、APIを使用することで画像や動画の物体、人物、テキスト、シーン、活動を特定できます。

# カスタムラベル とは
> Amazon Rekognition カスタムラベルを使用して、ビジネスニーズに合わせた画像の物体やシーンを特定できます。たとえば、モデルを構築して、アセンブリライン上の特定の機械部品を分類したり、不健康な植物を検出したりできます。Amazon Rekognition カスタムラベルは、モデル開発の手間のかかる作業を処理するので、機械学習の経験は必要ありません。特定したい物体やシーンの画像を提供するだけで、残りはサービスが処理します。

要するに、画像をAWSに提供して自分の好きなようにラベル(特定したいもの)を設定できるということです。

# カスタムラベルを用意する
今回は簡単な説明のみとさせて頂きます。
1. プロジェクトを作成する。
2. データセットを作成する。
3. 特定したものが写っている画像を複数用意し、データセットに画像を追加する。
4. それぞれの画像に自作のタグを付ける。
5. 新しいモデルをトレーニングする。(自分の場合は1時間以上かかりました。)

カスタムラベルの作成については下記サイトを参考にさせていただきました。
[第5回 Amazon Rekognition カスタムラベル(準備)](https://www.public.ne.jp/2021/04/20/%e7%ac%ac5%e5%9b%9e-amazon-rekognition-%e3%82%ab%e3%82%b9%e3%82%bf%e3%83%a0%e3%83%a9%e3%83%99%e3%83%ab%e6%ba%96%e5%82%99/)

# pythonコード

`APIコード`でPythonを選択すると、3種類のコードが表示されます。

1. モデルを開始するコード
2. 画像を分析するコード
3. モデルを停止するコード

この3種類をそのまま使うだけでS3の画像を認識することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1667352/21ed91bd-ee45-b276-7e4d-12ffc9dcba3b.png)

1と3にはデータセットの画像やARNが自動で入力されているので、そのまま使用できるはずです。

```python:画像を分析するコード

#Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
#PDX-License-Identifier: MIT-0 (For details, see https://github.com/awsdocs/amazon-rekognition-custom-labels-developer-guide/blob/master/LICENSE-SAMPLECODE.)

import boto3
import io
from PIL import Image, ImageDraw, ExifTags, ImageColor, ImageFont

def display_image(bucket,photo,response):
    # Load image from S3 bucket
    s3_connection = boto3.resource('s3')

    s3_object = s3_connection.Object(bucket,photo)
    s3_response = s3_object.get()

    stream = io.BytesIO(s3_response['Body'].read())
    image=Image.open(stream)

    # Ready image to draw bounding boxes on it.
    imgWidth, imgHeight = image.size
    draw = ImageDraw.Draw(image)

    # calculate and display bounding boxes for each detected custom label
    print('Detected custom labels for ' + photo)
    for customLabel in response['CustomLabels']:
        print('Label ' + str(customLabel['Name']))
        print('Confidence ' + str(customLabel['Confidence']))
        if 'Geometry' in customLabel:
            box = customLabel['Geometry']['BoundingBox']
            left = imgWidth * box['Left']
            top = imgHeight * box['Top']
            width = imgWidth * box['Width']
            height = imgHeight * box['Height']

            fnt = ImageFont.truetype('/Library/Fonts/Arial.ttf', 50)
            draw.text((left,top), customLabel['Name'], fill='#00d400', font=fnt)

            print('Left: ' + '{0:.0f}'.format(left))
            print('Top: ' + '{0:.0f}'.format(top))
            print('Label Width: ' + "{0:.0f}".format(width))
            print('Label Height: ' + "{0:.0f}".format(height))

            points = (
                (left,top),
                (left + width, top),
                (left + width, top + height),
                (left , top + height),
                (left, top))
            draw.line(points, fill='#00d400', width=5)

    image.show()

def show_custom_labels(model,bucket,photo, min_confidence):
    client=boto3.client('rekognition')

    #Call DetectCustomLabels
    response = client.detect_custom_labels(Image={'S3Object': {'Bucket': bucket, 'Name': photo}},
        MinConfidence=min_confidence,
        ProjectVersionArn=model)

    # For object detection use case, uncomment below code to display image.
    # display_image(bucket,photo,response)

    return len(response['CustomLabels'])

def main():

    bucket='MY_BUCKET'
    photo='MY_IMAGE_KEY'
    model='arn:aws:rekognition:ap-northeast-1:913059777631:project/custom-label-for-insurance-card/version/custom-label-for-insurance-card.2021-06-23T09.53.17/1624409597359'
    min_confidence=95

    label_count=show_custom_labels(model,bucket,photo, min_confidence)
    print("Custom labels detected: " + str(label_count))


if __name__ == "__main__":
    main()

```
`image.show()`でカスタムラベルを識別し、枠で囲った画像が表示されます。画像を`BoundingBox `の範囲でトリムして別名保存することで__画像認識＋トリミング__を実現できます。

#  終わりに
実は今週Pythonを触り始めたばかりで、まだ基礎を勉強中です。
今回は日常の業務の中で自分が学習中のAWSとPythonを活用できるユースケースを思いついたのが嬉しかったので、初めて記事を書いてみました。
今後も備忘録や作成したものなどを共有できればと思います。