【画像分析】Amazon Rekognitionの使い方

amazon-rekognition-method-title CODE

今回は、代表的な画像認識APIの1つであるAmazon Rekognitionの使い方を紹介します。

Amazon Rekognitionは以下のような機能を提供しています。

・オブジェクト、シーン、アクティビティの検出

・顔の検出、顔認識

・ 画像、動画内の不適切なコンテンツの識別

・ 有名人の認識

・ テキストの抽出

本記事では、画像内の顔検出や顔認識の方法を主に扱います。

 

準備

Amazon Linux(EC2)を作成し、IAM ユーザーでアクセスキーとシークレットアクセスを作成。

aws cliのセットアップは省略。

Python3などの環境構築は以下を参照。

https://www.tsukasa-blog.com/programming/django-ec2-apache/
# 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を使用してローカル画像を読み込みます。

 

画像内の顔の検出

画像内の顔のベクトルや表情、シーンなどの情報を表示します。

画像はこの美女の写真を使います。

フリー素材で見つけた綺麗すぎる美女。

rekognition顔認識の画像
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を指定するとより細かな顔データが得られます。

 

画像間の顔の比較

ソース画像内の顔とターゲット画像の顔を比較し、一致度を判定します。

ソース画像は先ほどの美女画像を使い、ターゲット画像は同じ美女が映ってるこの画像を使います。

rekognition顔認識の画像
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もコレクションに追加します。

rekognition顔認識の画像

セクシーすぎる。。。

"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の作成方法を紹介します。