AIサービスを利用して顔認証してみた③

はじめに

こんにちは。呉屋です。
今回は、前回投稿したサービスの設計・構築方法について紹介します。
このシリーズ最後となります。

構築したものは、Webサイトから人物画像をAI分析して、類似人物を検出するサービスです。
詳細はこちらを参照ください。
 AIサービスを利用して顔認証してみた②

Rekognition


AWS構成図は、以下となります。

設計書

設計ポイント

現在、新たな技術・サービスに対し、実現可能なのか・市場効果がありそうか検証を行っています。
その際、なるべく時間をかけずに作り、周りの意見をもらって改善する というプロセスを繰り返しています。
視点が違うアイディアをもらうことで「こうしたらもっと良くなる」「この技術と連携したら面白そう」など具体的なイメージを掴みやすく、楽しみながら作れます!

コスパよく作る上で考慮したポイントを紹介します。

サーバレス・マネージドサービスの利用

 サーバ「EC2」を利用する場合、ある程度の処理時間・負荷予測が必要です。
 また、OSのパッチ・ミドルウェアのアップデートといった様々な運用が発生します。
 しかし、サーバレス「Lambda」はその考慮が一切不要となります。
 処理分のリクエストや負荷状態によって自動でスケーリングしてくれます。

 次に、マネージドサービスです。
 AWSには「セキュリティ責任共有モデル」でお客様(アカウント管理者)との間で責任の切り分けが定義されています。
 ここはAWS側で責任もつけど、ここはお客様側で責任もって下さい というものです。
 今回は、Lambda・S3といったマネージドサービスを利用することで、インフラ面の管理をできるだけAWS側にもっていくように設計しました。
 セキュリティ責任共有モデルを以下に示します。
 オンプレだと、メーカー?ベンダー?お客様? どちらになるか比べてみて下さい。

AWSモデル

マイクロサービス思考

 マイクロサービス思考とは、用途・目的毎に小さく作り、それを組み合わせる考え方です。
 これにより「変化に強く、柔軟性の高い」サービスになります。
 サービス(アプリ、DB、ネットワーク)が密接だと、複雑化されてブラックボックスになりますよね。
 昔からある基幹系システムは、なかなか改修できず、このようなケースになっていることがあります。
 本サービスは、柔軟性をもたせ、他でも活用しやすい設計にしました。
 また、今回のインプットはWebサイトとなりますが、IoT機器からも可能な仕組みにします。

構築ポイント

各処理の構築方法について紹介します。
上記の設計工程のとおり、全てマネージドサービスを利用して、用途毎にサービスを作りました。

S3でWebサイト構築

 画像ファイルのアップロードを行うWebサイトです。

設計書

 画面描写の「html」ファイルと処理実行の「JavaScript」ファイルを用意します。
 フレームワークは「Vue.js」を使用しました。
 私自身触れたことはありませんでしたが、LINEアプリでも使用されている人気のフレームワークです。
 作成した2つのファイルをS3にアップロードします。

 最後にWebサイトのホスティング設定を行います。

S3

 これでWebサイトの完成です!
 Webサーバーを構築する場合、ApacheやNginxが必要ですが、S3を利用すれば簡単です! 

 次にセキュリティ対応として、S3の「バケットポリシー」で制限します。

 ①アクセスは、社内ネットワークのみ許可
 ②必要なS3アクションのみ許可

S3

 以上がWebサイトの構築設定でした。
 次は実行処理についてです。

設計書

Lambdaで画像をS3にアップロード

 Lambdaを使って、Webから送られてきた画像ファイルをS3にアップロードします。
 苦労した点は「画像ファイルがバイナリ形式でBase64にエンコードされているので、デコードすること」です。
 うーん、意味不明ですよね(笑)

 Base64とは、64進数を意味する言葉で全てのデータをアルファベット(a~z, A~z)と数字(0~9)、一部の記号(+,/)の64文字で表すエンコード方式です。
 使用する必要性は、 画像などのバイナリデータを文字列に置き換えてHTMLに埋め込むことで、受け取り側での誤解釈を防ぎ安全に通信してHTTPリクエストの回数を減らすことができるためです。

 つまり、Webサイトからバイナリ形式で送られてくるので、受け取り側のLambdaで変換する必要があります。
 Lambdaは、Pythonコードで記述しました。

 変換した後、アップロード先のS3フォルダとファイル名を設定してOKです。
 この辺りは、ググると例が多くあったので順調にいきました!
 (エラーハンドリングとか改善すべき点は多いです。。。)

import json
import boto3
import base64
from datetime import datetime, timezone

def lambda_handler(event, context):
    # 画像保存場所の設定
    s3 = boto3.resource('s3')
    bucket = s3.Bucket('XXXXX')
    folder = 'XXXXX/'

    # バイナリがBase64にエンコードされているので、ここでデコード
    imageBody = base64.b64decode(event['body-json'])
    # アップロードした画像ファイル名は処理実行時間とする
    TextTime = datetime.now().strftime('%Y-%m-%d-%H-%M-%S')
    # 必要な部分だけを切り取る
    images = imageBody.split(b'\r\n',4)
    
    # S3にアップロードする
    key = folder + TextTime +".jpg"
    bucket.put_object(
        Body = images[4],
        Key = key
    )
    
    # ファイル名をレスポンス値で使いやすいように別名で保存
    filename = TextTime +".jpg"
    # 画像名を Web側で取得するための戻り値
    return {
        'isBase64Encoded': False,
        'statusCode': 200,
        'headers': {'Access-Control-Allow-Origin' : '*' ,
        'Content-Type' :'application/json'},
        'body': '{"filename":"'+ filename + '"}',
        'filename' : filename,
    }

LambdaでRekognitionの比較分析

 Lambdaを使って、S3画像とコレクション画像をRekognitionで比較分析します。
 ポイントは、RekognitionのAPIを理解して使うことです。

 以下のAPIが用意されています。

 ①物体とシーンの検出(DetectLables API)
  ⇒イメージ内の物体やシーンおよびコンセプトを検知
   (例:動物園、キリン)

 ②顔の分析(DetectFaces API)
  ⇒属性(性別、感情、顔の特徴)を検知
   (例:男、笑顔)

 ③顔の比較(CompareFaces API)
  ⇒2つの画像内の顔が同一人物であるかを検知
   (例:類似度〇%)

 ④顔の認識(IndexFaces/SearchFacesByImage API)
  ⇒顔コレクションの中から個人(アイデンティティ)を検知
   顔コレクションとは、顔の特徴ベクトルの検索可能なインデックス

 今回は、アップロードされた画像から似た顔を検出するサービスのため、④のAPIを使用しました!
 予めコレクションに認証したい人物を登録しておき、ファイルをパラメータ指定するだけで分析できます!
 また、類似度も簡単に表示できました!

Rekognition
import boto3
import json
import math

BUCKET='XXXXX'
COLLECTION_ID='XXXXX'
# 返却する画像数
MAX_FACES=5

# 類似度の丸め
digit = 4
digit10 = 10 ** (digit - 1)

def lambda_handler(event, context):
    
    if event['file_name'] != '':
        file_name= "XXXXX/" + event['file_name']
    else:
        file_name = "dummy"
    
    if event['similarity'] != '':
        similarity=int(event['similarity'])
    else:
        # 類似度のデフォルト値
        similarity=80
    
    # Rekognition接続用クライアント作成
    client=boto3.client('rekognition')
    
    response=client.search_faces_by_image(
        Image={
            "S3Object": {
                "Bucket": BUCKET,
                "Name": file_name,
			}
		},
		MaxFaces=MAX_FACES,
		CollectionId=COLLECTION_ID,
		FaceMatchThreshold=similarity,
	)
    
    # レスポンス用配列
    result = []
    
    faceMatches = response['FaceMatches']
    
    # 一致する顔がヒットした場合
    if len(faceMatches) >= 1:
        # ヒットした顔画像分だけループ
        for matchFace in faceMatches:
            res_similarity = matchFace['Similarity']
            res_fileName = matchFace['Face']['ExternalImageId']
            res_json = { "FileName" : res_fileName, "Similarity" : str(math.floor(res_similarity * digit10) / digit10) + "%" }
            result.append(res_json)
        return(result)
    else:
        return({ "FileName" : "No Matched Faces...", "Similarity" : "-"})

API GatewayとLambdaの連携

 API Gatewayを利用して、作成したLambdaをAPIとして公開できるようにします。
 これにより、Webサイトからhttps通信でLambdaが実行できます。

 API Gateway作成後にLambdaを紐づけると、以下のようになります。
 エンドポイントURLが作成されるので、これをWebサイトから使用します。
 この連携は、サーバレス開発を行う中で何度も使用しますので、チュートリアル等で試すことをおすすめします。

Lambda

さいごに

このように全てAWSサービスを利用して作ることができました。
チーム内で試行錯誤したり、周囲の意見もらったりしてカタチにできました!

現在、気軽に開発できる環境が多くあります。
技術力がなくても、アイディアさえあれば、サービスは作れます。
私も次は「IoT」に挑戦してみたいと思います!

みなさんも頭の中の構想をアウトプットしてはいかがでしょうか(^o^)/