Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
19
Help us understand the problem. What is going on with this article?
@keeey999

Amazon Rekognitionで顔分析LINE BOT

More than 1 year has passed since last update.

前回の記事に引き続き、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,
    }}
19
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
keeey999

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
19
Help us understand the problem. What is going on with this article?