概要
画像に写る人物の顔を検出するプログラムを作りましょう。
画像解析サービスはいろいろありますが、手軽に使えるものといえば『OpenCV』か『Amazon AWS』ではないでしょうか。
前回はOpenCVによる顔検出を行いました。
OpenCVの難点は、多数用意されている検出アルゴリズムの中からどれを選択すべきかの判断が困難である点でした。
今回はAWSの顔検出サービスを使用してみることにしましょう。
AWSはクラウドサービスの中で世界一のシェアを誇るサービスですが、AIに関しても『Machine Learning』というその名のとおり機械学習サービスを提供しています。
その中の Amazon Rekogniton が、顔検出に該当するサービスです。
Amazon Rekognition は、画像の顔領域を検出するだけでなく、目の位置や感情分析までしてくれます。
Amazon Rekognitionは確度も教えてくれるよ。
検出結果がどれくらい信頼できるかも判断できるんだ。
参考までに、顔検出サービスとしてのOpenCVとAWSの比較を挙げておきます。
メリット | デメリット | |
---|---|---|
OpenCV | ・無料 ・ローカルで完結 | ・検出アルゴリズムを開発者が判断して選択 |
Amazon Rekognition | ・AWSが深層学習で自動検出 | ・従量課金(登録後12か月無料枠あり) ・AWSへのアクセスアカウントが必要 |
学習すること
- AWSへサインアップ(新規登録)してサービスを使えるようにする方法
- AWS boto3を使用してAWS Rekognitionへアクセスする方法
- AWS Rekognitionを使用して画像に写る人物の顔検出をする方法
- AWS S3へ画像をアップロードしたり、ダウンロードする方法
前提知識
- Python3プログラミング
この記事を作成した当時はAWS未経験だったね。
AWSの使用経験がない前提で進めていくよ。
開発環境
- Python3実行環境(Windows、MacOS、Linux上のPython仮想環境)
※当記事ではWindows10を使用します。
開発実施
手順
AWSについて調べた結果、次の手順で進めていけばよさそうです。
- AWSを使えるようにする
- AWSに新規登録する
- IAMユーザを作成する
- IAMユーザを使って、ローカルPCからAWSへアクセスできるようにする
- 顔検出用の画像を準備する
- 画像を用意する
- S3にバケットを作成する
- S3バケットへ画像をアップロードする
- AWS Machine Learningサービスで顔を検出する
- Rekognitionを使ってS3バケットの画像から顔を検出する
- 顔検出した画像を表示する
- Rekognitionの顔検出結果を受け取り、顔を枠で囲んだ画像を表示する
登場人物の関係を図にまとめました。
ざっくりこんなかんじです。
画像をS3へアップロードしていますが、これくらいの作業ならS3を使う必要はないかもしれません。
例えば、画像を一旦AWSサーバインスタンスの /tmp に仮置きしても同じことはできます。
今回は、S3を使う方法も学習しよう!
1. AWSを使えるようにする
AWSに新規登録する
AWSへサインアップして開発用アカウントを作成します。
Amazonのショッピング用アカウントは使用せず別のアカウントを新しく作るのがよいでしょう。
AWSのサービスはほぼ従量制ですが、1年間は無料で使えるそうです。
アカウントを作成すると自動的に「ルートユーザ」が作成されるので、管理者として作業するときは今後このアカウントを使っていくことになります。
管理者としてではなくAWSのサービスを使って何かをする場合は、アカウント内にIAMという作業用ユーザを作り、そのIAMユーザで作業するのがセオリーです。
AWSの登録作業についてダラダラと話していくよ。
退屈ならスキップしてね。
IAMユーザを作成する
IAMユーザを作成するとき認証情報タイプというものを選択しなくてはいけません。
- コンソールによるアクセスタイプ
- プログラムによるアクセスタイプ
コンソールによるアクセスタイプとは、AWSのサイトへログイン(サインイン)してブラウザでサービスを使用するタイプのことです。
プログラムによるアクセスタイプとは、外部のプログラムからネットワーク経由でサービスを使用するタイプのことです。
外部のプログラムとは、AWSとは別のサイトや端末で実行するプログラムのことを指します。
今回は自分のWindows端末でプログラムを組んで実行するので、後者のプログラムによるアクセスタイプを選択します。
IAMユーザを作るときに必ずすべきことがもう1つあります。グループの作成です。
ユーザは必ずグループの配下に作成しないといけないそうです。
これもちゃちゃっと作って、さきほど作成したIAMユーザを所属させます。
さて、IAMユーザとグループの作成が終わりました。が、もう1つ大事なことがあります。
アクセス権限の付与です。
AWSのユーザには、作成当初はアクセス権限というものがありません。要するに何もできません。
AWSのサービスを使うためには
「誰が、何に対して、何をすることができるのか(もしくはできないように禁止するのか)」
という権限を付与してあげないといけません。
今回は画像の顔検出をしたいので、次の権限を付与することにしました。
- AmazonRekognitionFullAccess
- AmazonS3FullAccess
- CloudWatchFullAccess
AmazonRekognitionFullAccessは、ML(Machine Learning)サービスの1つであるRekognitionを使うための権限です。RecognitionでなくRekognitionです。
AmazonS3FullAccessは、ストレージサービスであるS3へアクセスするための権限です。Rekognitionが顔検出するための画像ファイルをアップロードするために、S3を使用します。
もう1つ、CloudWatchFullAccessはログ出力するために必要な権限です。プログラムの中で標準出力へ書き出したメッセージなども記録されるそうです。
AmazonS3FullAccessは権限の範囲が大き過ぎるよ。
本来ならS3バケット個別のアクセス権限にすべきだね。
今回は初めてだしトライアルだから仕方ないけど。
IAMユーザを使って、ローカルPCからAWSへアクセスできるようにする
さきほど作成したIAMユーザを使ってAWSへアクセスするために、インストールすべきものが2つあります。
- boto3
- AWS-CLI
boto3はローカルPCなどからAWSサービスを使用するためのプログラミングライブラリです。
AWS-CLIは、ローカルPCのコマンドラインから、AWSアカウントを使用してAWSへアクセスするための統合ツールです。
ローカルPCのPython仮想環境へ boto3 と AWS-CLI をインストールし、つづけてAWS-CLIへIAMユーザの「アクセスキー」と「シークレットキー」を設定します。
これでローカルPCのPython仮想環境から、Pythonプログラム経由でAWSサービスを使用することができるようになります。
2. 顔検出用の画像を準備する
画像を探してくる
ネットのフリー素材を検索して、人の顔がいくつか写っている写真を頂戴してきました。
S3にバケットを作成する
AWSサイトへ前述のIAMユーザでログインし、S3へ新規バケットを作成します。
S3バケットへ画像をアップロードする
AWSサイトへログインした状態で、そのまま手動で画像をアップロードしてもよいのですが、ローカルPCのPythonプログラムからboto3を使ってアップロードすることにします。
import boto3
BUCKET_NAME = '{S3バケットの名前}'
KEY_NAME = '{ローカルPCにある画像の名前}'
FILE_NAME = KEY_NAME
class S3(object):
def __init__(self, bucket=BUCKET_NAME, key=KEY_NAME):
self.resource = boto3.resource('s3')
self.bucket = bucket
self.key = key
self.local_file = None
self.key_object = self.resource.Object(bucket, key)
def upload(self, local_file=FILE_NAME):
self.local_file = local_file
self.resource.Bucket(self.bucket).upload_file(Filename=self.local_file, Key=self.key)
def delete(self):
self.resource.Bucket(self.bucket).delete_objects(Delete={'Objects': [{'Key': self.key}]})
def get_object(self):
return self.key_object
def main():
# (1)ClientPCからboto3を使って、ローカルの画像をS3へUploadする
s3 = S3(bucket=BUCKET_NAME, key=KEY_NAME)
s3.upload(local_file=FILE_NAME)
if __name__ == '__main__':
main()
S3バケットに保存するファイルは「Key名」で識別します。
今回アップロードする画像のKey名は、画像ファイルの名前と同じにしました。
クラスS3には、アップロードだけでなく、のちに使用する削除(delete)とオブジェクト取得(get_object)も実装しておきました。
3. AWS Machine Learningサービスで顔を検出する
Rekognitionを使ってS3バケットの画像から顔を検出する
ようやく顔検出です。
これもローカルPCのPythonプログラムで実行します。
boto3でRekognitionサービスへアクセスして、S3バケットの画像から顔を検出してもらいます。
class Detector(object):
def __init__(self):
self.client = boto3.client('rekognition')
def detect_faces(self, bucket, key):
result = None
num_detected = 0
result = self.client.detect_faces(Image={'S3Object': {'Bucket': bucket, 'Name': key}}, Attributes=['ALL'])
print(f'rekognition detect_faces detected {len(result['FaceDetails'])} faces.')
return result
def main():
# (1)ClientPCからboto3を使って、ローカルの画像をS3へUploadする
s3 = S3(bucket=BUCKET_NAME, key=KEY_NAME)
s3.upload(local_file=FILE_NAME)
# (2)ClientPCからboto3を使って、(1)でUploadした画像をRekognitionで顔検出する
detector = Detector()
result = detector.detect_faces(bucket=BUCKET_NAME, key=KEY_NAME)
if result is None:
print('faces not detected.')
if __name__ == '__main__':
main()
print文で出力した内容は、AWSのCloudWatchで参照することができます。
プログラム簡略化のため、デバッグログはloggingではなくprintを使ってるよ
4. 顔検出した画像を表示する
Rekognitionの顔検出結果を受け取り、顔を枠で囲んだ画像を表示する
Rekognitionの検出結果には、画像の中の顔の範囲矩形が座標値として入っています。
その矩形を赤枠で表示してみましょう。
表示する画像はローカルの画像をそのまま読み込んでも問題ありませんが、Rekognitionが検出対象にしたS3バケットの画像をダウンロードして表示することにします。
(理由はただ、S3からダウンロードするプログラミングを書いてみたいためです)
最後に、S3バケットへアップロードした画像を削除しておきます。
import io
from PIL import Image
from PIL import ImageDraw
COLOR_BOX = '#ff0000'
def main():
# (1)ClientPCからboto3を使って、ローカルの画像をS3へUploadする
s3 = S3(bucket=BUCKET_NAME, key=KEY_NAME)
s3.upload(local_file=FILE_NAME)
# (2)ClientPCからboto3を使って、(1)でUploadした画像をRekognitionで顔検出する
detector = Detector()
result = detector.detect_faces(bucket=BUCKET_NAME, key=KEY_NAME)
if result is None:
print('faces not detected.')
# (3)ClientPCからPILを使って、S3画像を、Rekognitionの顔検出結果をもとに顔領域を枠で囲んで表示する
img_object = s3.get_object()
img_response = img_object.get()
img_stream = io.BytesIO(img_response['Body'].read())
img = Image.open(img_stream)
if result is not None:
width_img, height_img = img.size
img_draw = ImageDraw.Draw(img)
for facedetail in result['FaceDetails']:
box = facedetail['BoundingBox']
left_box = width_img * box['Left']
top_box = height_img * box['Top']
width_box = width_img * box['Width']
height_box = height_img * box['Height']
rect = [left_box, top_box, left_box + width_box, top_box + height_box]
img_draw.rectangle(rect, outline=COLOR_BOX, width=8)
img.show()
# (4)ClientPCからboto3を使って、(1)でUploadした画像を削除する
s3.delete()
if __name__ == '__main__':
main()
ではさっそく実行してみましょう。
無事すべての顔を検出することができました。
十分な精度ではないでしょうか。
全員正面を向いていて認識しやすい画像だったね。
もっと複雑な画像の方が、検出性能を試すことができたかもね。
今後の課題
最後に課題を挙げてみました。
- いろんな方向を向いた顔の画像で検出性能を試してみる
- OpenCVの顔検出と比較してみる
- S3へのフルアクセス権限を、バケット個別のアクセス権限へ限定する
- サーバーレスアプリで同じことをやってみる
まとめ
AWS Rekognitionを使って顔検出をしてみました。
OpenCVと違い、AWSアカウントの作成やAWSへアクセスするための開発環境やライブラリが必要ですが、顔検出以外の機能も豊富で、使い勝手もよく、さらに精度も良さそうです。
とはいえ、実用的なアプリにするためには、AWSサービスの呼び出し方や、対象とする画像ファイルの扱いなど、「課題」として挙げた数多くの工夫が必要です。
Python: 3.8
boto3: 1.18.57
コメント