Amazon Web Services ブログ

S+Camera と Amazon Rekognition を組み合わせて来客分析を行う

本記事では、IoT@Loft #9 で ソラコム様にご紹介いただいた、S+Camera Basic (以下 S+Camera) と Amazon RekognitionAmazon Elasticsearch Service などを組み合わせたデモを実現する方法を説明します。このデモでは、店舗の入り口に設置した S+Camera で顔を検出、検出した顔を Amazon S3 にアップロード、Amazon Rekognition を用いて分析することで、顧客の年齢や性別などの分析や、お得意様来店時の通知などを行うことができます。

Amazon Rekognition では、機械学習の専門知識を必要とせずに、実績のある高度にスケーラブルな深層学習テクノロジーを使用して、アプリケーションに画像およびビデオ分析を簡単に追加できるようになります。Amazon Rekognition を使用すると、画像と動画の物体、人物、テキスト、シーン、活動を特定し、不適切なコンテンツを検出できます。また、Amazon Rekognition カスタムラベルを使用することで、ビジネスニーズに合わせた画像の物体やシーンを特定できます。

S+Camera は SIM を搭載しているため、店舗外やイベント会場などのWi-Fiが整っていない環境でもAWSと連携し、来客数の分析などのPoCをスピーディに実施することができます。また、常時画像や動画をアップロードするかわりに顔検出のアルゴリズムをカメラ側で実行することで、必要な場合に限ってクラウド側へデータをアップロードし通信量の節約が可能です。そして、検出したい顔のコレクションをクラウド側に持たせてクラウドで個人を認識することで、カメラ側のアルゴリズムのアップデートを行わなくとも、認識したい人の設定を柔軟に変更することができます。

本記事で構築するデモのアーキテクチャは下図の通りです。ソラコム様の記事では、S+Cameraでの顔検出のアルゴリズム実施やAWSとの連携方法をご紹介されています(下図水色の点線)。本記事では S+Camera から Amazon S3 にアップロードされた画像に対して分析や通知機能を実装する方法を扱います(下図オレンジ色の点線)。

architecture

なお、本記事で扱う内容に関して、顔の画像データのプライバシーやセキュリティなどに十分に注意して実装いただく必要があります。Amazon Rekognition の FAQ のデータプライバシーや、Amazon S3 の FAQ のセキュリティについてもあわせてご参照ください。

それでは早速、デモの構築方法を紹介いたします。

事前準備

  • AWS CLI および pip3 がインストール済みの PC

Amazon Rekognition のコレクション作成

来店時に通知を行いたいお得意様を登録するためのコレクションを Amazon Rekognition に作成します。あらかじめ、コレクションに登録したいお得意様の顔写真を 名前.jpg (例: tanaka.jpg) のようなファイル名で準備しておきます。ファイル名の 名前 の部分を、お得意様(VIP)検知時の通知内容として利用します。

まずは、コレクション用の S3 バケットを作成し、画像をアップロードします。

  • Amazon S3 のコンソール を開きます
  • 左側のメニューの バケット を選び、右側の バケットを作成 ボタンをクリックします
  • 任意の名前でバケットを作成します (例: vip-bucket-20200701)
  • バケットの一覧から、作成したバケットをクリックします
  • 先ほど保存した画像ファイルをすべて選択して、この画面にドラッグ&ドロップし、 アップロード をクリックします

続いて、 Amazon Rekognition で顔認識を行うための、コレクションを作成します。

AWS CLI をインストールした PC のターミナル から以下のコマンドを実行します。

export COLLECTION_ID=vip-collection
aws rekognition create-collection --collection-id $COLLECTION_ID

以下のような出力が返ってくれば、vip-collection という名前のコレクションが作成されています。

{
    "StatusCode": 200,
    "CollectionArn": "aws:rekognition:your-region:012345678901:collection/vip-collection",
    "FaceModelVersion": "4.0"
}

続いて、このコレクションにお得意様の顔を登録していきます。先ほど作成した S3 バケット名を環境変数に登録します。vip-collection-20200701の部分は自身が作成されたものに書き換えてください。

export BUCKET_NAME="vip-bucket-20200701"

以下のコマンドを実行して、先ほど S3 バケットにアップロードした全画像をコレクションに登録します。

for key in $(aws s3 ls s3://$BUCKET_NAME/ | awk '{print $4}'); do
  name=$(echo $key | sed 's/\.[^\.]*$//')
  echo "index: $key"
  aws rekognition index-faces --collection-id $COLLECTION_ID \
  --image "S3Object={Bucket=$BUCKET_NAME,Name=$key}" \
  --external-image-id $name \
  --max-faces=1
done

コレクションに登録された顔の数を確認します。

aws rekognition describe-collection --collection-id $COLLECTION_ID

以下のような結果が出力されるので、 FaceCount の値を確認します。以下の場合は2つの顔がコレクションに登録されていることが分かります。

{
    "FaceCount": 2,
    "FaceModelVersion": "4.0",
    "CollectionARN": "arn:aws:rekognition:your-region:012345678901:collection/vip-collection",
    "CreationTimestamp": 1592111200.081
}

以上でコレクションの作成は完了です。

お得意様来店通知用の Amazon SNS の設定

お得意様の来店を検知した際にEメールで通知が飛ぶように、Amazon SNS の設定を行います

  • Amazon SNS のコンソール を開きます
  • 左側メニューの トピック をクリックし、右側の トピックの作成 をクリックします
  • 名前に vip-notification-topic を入力し、トピックの作成 をクリックします
  • 作成されたトピックの画面が表示されるので、詳細ARN の値をひかえておきます(後のAmazon Lambdaの手順で利用します)
  • 画面の中央付近の、サブスクリプションの作成 をクリックします
  • プロトコル: Eメール を選択し、エンドポイントに通知先のメールアドレスを入力、サブスクリプションの作成 をクリックします
  • 確認用のメールが届くので、“Confirm subscription” のリンクをクリックしてメールアドレスの確認を行います

この手順では通知先としてEメールを利用しましたが、Amazon SNSを利用すると、Eメールの他にSMSやプッシュ通知、HTTPSによるウェブフック経由での通知などを行うことも可能です。

顔認識用の AWS Lambda の作成

続いて、カメラから Amazon S3 に画像がアップロードされた際に Amazon Rekognition で顔認識を実行し、認識結果を Amazon Elasticsearch Service に送信したり、お得意様来店検知時に Amazon SNS へ通知したりする AWS Lambda の関数を作成します。

まず自分の PC のお好きな場所にフォルダを作成し、以下のコードを lambda_function.py として保存します。

import json
import logging
import os
import uuid

import boto3
import requests
from requests_aws4auth import AWS4Auth

logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)

reko = boto3.client("rekognition")
sns = boto3.client("sns")

# Get settings from environmental variables
es_url = os.getenv("ES_URL")
region = os.getenv("REGION")
topic_arn = os.getenv("TOPIC_ARN")

# Get credentials
credentials = boto3.Session().get_credentials()
aws_auth = AWS4Auth(credentials.access_key, credentials.secret_key, region, 'es', session_token=credentials.token)


def process_record(record):
    """ Submit face recognition result to Elasticsearch service and SNS """
    bucket = record["s3"]["bucket"]["name"]
    key = record["s3"]["object"]["key"]
    timestamp = record["eventTime"]
    logger.info(f"bucket: {bucket}, key: {key}")

    res = reko.detect_faces(
        Image={
            'S3Object': {
                'Bucket': bucket,
                'Name': key,
            }
        },
        Attributes=["ALL"]
    )
    
    # Post detected faces to Elasticsearch
    for face in res["FaceDetails"]:
        data = {
            "timestamp": timestamp,
            "AgeLow": face["AgeRange"]["Low"],
            "AgeHigh": face["AgeRange"]["High"],
            "Smile": face["Smile"]["Confidence"],
            "Gender": face["Gender"]["Value"],            "Emotions": {d["Type"]: d["Confidence"] for d in face["Emotions"]}
        }
        response = requests.post(f"{es_url}/record/face/{uuid.uuid4()}",
                                 auth=aws_auth,
                                 headers={"Content-Type": "application/json"},
                                 data=json.dumps(data))
        logger.info(f"result: code={response.status_code}, response={response.text}")

    res = reko.search_faces_by_image(
        CollectionId='vip-collection',
        Image={
            'S3Object': {
                'Bucket': bucket,
                'Name': key,
            }
        },
        MaxFaces=10,
        FaceMatchThreshold=95,
        QualityFilter='AUTO'
    )

    # Send a message if VIP arrived
    if res["FaceMatches"]:
        msg = "VIP arrived: "
        msg += ", ".join(face["Face"]["ExternalImageId"] for face in res["FaceMatches"])
        sns.publish(TopicArn=topic_arn, Message=msg, Subject="VIP notification")
        logger.info(f"Notify {msg}")


def lambda_handler(event, context):
    for record in event['Records']:
        process_record(record)
    return {"result": "ok"}

次に PC のターミナルを開き、lambda_function.py を作成したフォルダに移動し、以下のコマンドを実行し、lambda.zip ファイルを作成します。

cd 作成したフォルダ
pip3 install requests-aws4auth -t .
zip lambda.zip -r ./

続いて、ブラウザから AWS Lambda の作成を行います。

  • AWS Lambda のコンソール を開きます
  • 左側のメニューの 関数 を選択し、右側の 関数の作成 をクリックします
  • 以下の情報を入力して、 関数の作成 をクリックします
    • 一から作成
    • 関数名: rekognition-lambda
    • ランタイム: Python 3.8
    • 実行ロール: AWSポリシーテンプレートから新しいロールを作成
      • ロール名: rekognition-lambda-role
      • ポリシーテンプレート: 以下のポリシーを選択
        • Amazon S3 オブジェクトの読み取り専用アクセス権限
        • Elasticsearch のアクセス権限
        • Amazon SNS 発行ポリシー
  • 作成された Lambda 関数のコンソールの 関数コード で以下の操作をします
    • 右側の アクション から .zip ファイルをアップロード を選択
    • 先ほど作成した lambda.zip を選択
    • 画面右上の 保存 をクリック

来客分析用の Amazon Elasticsearch Service のセットアップ

本記事では来客分析のダッシュボードとして Amazon Elasticsearch Service の Kibana を利用します。なお、以下の手順では Amazon Elasticsearch Service のアクセス元のIPアドレスによって接続元を制限することで Elasticsearch のドメインを保護しておりますが、接続元のIPアドレスが変わりうるようなユースケースでは Amazon Cognito によるユーザ認証などの方法をご検討ください。

  • Amazon Elasticsearch Service のコンソール を開きます
  • 左側のメニューの ダッシュボード を選択し、新しいドメインの作成 をクリックします
  • 以下の設定を行なっていきます
    • Step 1: デプロイタイプの選択
      • デプロイタイプの選択: 開発およびテスト
      • Elasticsearch のバージョン: 7.4
      • 次へ をクリック
    • Step 2: ドメインの設定
      • Elasticsearch ドメイン名: rekognition-domain
      • データノード
        • インスタンスタイプ: t2.small.elasticseasrch
      • 上記以外はデフォルト設定のまま 次へ をクリック
    • Step 3: アクセスとセキュリティの設定
      • ネットワーク構成: パブリックアクセス
      • アクセスポリシー: カスタムアクセスポリシー よりポリシーを2つ追加します
        • 1つ目
          • タイプを選択: IPv4アドレス
          • プリンシパルを入力: IPアドレスチェッカーで調べた、接続元の IPv4 アドレスを入力 (例: 123.1.23.45)
          • アクションを選択: 許可
        • 2つ目
          • タイプを選択: IAM ARN
          • プリンシパルを入力: arn:aws:iam::アカウントID:role/service-role/rekognition-lambda-role
            • 上記の アカウントID の部分は、利用している AWS のアカウントIDに置き換えます
            • アカウントIDは アカウント設定 のページで確認できます
          • アクションを選択: 許可
      • 上記以外はデフォルト設定のまま 次へ をクリック
    • Step 4: 確認
      • 設定内容に問題がなければ 確認 をクリック

Amazon Elasticsearch Service のドメインが作成されるまで10分程度かかります。ドメインのステータスが アクティブ になるまで待ちましょう。

ドメインのステータスが変わったら、概要タブの エンドポイント の URL をコピーしておきます
(例: https://search-rekognition-domain-xxxx.your-region.es.amazonaws.com)。

AWS Lambda の設定

続いて、 Lambda 関数に環境変数を設定するために、先ほど作成した Lambda 関数の画面に戻ります。

  • 画面下部の 環境変数 > 環境変数を管理 をクリック
  • 環境変数の追加 をクリック
  • 以下の2つの環境変数を入力し、保存 をクリック
    • 1つ目
      • キー: ES_URL
      • : 先ほどコピーした URL
    • 2つ目
      • キー: REGION
      • : 利用しているリージョン (例: ap-northeast-1)
    • 3つ目
      • キー: TOPIC_ARN
      • : 先ほどコピーした Amazon SNS トピックのARN

また、Lambda の実行ロールに権限を付与します。

  • 画面上部の アクセス権限 > 実行ロール > rekognition-lambda-role をクリックします
  • IAM ロールの画面が開くので アクセス権限 > ポリシーをアタッチします をクリックします
  • AmazonRekognitionReadOnlyAccess にチェックを入れて、右下の ポリシーのアタッチ をクリックします

そして、S3 への画像アップロード時に Lambda が実行されるようにトリガーの設定を行います。

  • 画面上部の 設定 > Designer > +トリガーを追加 をクリック
  • トリガーの設定S3 を選択し、以下の設定を入力し 追加 をクリックします
    • バケット: 顔画像のアップロード用のバケット(ソラコム様の記事の手順で作成していない場合は、別途ご作成ください)
    • イベントタイプ: すべてのオブジェクト作成イベント
    • サフィックス: .jpg (アップロードされる画像の拡張子にあわせてご変更ください)

以上で、S3 に画像がアップロードされた際に Lambda 関数が実行、認識結果が Elasticsearch Service に書き込まれ、お得意様の来店検知時にメールで通知が飛ぶようになります。なお、S3 にアップロードされた画像の保存が不要な場合は、上記の Lambda 関数の最後に画像を削除する処理を追加する、もしくは S3 バケットのライフサイクルポリシーを設定するなどの方法で、自動で画像を削除することができます。

Kibana の設定

最後に Amazon Elasticsearch Service の Kibana を用いて、顔認識した結果を分析するためのダッシュボードを作成します。

まず、Kibana のダッシュボードを開きます。

Kibana の画面が開いたら、まずはインデックスパターンの設定を行います。

  • 左側の歯車のアイコンをクリック
  • 左側の Index Patterns を選択し、右側の Create index pattern をクリックします
  • Step 1 of 2: Define index pattern
    • Index pattern: record と入力し、 Next step をクリックします
  • Step 2 of 2: Configure settings
    • Time Filter field name: timestamp を選択
    • Create index pattern をクリックします
  • 以下のような画面が表示され、レコードの型が分析されているのが分かります

kibana - index

Kibana でレコードの確認

次に、Kibana で Amazon Elasticsearch Service に登録されたレコードを確認します。

  • 左側のコンパス(Discover)のアイコンをクリックします
  • 以下のような画面が表示され、各時刻に認識された人の年齢、性別などの情報が確認できます

kibana - discover

Kibana での可視化

最後に、認識結果をグラフを用いて可視化してみます。例えば、来店者の年齢推定結果を分析します。

  • 左側のグラフのアイコンをクリックし、画面中央の Create new visualization をクリックします
  • Horizontal Bar をクリックします
  • New Data Table / Choose a source では record* をクリックします
  • 左側の Metrics > Y-Axis に以下の設定をします
    • Aggregation: Count を選択
  • Buckets > + Add をクリックし、 X-axis を選択します
  • Metrics の上にある再生ボタンをクリックし、変更を適用します

以下のようなグラフが表示され、来客の年齢の傾向を可視化することができました。

kibana - visualize

 

最後に、画面上部の Save をクリックし、グラフを保存します。

同様に、性別や表情から読み取れる感情についても Visualization を作成し1つのダッシュボード上に表示することで、下図のように来客の傾向をリアルタイムに分析するためのダッシュボードを作成することができます。

kibana - dashboard

さいごに

この記事では、S+Camera と Amazon Rekognition, Amazon Elasticsearch Service, Amazon SNS などのAWSサービスを組み合わせて、Wi-Fiが整っていない環境でもカメラの画像から来客の傾向分析やお得意様の来店通知などを実現する方法を紹介しました。Amazon Rekognition の詳細な機能についてはドキュメントもご参照ください。冒頭でも述べたとおり、本記事で扱う内容に関して、顔の画像データのプライバシーやセキュリティなどには、十分にご注意の上ご実装ください。

また、本記事では紹介しませんでしたが、Amazon Kinesis Video Streams を用いることで、Wi-Fiや有線ネットワーク環境で常時カメラからの動画をストリーミングし、再生や分析に利用することができます。こちらについてはハンズオンも提供しているため、お客様のネットワーク環境や分析の目的に応じてより良い方法を選択して下さい。

著者について

mihira三平 悠磨

ソフトウェアエンジニアとして会話AIやロボット開発を経験しました。AWS では IoT スペシャリストソリューションアーキテクトとして、お客様の IoT 関連案件を支援しています。