今回は、代表的な画像認識APIの1つであるAmazon Rekognitionの使い方を紹介します。
Amazon Rekognitionは以下のような機能を提供しています。
・オブジェクト、シーン、アクティビティの検出
・顔の検出、顔認識
・ 画像、動画内の不適切なコンテンツの識別
・ 有名人の認識
・ テキストの抽出
本記事では、画像内の顔検出や顔認識の方法を主に扱います。
準備
Amazon Linux(EC2)を作成し、IAM ユーザーでアクセスキーとシークレットアクセスを作成。
aws cliのセットアップは省略。
Python3などの環境構築は以下を参照。
# rekognitionを操作するためにboto3をインストール
pip3 install boto3
なお、この記事で使うPythonのバージョンは Python3.7.4 です。
コレクションとは?
コレクションとは顔のベクトル情報を持つコンテナで、AWSアカウントのリージョン内に複数作成できます。
作成するたびに一意の Amazon リソースネーム (ARN) が割り当てられ、1コレクション内に2000万個の顔データを保持することができます。
コレクションごとに深層学習モデルのバージョン情報を持っており、作成した時点での最新バージョンで作成されます。
1人あたり3枚ほど画像をコレクションに追加すれば、かなりの精度で判別してくれます。
主な制限
Amazon Rekognitionの無料枠は最初の12ヶ月間あり、個人で開発するには十分な枠が設けられています。
・画像の入力形式はbase64エンコード(SDKは不要)した画像かS3オブジェクトのみ
・画像形式はPNGまたはJPEG
・最小画像サイズは80×80
・S3オブジェクトの保存画像サイズは15MBまで
・画像内の顔は40×40px以上で検出可能
詳しい制限はAWSのReferenceを参照ください。
顔の検出と分析
コレクションに顔データを格納する前に、画像内の顔を検出するオペレーションを実行してみます。
入力画像はS3オブジェクトを使わずにPythonのSDKを使用してローカル画像を読み込みます。
画像内の顔の検出
画像内の顔のベクトルや表情、シーンなどの情報を表示します。
画像はこの美女の写真を使います。
フリー素材で見つけた綺麗すぎる美女。

import boto3
#boto3のclientを作成し、rekognitionとリージョンを指定
client = boto3.client('rekognition', 'ap-northeast-1')
img_file_path = 'image1.jpg'
img = open(img_file_path, 'rb')
# rekognitionのdetect_labelsに画像バイト列を渡してラベル検出
response = client.detect_faces(
Image={
'Bytes': img.read()
}
)
print(response)
{
"FaceDetails": [
{
"BoundingBox": {
"Width": 0.3820308446884155,
"Height": 0.3321954309940338,
"Left": 0.31003570556640625,
"Top": 0.3712398409843445
},
"Landmarks": [
{
"Type": "eyeLeft",
"X": 0.4603809118270874,
"Y": 0.500609815120697
},
{
"Type": "eyeRight",
"X": 0.625609278678894,
"Y": 0.5136897563934326
},
{
"Type": "mouthLeft",
"X": 0.46957412362098694,
"Y": 0.6211203336715698
},
{
"Type": "mouthRight",
"X": 0.6054244041442871,
"Y": 0.6318552494049072
},
{
"Type": "nose",
"X": 0.573784351348877,
"Y": 0.5566537380218506
}
],
"Pose": {
"Roll": 9.553505897521973,
"Yaw": 23.43260383605957,
"Pitch": 11.866987228393555
},
"Quality": {
"Brightness": 61.15129470825195,
"Sharpness": 86.86019134521484
},
"Confidence": 100.0
}
],
}
顔のランドマークや顔の信頼度が返ってきます。
Attributes にALLを指定するとより細かな顔データが得られます。
画像間の顔の比較
ソース画像内の顔とターゲット画像の顔を比較し、一致度を判定します。
ソース画像は先ほどの美女画像を使い、ターゲット画像は同じ美女が映ってるこの画像を使います。

image1 = 'image1.jpg' # ソース画像
image2 = 'image2.jpg' # ターゲット画像
img1 = open(image1, 'rb')
img2 = open(image2, 'rb')
response = client.compare_faces(
SimilarityThreshold=80, # 一致度が80%以上に限定
SourceImage={'Bytes': img1.read()},
TargetImage={'Bytes': img2.read()}
)
for faceMatch in response['FaceMatches']:
print(faceMatch)
{
"Similarity": 99.90501403808594,
"Face": {
"BoundingBox": {
"Width": 0.2191682904958725,
"Height": 0.4197736084461212,
"Left": 0.4726499319076538,
"Top": 0.29024964570999146
},
"Confidence": 100.0,
"Landmarks": [
{
"Type": "eyeLeft",
"X": 0.5406991839408875,
"Y": 0.46720731258392334
},
{
"Type": "eyeRight",
"X": 0.637633740901947,
"Y": 0.44829031825065613
},
{
"Type": "mouthLeft",
"X": 0.5694117546081543,
"Y": 0.6150451898574829
},
{
"Type": "mouthRight",
"X": 0.6492563486099243,
"Y": 0.5993497371673584
},
{
"Type": "nose",
"X": 0.6099340319633484,
"Y": 0.5101433992385864
}
],
"Pose": {
"Roll": -8.299508094787598,
"Yaw": 15.455485343933105,
"Pitch": 3.8333613872528076
},
"Quality": {
"Brightness": 52.02294158935547,
"Sharpness": 86.86019134521484
}
}
}
Similarity (一致度)が99.9%で一致していることが証明されました。
顔の向きや改解像度の問題もありますが、同じ人物で比較した場合はだいたい95%以上の信頼度になります。
コレクション操作
aws cliを使用するので、環境にない場合はインストールしておく。
コレクション作成
まずは、顔データを保持するコレクションを作成。
aws rekognition create-collection --collection-id "my-collection"
{
"CollectionArn": "aws:rekognition:ap-northeast-1:*****:collection/my-collection",
"FaceModelVersion": "4.0",
"StatusCode": 200
}
CollectionID :任意のコレクション名を指定。
FaceModelVersion :学習モデルのバージョン。
コレクション定義
作成したコレクション情報を確認。
aws rekognition describe-collection --collection-id my-collection
{
"FaceCount": 0,
"CreationTimestamp": 1575701390.242,
"CollectionARN": "arn:aws:rekognition:ap-northeast-1:704087196003:collection/my-collection",
"FaceModelVersion": "4.0"
}
FaceCount :コレクション内の顔データ数
コレクションの一覧表示
作成済みのコレクションの一覧を表示。
aws rekognition list-collections
{
"FaceModelVersions": [
"4.0"
],
"CollectionIds": [
"my-collection"
]
}
コレクションに顔データを追加
作成したコレクションに実際に顔データを入れていきます。
画像は先ほどの美女画像1です。
import boto3
#boto3のclientを作成し、rekognitionとリージョンを指定
client = boto3.client('rekognition', 'ap-northeast-1')
collection_id = 'my-collection' # 作成したコレクション
img_file_path = 'image1.jpg'
img = open(img_file_path, 'rb')
response = client.index_faces(
CollectionId=collection_id,
Image={'Bytes':img.read()},
ExternalImageId='image1', # 顔データ
MaxFaces=1, # コレクションに追加する顔の最大数
QualityFilter="AUTO", # 顔データとしての質が悪いものが除外
DetectionAttributes=['ALL']) # 顔データの全てのランドマークを返す
print(response)
{
"FaceRecords": [
{
"Face": {
"FaceId": "5ae99bab-eaa7-4e1a-b8c7-8fa8bf453107",
"BoundingBox": {
"Width": 0.3820308446884155,
"Height": 0.3321954309940338,
"Left": 0.31003570556640625,
"Top": 0.3712398409843445
},
"ImageId": "4860ed57-16fd-3bee-9312-8021d71efc9b",
"ExternalImageId": "image1",
"Confidence": 100.0
},
"FaceDetail": {
"BoundingBox": {
"Width": 0.3820308446884155,
"Height": 0.3321954309940338,
"Left": 0.31003570556640625,
"Top": 0.3712398409843445
},
"Landmarks": [
{
"Type": "eyeLeft",
"X": 0.4603809118270874,
"Y": 0.500609815120697
},
{
"Type": "eyeRight",
"X": 0.625609278678894,
"Y": 0.5136897563934326
},
{
"Type": "mouthLeft",
"X": 0.46957412362098694,
"Y": 0.6211203336715698
},
{
"Type": "mouthRight",
"X": 0.6054244041442871,
"Y": 0.6318552494049072
},
{
"Type": "nose",
"X": 0.573784351348877,
"Y": 0.5566537380218506
}
],
"Pose": {
"Roll": 9.553505897521973,
"Yaw": 23.43260383605957,
"Pitch": 11.866987228393555
},
"Quality": {
"Brightness": 61.15129470825195,
"Sharpness": 86.86019134521484
},
"Confidence": 100.0
}
}
],
}
MaxFaces が1で画像内に複数の顔が映っている場合、一番大きい顔がコレクションに追加されます。
ExternalImageId はユーザーが指定できる唯一の識別子なので、入力画像の情報などを指定しておくといいです。
FaceId はコレクション内で一意になる顔データに紐づくID。
コレクション内の顔データを確認。
collection_id = 'my-collection'
response = client.list_faces(
CollectionId=collection_id,
MaxResults=5)
print(response)
{
"Faces": [
{
"FaceId": "5ae99bab-eaa7-4e1a-b8c7-8fa8bf453107",
"BoundingBox": {
"Width": 0.38203099370002747,
"Height": 0.3321950137615204,
"Left": 0.3100360035896301,
"Top": 0.3712399899959564
},
"ImageId": "4860ed57-16fd-3bee-9312-8021d71efc9b",
"ExternalImageId": "image1",
"Confidence": 100.0
}
]
}
画像1がコレクションに入ってますね。
画像を用いた顔の検索
指定した画像内の一番大きい顔と一致する顔データをコレクションから検索します。
検索に用いる画像は画像2を使います。
collection_id = 'my-collection'
img_file_path = 'image2.jpg'
img = open(img_file_path, 'rb')
response = client.search_faces_by_image(
CollectionId=collection_id,
Image={'Bytes':img.read()},
FaceMatchThreshold=80, # レスポンスを一致度80%以上に制限
MaxFaces=5) # 一致した顔の最大数
print(response)
{
"SearchedFaceBoundingBox": {
"Width": 0.2191682904958725,
"Height": 0.4197736084461212,
"Left": 0.4726499319076538,
"Top": 0.29024964570999146
},
"SearchedFaceConfidence": 100.0,
"FaceMatches": [
{
"Similarity": 99.9050064086914,
"Face": {
"FaceId": "5ae99bab-eaa7-4e1a-b8c7-8fa8bf453107",
"BoundingBox": {
"Width": 0.38203099370002747,
"Height": 0.3321950137615204,
"Left": 0.3100360035896301,
"Top": 0.3712399899959564
},
"ImageId": "4860ed57-16fd-3bee-9312-8021d71efc9b",
"ExternalImageId": "image1",
"Confidence": 100.0
}
}
],
"FaceModelVersion": "4.0",
}
無事画像1が一致しました。
Face IDを用いた顔の検索
コレクション内の検索顔データと一致する顔をコレクション内から検索します。
現在、コレクション内には画像1の顔データしか存在していないので、検索のために画像2に加えて、この画像3もコレクションに追加します。

セクシーすぎる。。。
"Face": {
"FaceId": "4ea5f764-f85f-450f-9eaa-47147c1942c4",
...
"ExternalImageId": "image2",
...
"Face": {
"FaceId": "62745d77-17ec-4dea-8509-91e26eab2c2d",
...
"ExternalImageId": "image3",
画像2・3もコレクションに追加しました。
画像3の顔データでコレクション内から類似顔を検索します。
collection_id = 'my-collection'
response = client.search_faces(
CollectionId=collection_id,
FaceId='62745d77-17ec-4dea-8509-91e26eab2c2d', # image3で検索
FaceMatchThreshold=80, # レスポンスを一致度80%以上に制限
MaxFaces=5)
print(response)
{
"SearchedFaceId": "62745d77-17ec-4dea-8509-91e26eab2c2d",
"FaceMatches": [
{
"Similarity": 99.93736267089844,
"Face": {
"FaceId": "5ae99bab-eaa7-4e1a-b8c7-8fa8bf453107",
"BoundingBox": {
"Width": 0.38203099370002747,
"Height": 0.3321950137615204,
"Left": 0.3100360035896301,
"Top": 0.3712399899959564
},
"ImageId": "4860ed57-16fd-3bee-9312-8021d71efc9b",
"ExternalImageId": "image1",
"Confidence": 100.0
}
},
{
"Similarity": 99.91512298583984,
"Face": {
"FaceId": "4ea5f764-f85f-450f-9eaa-47147c1942c4",
"BoundingBox": {
"Width": 0.21916800737380981,
"Height": 0.41977399587631226,
"Left": 0.4726499915122986,
"Top": 0.2902500033378601
},
"ImageId": "6c715dc7-39b6-39a1-be65-a1775b1a4f78",
"ExternalImageId": "image2",
"Confidence": 100.0
}
}
],
"FaceModelVersion": "4.0",
}
しっかりと画像1・2がマッチしたので成功です。
コレクションから顔データを削除
コレクションに追加した顔データを削除します。
各顔データが持つ一意の識別子Face IDの配列をAPIリクエストに付与することで削除できます。
今回は画像1・2をコレクションから削除してみます。
collection_id = 'my-collection'
faces = ['4ea5f764-f85f-450f-9eaa-47147c1942c4', '5ae99bab-eaa7-4e1a-b8c7-8fa8bf453107'] # image1と2を削除
response = client.delete_faces(
CollectionId=collection_id,
FaceIds=faces)
print(response)
{
"DeletedFaces": [
"4ea5f764-f85f-450f-9eaa-47147c1942c4",
"5ae99bab-eaa7-4e1a-b8c7-8fa8bf453107"
],
}
画像1・2が削除されたかコレクションの顔データ一覧で確認します。
{
"Faces": [
{
"FaceId": "62745d77-17ec-4dea-8509-91e26eab2c2d",
"BoundingBox": {
"Width": 0.29355600476264954,
"Height": 0.261476993560791,
"Left": 0.443107008934021,
"Top": 0.3821699917316437
},
"ImageId": "799099d1-64ba-3790-9496-e4334489e259",
"ExternalImageId": "image3",
"Confidence": 100.0
}
],
}
しっかりと削除されています。
Amazon Rekognitionは深層学習の知識がない方でも簡単に画像分析ができるサービスなので是非使ってみてください。
次回は Amazon Rekognitionを用いた画像分析CMSの作成方法を紹介します。