概要
Raspberry Pi でSIM経由で通信する顔認証システムを作成し、認証結果を kintone で管理するシステムを構築します。
今回は、Raspberry Pi 内に保管した画像を使って顔が同じかを比較判定します。
顔認証システム構築シリーズ
Raspberry Pi で顔を認識しファイルに保存する
https://qiita.com/yukataoka/items/7510217f4b6efdefff06
Amazon Rekognition で顔が同じか比較判定し、感情などの情報を取得する
https://qiita.com/yukataoka/items/3fde5d6b22255ff1aed9
Raspberry Pi でCO2センサを使う
https://qiita.com/yukataoka/items/a3b4065e8210b8f372ff
Raspberry Pi で温湿度気圧センサを使う
https://qiita.com/yukataoka/items/8f9046587c978e91f689
環境
前回の以下の内容を参照ください。
https://qiita.com/yukataoka/items/7510217f4b6efdefff06#%E7%92%B0%E5%A2%83
Python boto3 環境の設定
boto3 は AWS (Amazon Web Services) を Python から操作するためのライブラリです。
pip3 で簡単にインストールできます。
$ sudo pip3 install boto3
boto3 の基本的な使い方については、「Python boto3 でAWSを自在に操ろう ~入門編~」の情報を参考にすると良いでしょう。
AWS 側の設定
IAM で AmazonRekognitionFullAccess 権限を持つプログラムのみからアクセスするユーザを追加し、アクセスキーを保管します。
ユーザの追加やアクセスキーについては、「アクセスキーについて」の情報を参考にすると良いでしょう。
Python3 のコード
AWS の rekognition を利用して、顔写真の比較結果を表示します。
また、顔検出から感情データの取得結果を表示します。
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import boto3
import json
class Faces:
def __init__(self, access='', secret='' , region='ap-northeast-1'):
self.client=boto3.client('rekognition',
aws_access_key_id = access,
aws_secret_access_key = secret,
region_name = region
)
# 顔写真を比較する
def Compare(self, sourceFile='source.jpg', targetFile='target.jpg'):
imageSource = open(sourceFile,'rb')
imageTarget = open(targetFile,'rb')
response = self.client.compare_faces(SimilarityThreshold=70,
SourceImage={'Bytes': imageSource.read()},
TargetImage={'Bytes': imageTarget.read()})
for faceMatch in response['FaceMatches']:
similarity = faceMatch['Similarity']
position = faceMatch['Face']['BoundingBox']
confidence = faceMatch['Face']['Confidence']
print('O ' + targetFile + ' face at ' +
str(position['Left']) + ' ' +
str(position['Top']) +
' matches with ' + str(confidence) + '% confidence, ' +
str(similarity) + '% similarity')
for faceUnmatch in response['UnmatchedFaces']:
position = faceUnmatch['BoundingBox']
confidence = faceUnmatch['Confidence']
print('X ' + targetFile + ' face at ' +
str(position['Left']) + ' ' +
str(position['Top']) +
' unmatches with ' + str(confidence) + '% confidence')
imageSource.close()
imageTarget.close()
return response['FaceMatches']
# 顔検出から感情データを取得
def Detect(self, sourceFile='source.jpg'):
imageSource = open(sourceFile,'rb')
response = self.client.detect_faces(Image={'Bytes': imageSource.read()},Attributes=['ALL'])
print('Detected faces for ' + sourceFile)
for faceDetail in response['FaceDetails']:
position = faceDetail['BoundingBox']
print('The face at ' +
str(position['Left']) + ' ' +
str(position['Top']) +
'. The detected face is between ' + str(faceDetail['AgeRange']['Low']) +
' and ' + str(faceDetail['AgeRange']['High']) + ' years old. ' +
' Gender is ' + faceDetail['Gender']['Value'] + '. ')
print('Emotions attributes:')
print(json.dumps(faceDetail['Emotions'], indent=4, sort_keys=True))
return response
if __name__ == "__main__":
face = Faces('aws_access_key_id', 'aws_secret_access_key')
print('================================')
face.Compare('My01.jpg', 'My02.jpg')
print('================================')
face.Compare('My01.jpg', 'My03.jpg')
print('================================')
face.Compare('My03.jpg', 'My04.jpg')
print('================================')
face.Compare('My03.jpg', 'My05.jpg')
print('================================')
face.Compare('My03.jpg', 'Other01.jpg')
print('================================')
face.Compare('My03.jpg', 'Other02.jpg')
print('================================')
face.Compare('My03.jpg', 'Other03.jpg')
print('================================')
face.Compare('My03.jpg', 'Other04.jpg')
print('================================')
face.Compare('My03.jpg', 'Other05.jpg')
print('================================')
print('\n')
print('--------------------------------')
face.Detect('My01.jpg')
print('--------------------------------')
face.Detect('My02.jpg')
print('--------------------------------')
face.Detect('My03.jpg')
print('--------------------------------')
face.Detect('My04.jpg')
print('--------------------------------')
face.Detect('My05.jpg')
print('--------------------------------')
face.Detect('Other01.jpg')
print('--------------------------------')
face.Detect('Other02.jpg')
print('--------------------------------')
face.Detect('Other03.jpg')
print('--------------------------------')
face.Detect('Other04.jpg')
print('--------------------------------')
face.Detect('Other05.jpg')
print('--------------------------------')
結果
以下のサンプルデータと結果から、2つの顔画像のマッチ、アンマッチ精度は相当高いようです。
こちらで公開できないですが、保有する写真から眼鏡顔を選んで比較しましたが、完ぺきにアンマッチを判定しました。
テスト画像の Other01.jpg, Other02.jpg, Other04.jpg, Other05.jpg は、「ぱくたそ」のフリー素材を利用させていただきました。
その他にも、以下の面白い結果を得ることができました。
- 顔検出で My01.jpg の背後にいる人を検知していますが、性別は間違えています。
- 顔検出で My02.jpg はHAPPYが 97.32% ですが、確かに朗らかな感じが強いです。
- 顔検出で My05.jpg はCALM(穏やかな)が 90.51% ですが、そんな感じでしょうか。
- 顔検出で Other03.jpg は息子ですが、祭りの恰好で性別を間違えています。獅子舞は検出されていません。
注意
Amazon Rekognition の 顔の比較 Webサイトで実行した場合のレスポンスの json と Python の boto3 で取得した json とはレイアウトは同じですが、結果のデータが異なります。
Webサイトでは、比較側の顔が複数ある場合 FaceMatches に全ての顔が分類され UnmatchedFaces は空となります。
boto3で取得した場合は、比較側の顔が複数ある場合でも顔が合致する顔が FaceMatches に、合致しない場合は UnmatchedFaces に分類されます。(顔が1つの場合でも同じ。)
さすがに、このような現象は許して欲しいですね。
================================
O My02.jpg face at 0.4581129848957062 0.07815402746200562 matches with 100.0% confidence, 99.81407928466797% similarity
================================
O My02.jpg face at 0.4581129848957062 0.07815402746200562 matches with 100.0% confidence, 99.81407928466797% similarity
================================
O My03.jpg face at 0.2972644567489624 0.3247520625591278 matches with 99.99977111816406% confidence, 97.09852600097656% similarity
================================
O My04.jpg face at 0.5282963514328003 0.5222135782241821 matches with 99.99996185302734% confidence, 98.2182388305664% similarity
================================
O My05.jpg face at 0.2938196659088135 0.2693774104118347 matches with 99.99998474121094% confidence, 97.79974365234375% similarity
================================
X Other01.jpg face at 0.39465853571891785 0.18935610353946686 unmatches with 99.99995422363281% confidence
================================
X Other02.jpg face at 0.35288524627685547 0.16854149103164673 unmatches with 100.0% confidence
================================
X Other03.jpg face at 0.3426309823989868 0.32221511006355286 unmatches with 99.9999771118164% confidence
================================
X Other04.jpg face at 0.4581896960735321 0.18310882151126862 unmatches with 100.0% confidence
================================
X Other05.jpg face at 0.3525817394256592 0.26986002922058105 unmatches with 100.0% confidence
================================
--------------------------------
Detected faces for My01.jpg
The face at 0.171476617455 0.124303229153. The detected face is between 29 and 45 years old. Gender is Male.
Emotions attributes:
[
{
"Confidence": 1.3882617950439453,
"Type": "CALM"
},
{
"Confidence": 0.5102754831314087,
"Type": "SAD"
},
{
"Confidence": 85.1082763671875,
"Type": "HAPPY"
},
{
"Confidence": 3.5353944301605225,
"Type": "SURPRISED"
},
{
"Confidence": 3.0688531398773193,
"Type": "DISGUSTED"
},
{
"Confidence": 2.9705846309661865,
"Type": "ANGRY"
},
{
"Confidence": 3.4183461666107178,
"Type": "CONFUSED"
}
]
The face at 0.923280537128 0.317661702633. The detected face is between 20 and 38 years old. Gender is Female.
Emotions attributes:
[
{
"Confidence": 45.22486114501953,
"Type": "CONFUSED"
},
{
"Confidence": 45.277984619140625,
"Type": "ANGRY"
},
{
"Confidence": 46.153038024902344,
"Type": "CALM"
},
{
"Confidence": 45.34050369262695,
"Type": "SURPRISED"
},
{
"Confidence": 45.16493606567383,
"Type": "DISGUSTED"
},
{
"Confidence": 48.69762420654297,
"Type": "SAD"
},
{
"Confidence": 49.141056060791016,
"Type": "HAPPY"
}
]
--------------------------------
Detected faces for My02.jpg
X The face at 0.458112984896 0.078154027462. The detected face is between 15 and 25 years old. Gender is Male.
Emotions attributes:
[
{
"Confidence": 0.37020349502563477,
"Type": "CONFUSED"
},
{
"Confidence": 0.08613979816436768,
"Type": "SAD"
},
{
"Confidence": 0.8607620596885681,
"Type": "SURPRISED"
},
{
"Confidence": 0.602418065071106,
"Type": "DISGUSTED"
},
{
"Confidence": 0.7131559252738953,
"Type": "ANGRY"
},
{
"Confidence": 97.3235092163086,
"Type": "HAPPY"
},
{
"Confidence": 0.04381405934691429,
"Type": "CALM"
}
]
(中略)
--------------------------------
Detected faces for My05.jpg
X The face at 0.293819665909 0.269377410412. The detected face is between 35 and 52 years old. Gender is Male.
Emotions attributes:
[
{
"Confidence": 3.0812907218933105,
"Type": "CONFUSED"
},
{
"Confidence": 0.8279056549072266,
"Type": "ANGRY"
},
{
"Confidence": 90.508056640625,
"Type": "CALM"
},
{
"Confidence": 2.1059083938598633,
"Type": "SURPRISED"
},
{
"Confidence": 0.7003881931304932,
"Type": "DISGUSTED"
},
{
"Confidence": 1.9108589887619019,
"Type": "SAD"
},
{
"Confidence": 0.8655884265899658,
"Type": "HAPPY"
}
]
(中略)
--------------------------------
Detected faces for Other03.jpg
X The face at 0.342630982399 0.322215110064. The detected face is between 9 and 14 years old. Gender is Female.
Emotions attributes:
[
{
"Confidence": 3.8436155319213867,
"Type": "SAD"
},
{
"Confidence": 65.46427917480469,
"Type": "CALM"
},
{
"Confidence": 17.642349243164062,
"Type": "CONFUSED"
},
{
"Confidence": 2.095968723297119,
"Type": "DISGUSTED"
},
{
"Confidence": 9.949064254760742,
"Type": "ANGRY"
},
{
"Confidence": 0.7067313194274902,
"Type": "SURPRISED"
},
{
"Confidence": 0.29799211025238037,
"Type": "HAPPY"
}
]
(後略)
--------------------------------
参考サイト
Amazon Rekognition - Python Code Samples
https://gist.github.com/alexcasalboni/0f21a1889f09760f8981b643326730ff
イメージ間の顔の比較
https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/faces-comparefaces.html
イメージ内の顔の検出
https://docs.aws.amazon.com/ja_jp/rekognition/latest/dg/faces-detect-images.html
Amazon Rekognitionで2つの画像から顔を検出・比較する
https://dev.classmethod.jp/cloud/make-full-use-rekognition/