前回の記事に引き続き、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
# 画像メッセージの場合
@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()
で削除できます。
# S3の画像を削除
s3.delete_object(Bucket='backetを指定', Key=filename)
Rekognitionを呼び出す
S3のバケットとキー(ファイル名)を指定して、Rekognitionのdetect_faces()
を呼び出します。
このとき、Attributes
をALL
にすることで感情データ(Emotions)も取得することができます。
SDKリファレンス
# 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,
}}