LoginSignup
12

More than 3 years have passed since last update.

posted at

updated at

初心者でもできる、LambdaでRekognitionのコレクション機能で大人数の顔認識サーバレスシステム

目的 & コレクション機能の概要

学校の集合写真で、誰が写っているのかを認識するために、顔比較の機能を実装したく、AWS Rekognitionの機能を目につけた。
意外と公式ドキュメント以外の資料があんまり為、ここで自分で整理した。
実すごく使いやすい、単純な処理なので、画像認識やAWSに興味がある初心者でもぜひ試してみましょう!

AWSの権限設定は面倒なことがあるかもしれないですが、今回の内容とあんまり直接の関係がないため割愛させてください。

公式のデモこちら:
https://ap-northeast-1.console.aws.amazon.com/rekognition/home?region=ap-northeast-1#/face-comparison

16名の学生があるクラス(イメージ)
14408339_PW36.jpg
これが元データとして、コレクションに事前に一枚一枚顔を登録する
登録する際に、ラベルを付ける

例えば:
14408339_PW36.jpg
ラベル: 山田

そして、8人の集合写真が一枚あるとして

認識した顔に付けたラベルの結果として返してくる。
(例)「山田」「田中」「石井」「高橋」「鈴木」「山下」「木村」「上村」

アーキテクチャ

スクリーンショット 2019-05-31 9.31.32.png

S3
選んだ理由
1.Lambdaからそのままファイル読み込みやすい
2.Lambdaのトリガーとして起こすため
3.Rekognition機能もS3からファイル直接読むことができる
機能
Webサーバでアップロードした際、Lambdaのトリガーになり、写真ファイルの読み込み

Lambda
選んだ理由
Rekognition、DynamoDBとセットとして使う
機能
1.アップロードした写真データをRekognitionに渡す
2.Rekognitionの処理結果をDynamoDBに書き込む

Rekognition
機能
1.顔の元データを登録
2.検知した顔のラベル付け、結果をLambdaに返す

DynamoDB
選んだ理由
LambdaとRDS(MySQL)は相性が良くない,なぜなら、RDSの同時接続に耐えられないから
参考記事
Lambda+RDSはアンチパターン
機能
Rekognitionの処理結果を格納する

事前準備

この部分はaws-cliを使った

コレクションの作成

 > aws rekognition create-collection --collection-id "[自分のコレクション名]"

成功した結果

{
    "StatusCode": 200,
    "CollectionArn": "aws:rekognition:ap-northeast-1:570955322844:collection/[自分のコレクション名]",
    "FaceModelVersion": "4.0"
}

作成したコレクションの一覧を見る

 > aws rekognition list-collections
{
    "CollectionIds": [
        "sample",
        "[自分のコレクション名]"
    ],
    "FaceModelVersions": [
        "4.0",
        "4.0"
    ]
}

FaceModelVersionsにある"4.0"は現在使っている学習済みのモデルバージョンです。

その他のコマンド
コレクションに登録した顔の一覧
aws rekognition list-faces --collection-id "[自分のコレクション名]"

コレクションに登録した顔を削除 (間違いて登録する際にはこれで削除できる)
aws rekognition delete-faces

コレクションに顔を登録 (これはlambdaでやる)
aws rekognition index-faces --image

メイン処理

S3のファイルのパスをチェックし、それぞれです応じて処理を分ける

  1. コレクションに顔を登録処理 collectionフォルダーの物はindex_facesを呼ぶ
  2. 顔識別処理 collection以外の処理はsearch_faces_by_image
  3. search_faces_by_imageの結果insertDynamoDBを呼ぶ
from __future__ import print_function

import boto3
from boto3.dynamodb.conditions import Key, Attr
from decimal import Decimal
import json
import urllib.parse

rekognition = boto3.client('rekognition')
dynamodb = boto3.resource('dynamodb')

def lambda_handler(event, context):
    # bucketから取り出し
    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.parse.unquote_plus(event['Records'][0]['s3']['object']['key'], encoding='utf8')

    # パスからフォルダー名を取り出す
    folder_str = key.split("/", 1)

    # コレクションのフォルダーにアップロードしたものであれば、コレクション登録ロジックに入る
    # 僕の場合に'collection'というフォルダーにした
    if folder_str[0] == 'collection':  # <--- フォルダー名
        str = folder_str[1].split("_", 1)
        # コレクションに顔を登録処理
        index_faces(bucket, key, str[0])
        return

    # 顔識別処理
    response = search_faces_by_image(bucket, key)        
    str = key.split("_", 1)

    faces = response['FaceMatches']
    # DynamoDBに書き込む
    table = dynamodb.Table('[DYNAMODBのテーブル名]')
    for face in faces:
       # ExternalImageIdは自分で事前登録したラベル名
       insertDynamoDB(table, str[0], face['Face']['ExternalImageId'])

    return

コレクションに顔を登録処理

rekognition.index_faces()でS3のファイルを登録する
S3にアップロードしたファイルはこの子にしてみる
アップロードファイルパス
collection/青山らら.png として

ラベルは「青山らら」にする

def index_faces(bucket, key, labelId):
    response = rekognition.index_faces(CollectionId="[コレクションID]",
                                        Image={"S3Object": {"Bucket": bucket, "Name": key}},
                                        ExternalImageId=labelId,
                                        MaxFaces=1,
                                        QualityFilter="AUTO",
                                        DetectionAttributes=['ALL'])
    return response

レスポンス
一部抜粋

        {
            "FaceId": "262a08f3-b7ba-474d-b1a2-6530073ece54", <-- 登録成功したID
            "BoundingBox": {
                "Width": 0.2804960012435913,
                "Height": 0.5630229711532593,
                "Left": 0.41263899207115173,
                "Top": 0.23804500699043274
            },
            "ImageId": "f3b8191a-27ff-326d-ac21-1c49d18642b1",
            "ExternalImageId": "青山らら", <-- ラベル
            "Confidence": 100.0
        }

顔識別処理

rekognition.search_faces_by_image()でS3のファイルを検知する

アップロードしたファイルはこちら「青山らら」ちゃんと誰か知らない人
パスは特にフォルダー付けない、 ******.pngで大丈夫


def search_faces_by_image(bucket, key):
    threshold = 70  #類似度、 これより低い結果をレスポンスに含めない、 デフォルトは80
    maxFaces = 15  #最大検知可能な顔数
    response = rekognition.search_faces_by_image(CollectionId="[コレクションID]", 
                                                Image={"S3Object": {"Bucket": bucket, "Name": key}},
                                                FaceMatchThreshold=threshold,
                                                MaxFaces=maxFaces)
    return response

レスポンス
一部抜粋

{
    "SearchedFaceBoundingBox": {
        "Width": 0.15396510064601898,
        "Height": 0.27054980397224426,
        "Left": 0.704308032989502,
        "Top": 0.18812672793865204
    },
    "SearchedFaceConfidence": 100,
    "FaceMatches": [ <--- この配列に一致した顔の結果が帰ってくる
        {
            "Similarity": 74.76554870605469, <--- 類似度、この場合は74%
            "Face": {
                "FaceId": "262a08f3-b7ba-474d-b1a2-6530073ece54", <-- 先程の登録した顔のID
                "BoundingBox": {
                    "Width": 0.2804960012435913,
                    "Height": 0.5630229711532593,
                    "Left": 0.41263899207115173,
                    "Top": 0.23804500699043274
                },
                "ImageId": "f3b8191a-27ff-326d-ac21-1c49d18642b1",
                "ExternalImageId": "青山らら",   <--- 登録したラベルの内容
                "Confidence": 100
            }
        }
    ],
    "FaceModelVersion": "4.0",
}

類似度に関して、ドキュメントには多くの法律執行のユースケースでは、偶発的な誤認識を減らすため、99% 以上の高いしきい値を使用することをお勧めします。

DynamoDB

LambdaからDynamoDBに書き込むもすごく簡単 put_itemを呼ぶだけ

def insertDB(table, student_id, name):
    table.put_item(
        Item = {
            "student_id": student_id, <-- 学生のID
            "name": name <-- ExternalImageId登録したラベルの内容この場合は青山らら
        }
    )

全体のコード

おまけ、顔認識に関しての話

こちらの去年年末の記事ですが、グーグル、顔認識APIの提供を当面控えると言明
https://japan.cnet.com/article/35130142/

AWSの顔認識のAPIの提供も控えろうという声もあると聞いたことがある。

その日になると、こちらのAPIを使ってみようか
最近AI分野に力に入れている中国、非常に強力なAPIを無料公開している
顔、ボティ、ジェスチャーなの幅広いの画像認識機能がある

Face++ API
https://www.faceplusplus.com/

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
12