表情判定するLINE BOTをつくった(LINE x Amazon Rekognition)

前回の記事で、<b>LINEで画像を飛ばしてS3に保存する機能</b>を実装しました。
[LINEで送った画像をS3に保存する(LINE Messaging API x AWS)
](https://qiita.com/ted-17/items/0e3e4956a19ad183e739)
# やること
・LINEで画像を飛ばしてAmazon Rekognitionに食わせる
・判定結果をLINEに返す
をしてみようと思います。

# 構成図
![line_to_rekognition.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989761/d9549338-cc7f-6c39-e130-99a1219a3329.png)
[前回](https://qiita.com/ted-17/items/0e3e4956a19ad183e739)からAmazon Rekognitionが増えただけ。
今回はLINEで送ってLINEに返すという気持ちを込めて双方向⇄にしています。
前回同様AWS LambdaにPythonで書いていきます。

# Amazon Rekognitionで顔情報を解析
画像を取得して、Amazon Rekognitionのdetect_facesを使って顔情報を解析します。

```python:lambda_function.py
rekognition=boto3.client('rekognition')
def lambda_handler(event, context):
    body = json.loads(event['body'])
    for event in body['events']:
        #-- LINEからimage（画像)が届いた時
        if event['message']['type'] == 'image':
            #-- 1. 画像を読み出し
            MessageId = event['message']['id']  # メッセージID
            ImageFile = requests.get('https://api-data.line.me/v2/bot/message/'+ MessageId +'/content',headers=HEADER) #Imagecontent取得
            Image_bin = BytesIO(ImageFile.content)
            Image = Image_bin.getvalue()  # 画像取得

            #-- 2. Amazon Rekognition
            res = rekognition.detect_faces(
                Image={"Bytes":Image},
                Attributes=['ALL'],
                )
```

ここで、res['FaceDetails']をみてみると、↓のような感じで顔に関するデータがたくさん出てきます。
顔の座標、年齢幅、笑っているか否か、眼鏡をかけているか、etc...

```
[1]:res['FaceDetails'][0].keys()
dict_keys(['BoundingBox', 'AgeRange', 'Smile', 'Eyeglasses', 'Sunglasses', 'Gender', 'Beard', 'Mustache', 'EyesOpen', 'MouthOpen', 'Emotions', 'Landmarks', 'Pose', 'Quality', 'Confidence'])
```

この中で、表情は['Emotions']のキーを展開することで下記のように得られます。

```
[2]:res['FaceDetails'][0]['Emotions']
[{'Type': 'FEAR', 'Confidence': 64.29468536376953},
 {'Type': 'HAPPY', 'Confidence': 19.791912078857422},
 {'Type': 'ANGRY', 'Confidence': 14.918501853942871},
 {'Type': 'SURPRISED', 'Confidence': 0.4045420289039612},
 {'Type': 'DISGUSTED', 'Confidence': 0.2060088962316513},
 {'Type': 'SAD', 'Confidence': 0.19950535893440247},
 {'Type': 'CONFUSED', 'Confidence': 0.1273392289876938},
 {'Type': 'CALM', 'Confidence': 0.057497505098581314}]
```

８種類の感情が、百分率の降順ソートで返されます。
# 感情情報をLINEに送り返す
今回は、一番大きい感情(FEAR)を返すようにしてみます。
一番大きい＝index番号0のものを返します。返信メッセージの格納は前回と同様です。

```python:lambda_function.py
        emotion=res['FaceDetails'][0]['Emotions'] #ちなみに この0は人数(複数人いれば0,1,2,..)
        emotion_type=emotion[0]['Type'] #str
        confidence=emotion[0]['Confidence'] #float'

        msg='emotion:%s (confidence:%.2f)'%(emotion_type, confidence)

        #-- LINEに返す情報
        REQUEST_MESSAGE = [
        {
        'type': 'text',
        'text': msg,
        }
        ]
        payload = {'replyToken': event['replyToken'], 'messages': REQUEST_MESSAGE}

        #-- HEADERとmessages(payload)を付加してpost
        if len(payload['messages']) > 0:
                response = requests.post(
                'https://api.line.me/v2/bot/message/reply',
                headers=HEADER,
                data=json.dumps(payload)
                )
    return 0
```

# おまけ：マスク有無の判定してみる
時代のトレンドに鑑みてついでにやってみました。
マスクしているか否かの判定には、rekognitionのdetect_protective_equipmentを使います。
「画像から検出された人が着用している個人用防護具（PPE）を検出する」そうです。なんとニッチ。
ここにFACE_COVERのキーがあったので、せっかくなのでマスク有無判定器として使いましょう。

わかりやすく？　関数化してみました

```python:lambda_function.py
def detect_mask(rekognition,Image):
    res = rekognition.detect_protective_equipment(
        Image={"Bytes":Image},
        SummarizationAttributes={
            "MinConfidence": 80,
            "RequiredEquipmentTypes": [
                "FACE_COVER"
            ]
        }
    )
    is_mask=False
    #-- ひとりでもマスクをしていたらフラグをあげる
    for p in res['Persons']:
        if p['BodyParts'][0]['EquipmentDetections']:
            is_mask=True
            break
    return is_mask
```
マスクしているか否かのTrue/Falseを返します。複数人映っている場合を想定しています。
<b>detect_protective_equipment</b> の引数 <b>SummarizationAttributes</b>で、FACE_COVER（⊃マスク)を指定します。
MinConfidenceは80にしました。この値よりも低い信頼度のラベルは返されません。適合率重視ですね(この辺りいつも混乱...)。
つまり相当自信を持っていないとマスク有判定されません。「中途半端につけているのは、マスクしてるとは見なさん！！！」ということですね。
このis_mask情報を用いて、LINEに返すmsgに一言付け加えるなどしてもオモローですね。

# おわり
今回はAmazon Rekognitionを用いて、「LINEで顔画像を送信し、その表情をLINEに返す」ことをしてみました！ついでに時代の潮流に乗っかってマスク有無の判定もしてみました。
Rekognitionは他にも物体検出や画像内のテキスト抽出などもお手軽にできるので、いろいろと用途が広がりますね！

#Re <b>k</b> ognitionの理由は何なのだろうか...