AIサービスを利用して顔認証してみた③
はじめに
こんにちは。呉屋です。
今回は、前回投稿したサービスの設計・構築方法について紹介します。
このシリーズ最後となります。
構築したものは、Webサイトから人物画像をAI分析して、類似人物を検出するサービスです。
詳細はこちらを参照ください。
AIサービスを利用して顔認証してみた②

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

設計ポイント
現在、新たな技術・サービスに対し、実現可能なのか・市場効果がありそうか検証を行っています。
その際、なるべく時間をかけずに作り、周りの意見をもらって改善する というプロセスを繰り返しています。
視点が違うアイディアをもらうことで「こうしたらもっと良くなる」「この技術と連携したら面白そう」など具体的なイメージを掴みやすく、楽しみながら作れます!
コスパよく作る上で考慮したポイントを紹介します。
サーバレス・マネージドサービスの利用
サーバ「EC2」を利用する場合、ある程度の処理時間・負荷予測が必要です。
また、OSのパッチ・ミドルウェアのアップデートといった様々な運用が発生します。
しかし、サーバレス「Lambda」はその考慮が一切不要となります。
処理分のリクエストや負荷状態によって自動でスケーリングしてくれます。
次に、マネージドサービスです。
AWSには「セキュリティ責任共有モデル」でお客様(アカウント管理者)との間で責任の切り分けが定義されています。
ここはAWS側で責任もつけど、ここはお客様側で責任もって下さい というものです。
今回は、Lambda・S3といったマネージドサービスを利用することで、インフラ面の管理をできるだけAWS側にもっていくように設計しました。
セキュリティ責任共有モデルを以下に示します。
オンプレだと、メーカー?ベンダー?お客様? どちらになるか比べてみて下さい。

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

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

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

これでWebサイトの完成です!
Webサーバーを構築する場合、ApacheやNginxが必要ですが、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を使用しました!
予めコレクションに認証したい人物を登録しておき、ファイルをパラメータ指定するだけで分析できます!
また、類似度も簡単に表示できました!

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サイトから使用します。
この連携は、サーバレス開発を行う中で何度も使用しますので、チュートリアル等で試すことをおすすめします。

さいごに
このように全てAWSサービスを利用して作ることができました。
チーム内で試行錯誤したり、周囲の意見もらったりしてカタチにできました!
現在、気軽に開発できる環境が多くあります。
技術力がなくても、アイディアさえあれば、サービスは作れます。
私も次は「IoT」に挑戦してみたいと思います!
みなさんも頭の中の構想をアウトプットしてはいかがでしょうか(^o^)/