26
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Amazon Rekognitionで顔分析LINE BOT

Posted at

前回の記事に引き続き、PythonとHerokuでLINE BOTを作ったメモ書きです。
今回はAmazon Rekognitionを使って、顔(感情)分析をしてみます。
基本的に、前回AutoML VisionのAPIを呼んでいた箇所をAmazon RekognitionのAPIに変えただけになります。

できたものがこちら。

準備

PythonのBoto3というライブラリからAWSを操作するためにAPIキーが必要になります。
IAMユーザの作成やキーの取得については以下を参考にしました。

Amazon AWSを使用してIAMユーザーを作成する方法
Python boto3 でAWSを自在に操ろう ~入門編~

S3に画像を保存

LINEから送られてきた画像データを一度S3に格納することで、Rekognitionの呼び出しが簡単になります。
APIキーとリージョンはHerokuで環境変数に入れておきます。

  • AWS_ACCESS_KEY_ID
  • AWS_SECRET_ACCESS_KEY
  • AWS_DEFAULT_REGION
main.py
# 画像メッセージの場合
@handler.add(MessageEvent, message=ImageMessage)
def handle_image(event):
    message_id = event.message.id
    message_content = line_bot_api.get_message_content(message_id)

    image_bin = BytesIO(message_content.content)
    image = image_bin.getvalue()

    # S3へ画像を保存
    s3 = boto3.client('s3')
    filename = message_id + '.jpg' # メッセージIDをファイル名とする
    s3.put_object(Bucket='backetを指定', Body=image,  Key=filename)

画像を残しておきたくない場合はdelete_object()で削除できます。

main.py
    # S3の画像を削除
    s3.delete_object(Bucket='backetを指定', Key=filename)

Rekognitionを呼び出す

S3のバケットとキー(ファイル名)を指定して、Rekognitionのdetect_faces()を呼び出します。
このとき、AttributesALLにすることで感情データ(Emotions)も取得することができます。
SDKリファレンス

main.py
    # Rekognition呼び出し
    rekognition = boto3.client('rekognition')
    response = rekognition.detect_faces(
        Image={
            'S3Object': {
                'Bucket': 'backetを指定',
                'Name': filename
            }
        },
        Attributes=[
            'ALL'
        ]
    )

    # 結果から感情データを取得
    message = ''
    cnt = 0
    for face_detail in response['FaceDetails']:
        cnt += 1
        message += str(cnt) + '人目\n'
        for emotion in face_detail['Emotions']:
            message += translation(emotion['Type']) + ':' + \
                str(round(emotion['Confidence'], 6)) + '\n'


def translation(type):
    if type == 'HAPPY':
        return '幸せ'
    elif type == 'SAD':
        return '悲しみ'
    elif type == 'ANGRY':
        return '怒り'
    elif type == 'SURPRISED':
        return '驚き'
    elif type == 'DISGUSTED':
        return '嫌悪'
    elif type == 'CALM':
        return '穏やか'
    elif type == 'CONFUSED':
        return '困惑'
    elif type == 'FEAR':
        return '恐れ'

レスポンスはこんな感じでいろいろなパラメータが返ってきます。
(1枚目の女性の写真の場合です)

{'FaceDetails': [{
    'BoundingBox': {
        'Width': 0.13417434692382812,
        'Height': 0.244236558675766,
        'Left': 0.4932348132133484,
        'Top': 0.16279612481594086,
        },
    'AgeRange': {'Low': 20, 'High': 32},
    'Smile': {'Value': True, 'Confidence': 99.76376342773438},
    'Eyeglasses': {'Value': False, 'Confidence': 99.79804992675781},
    'Sunglasses': {'Value': False, 'Confidence': 99.94234466552734},
    'Gender': {'Value': 'Female', 'Confidence': 99.739990234375},
    'Beard': {'Value': False, 'Confidence': 99.172607421875},
    'Mustache': {'Value': False, 'Confidence': 99.76605987548828},
    'EyesOpen': {'Value': True, 'Confidence': 79.16128540039062},
    'MouthOpen': {'Value': True, 'Confidence': 99.7750015258789},
    'Emotions': [
        {'Type': 'SURPRISED', 'Confidence': 0.05093928799033165},
        {'Type': 'HAPPY', 'Confidence': 99.83908081054688},
        {'Type': 'FEAR', 'Confidence': 0.02197244018316269},
        {'Type': 'CONFUSED', 'Confidence': 0.01973951980471611},
        {'Type': 'DISGUSTED', 'Confidence': 0.013059847988188267},
        {'Type': 'CALM', 'Confidence': 0.006850585341453552},
        {'Type': 'SAD', 'Confidence': 0.013594787567853928},
        {'Type': 'ANGRY', 'Confidence': 0.03477080538868904},
        ],
    'Landmarks': [
        {'Type': 'eyeLeft', 'X': 0.5280879139900208,
         'Y': 0.22927305102348328},
        {'Type': 'eyeRight', 'X': 0.5915847420692444,
         'Y': 0.24782206118106842},
        {'Type': 'mouthLeft', 'X': 0.5162054300308228,
         'Y': 0.3102501630783081},
        {'Type': 'mouthRight', 'X': 0.5685757398605347,
         'Y': 0.32595935463905334},
        {'Type': 'nose', 'X': 0.543215811252594,
         'Y': 0.2711125910282135},
        {'Type': 'leftEyeBrowLeft', 'X': 0.5093030333518982,
         'Y': 0.20783887803554535},
        {'Type': 'leftEyeBrowRight', 'X': 0.5432007908821106,
         'Y': 0.20587614178657532},
        {'Type': 'leftEyeBrowUp', 'X': 0.5266761779785156,
         'Y': 0.19909897446632385},
        {'Type': 'rightEyeBrowLeft', 'X': 0.5808103680610657,
         'Y': 0.21660329401493073},
        {'Type': 'rightEyeBrowRight', 'X': 0.6230998039245605,
         'Y': 0.24032928049564362},
        {'Type': 'rightEyeBrowUp', 'X': 0.6021548509597778,
         'Y': 0.21990607678890228},
        {'Type': 'leftEyeLeft', 'X': 0.5178995132446289,
         'Y': 0.22759923338890076},
        {'Type': 'leftEyeRight', 'X': 0.5400444865226746,
         'Y': 0.23417668044567108},
        {'Type': 'leftEyeUp', 'X': 0.5282144546508789,
         'Y': 0.22547268867492676},
        {'Type': 'leftEyeDown', 'X': 0.5273098349571228,
         'Y': 0.23307734727859497},
        {'Type': 'rightEyeLeft', 'X': 0.5778760313987732,
         'Y': 0.24511677026748657},
        {'Type': 'rightEyeRight', 'X': 0.6024900674819946,
         'Y': 0.25224098563194275},
        {'Type': 'rightEyeUp', 'X': 0.5909795761108398,
         'Y': 0.2437404841184616},
        {'Type': 'rightEyeDown', 'X': 0.5891347527503967,
         'Y': 0.2511424422264099},
        {'Type': 'noseLeft', 'X': 0.5332950949668884,
         'Y': 0.28240063786506653},
        {'Type': 'noseRight', 'X': 0.5571921467781067,
         'Y': 0.28958040475845337},
        {'Type': 'mouthUp', 'X': 0.540307343006134,
         'Y': 0.3037816286087036},
        {'Type': 'mouthDown', 'X': 0.5361402630805969,
         'Y': 0.3289361000061035},
        {'Type': 'leftPupil', 'X': 0.5280879139900208,
         'Y': 0.22927305102348328},
        {'Type': 'rightPupil', 'X': 0.5915847420692444,
         'Y': 0.24782206118106842},
        {'Type': 'upperJawlineLeft', 'X': 0.500860333442688,
         'Y': 0.2379489243030548},
        {'Type': 'midJawlineLeft', 'X': 0.4942063093185425,
         'Y': 0.32398536801338196},
        {'Type': 'chinBottom', 'X': 0.5307005047798157,
         'Y': 0.374202162027359},
        {'Type': 'midJawlineRight', 'X': 0.6082754135131836,
         'Y': 0.3568985164165497},
        {'Type': 'upperJawlineRight', 'X': 0.6429087519645691,
         'Y': 0.2788805365562439},
        ],
    'Pose': {'Roll': 10.41435718536377, 'Yaw': -26.832902908325195,
             'Pitch': 2.036668062210083},
    'Quality': {'Brightness': 68.89059448242188,
                'Sharpness': 94.08262634277344},
    'Confidence': 99.99998474121094,
    }], 'ResponseMetadata': {
    'RequestId': '8dde5ca4-1af5-4063-8ac4-bb2156d3e85c',
    'HTTPStatusCode': 200,
    'HTTPHeaders': {
        'content-type': 'application/x-amz-json-1.1',
        'date': 'Tue, 10 Sep 2019 21:14:47 GMT',
        'x-amzn-requestid': '8dde5ca4-1af5-4063-8ac4-bb2156d3e85c',
        'content-length': '3354',
        'connection': 'keep-alive',
        },
    'RetryAttempts': 0,
    }}
26
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
26
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?