本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。
使用 Amazon Rekognition 进行身份验证
Amazon Rekognition 为用户提供了多种操作,可以轻松创建身份验证系统。Amazon Rekognition 允许用户检测图像中的人脸,然后通过比较人脸数据将任何检测到的人脸与其他人脸进行比较。这些人脸数据存储在名为“集合”的服务器端容器中。通过利用 Amazon Rekognition 的人脸检测、人脸比较和集合管理操作,您可以创建带有身份验证解决方案的应用程序。
本教程将演示创建需要身份验证的应用程序的两个常见工作流程。
第一个工作流程涉及在集合中注册新用户。第二个工作流程涉及搜索现有集合,以便登录回归用户。
在本教程中,您将使用 AWS SDK for Python
先决条件
在开始本教程之前,你需要安装 Python 并完成设置 Python AWS 开发工具包
-
已创建 Amazon Simple Storage Service 存储桶,并上传一张您希望用作身份验证的 ID 的图像。
-
已选择第二张图像作为身份验证的目标图像。
创建集合
在集合中注册新用户或搜索用户集合之前,必须先有一个集合可供使用。Amazon Rekognition 集合是一个服务器端容器,用于存储有关检测到的人脸的信息。
创建集合
首先,您将编写一个函数,用于创建供应用程序使用的集合。Amazon Rekognition 存储有关在名为集合的服务器端容器中检测到的人脸的信息。您可以搜索存储在集合中的人脸信息以查找已知人脸。要存储人脸信息,您首先需要使用 CreateCollection
操作创建集合。
-
请为要创建的集合选择名称。在以下代码中,将
collection_id
的值替换为您要创建的集合的名称,并将region
的值替换为用户凭证中定义的区域名称。您可以使用Tags
参数将您想要的任何标签应用到集合中,尽管这不是必需的。CreateCollection
操作将返回有关您创建的集合的信息,包括该集合的 Arn。记下运行代码后收到的 Arn。import boto3 def create_collection(collection_id, region): client = boto3.client('rekognition', region_name=region) # Create a collection print('Creating collection:' + collection_id) response = client.create_collection(CollectionId=collection_id, Tags={"SampleKey1":"SampleValue1"}) print('Collection ARN: ' + response['CollectionArn']) print('Status code: ' + str(response['StatusCode'])) print('Done...') collection_id = 'collection-id-name' region = "region-name" create_collection(collection_id, region)
-
保存并运行代码。复制集合 Arn。
现在 Rekognition 集合已经创建,您可以在该集合中存储人脸信息和标识符。您还可以将人脸与存储的信息进行比较以进行验证。
新用户注册
您需要能够注册新用户并将其信息添加到集合中。注册新用户的过程通常涉及以下步骤:
调用 DetectFaces
操作
编写代码以通过 DetectFaces
操作检查人脸图像的质量。您将使用 DetectFaces
操作来确定摄像头拍摄的图像是否适合由 SearchFacesByImage
操作处理。图像应仅包含一张人脸。您将为 DetectFaces
操作提供本地输入图像文件,并接收图像中检测到的人脸的详细信息。以下示例代码为 DetectFaces
提供输入图像,然后检查图像中是否仅检测到一张人脸。
-
在以下代码示例中,将
photo
替换为要在其中检测人脸的目标图像的名称。您还需要将region
的值替换为与您的账户关联的地区名称。import boto3 import json def detect_faces(target_file, region): client=boto3.client('rekognition', region_name=region) imageTarget = open(target_file, 'rb') response = client.detect_faces(Image={'Bytes': imageTarget.read()}, Attributes=['ALL']) print('Detected faces for ' + photo) for faceDetail in response['FaceDetails']: print('The detected face is between ' + str(faceDetail['AgeRange']['Low']) + ' and ' + str(faceDetail['AgeRange']['High']) + ' years old') print('Here are the other attributes:') print(json.dumps(faceDetail, indent=4, sort_keys=True)) # Access predictions for individual face details and print them print("Gender: " + str(faceDetail['Gender'])) print("Smile: " + str(faceDetail['Smile'])) print("Eyeglasses: " + str(faceDetail['Eyeglasses'])) print("Emotions: " + str(faceDetail['Emotions'][0])) return len(response['FaceDetails']) photo = 'photo-name' region = 'region-name' face_count=detect_faces(photo, region) print("Faces detected: " + str(face_count)) if face_count == 1: print("Image suitable for use in collection.") else: print("Please submit an image with only one face.")
-
保存并运行正在进行的代码。
调用 CompareFaces
操作
您的应用程序需要能够在集合中注册新用户并确认回归用户的身份。您将首先创建用于注册新用户的函数。首先,您将使用该CompareFaces
操作来比较本地input/target image of the user and a ID/stored图像。如果在两张图片中检测到的人脸相符,则可以在集合中进行搜索,以查看用户是否已在其中注册。
首先编写一个函数,将输入图像与您存储在 Amazon S3 存储桶中的 ID 图像进行比较。在以下代码示例中,您需要自行提供输入图像,该图像应在使用某种形式的活跃度检测器后拍摄。您还需要传递存储在 Amazon S3 存储桶中的图像的名称。
-
将
bucket
的值替换为包含源文件的 Amazon S3 存储桶的名称。您还需要将source_file
的值替换为您正在使用的源图像的名称。将target_file
的值替换为您提供的目标文件的名称。将region
的值替换为用户凭证中定义的region
的名称。您还需要使用
similarityThreshold
参数指定响应中返回的匹配结果的最低置信度。只有当置信度高于此阈值时,才会在FaceMatches
数组中返回检测到的人脸。您选择的similarityThreshold
应反映特定使用案例的性质。任何涉及关键安全应用的用例都应使用 99 作为所选阈值。import boto3 def compare_faces(bucket, sourceFile, targetFile, region): client = boto3.client('rekognition', region_name=region) imageTarget = open(targetFile, 'rb') response = client.compare_faces(SimilarityThreshold=99, SourceImage={'S3Object':{'Bucket':bucket,'Name':sourceFile}}, TargetImage={'Bytes': imageTarget.read()}) for faceMatch in response['FaceMatches']: position = faceMatch['Face']['BoundingBox'] similarity = str(faceMatch['Similarity']) print('The face at ' + str(position['Left']) + ' ' + str(position['Top']) + ' matches with ' + similarity + '% confidence') imageTarget.close() return len(response['FaceMatches']) bucket = 'bucket-name' source_file = 'source-file-name' target_file = 'target-file-name' region = "region-name" face_matches = compare_faces(bucket, source_file, target_file, region) print("Face matches: " + str(face_matches)) if str(face_matches) == "1": print("Face match found.") else: print("No face match found.")
-
保存并运行正在进行的代码。
系统将返回一个响应对象,其中包含有关匹配人脸和置信度的信息。
调用 SearchFacesByImage
操作
如果 CompareFaces
操作的置信度高于您选择的 SimilarityThreshold
,则需要在集合中搜索可能与输入图像匹配的人脸。如果在您的集合中找到了匹配项,则表示该用户可能已经在集合中注册,因此无需在您的集合中注册新用户。如果没有匹配项,则可以在集合中注册新用户。
-
首先编写将调用
SearchFacesByImage
操作的代码。该操作将以本地图像文件作为参数,然后在您的Collection
搜索中搜索与所提供图像中检测到的最大面孔匹配的人脸。在以下代码示例中,将
collectionId
的值更改为要搜索的集合。将region
的值替换为与您的账户关联的区域名称。您还需要将photo
的值替换为输入文件的名称。您还需要通过将threshold
的值替换为选定的百分位数来指定相似度阈值。import boto3 collectionId = 'collection-id-name' region = "region-name" photo = 'photo-name' threshold = 99 maxFaces = 1 client = boto3.client('rekognition', region_name=region) # input image should be local file here, not s3 file with open(photo, 'rb') as image: response = client.search_faces_by_image(CollectionId=collectionId, Image={'Bytes': image.read()}, FaceMatchThreshold=threshold, MaxFaces=maxFaces) faceMatches = response['FaceMatches'] print(faceMatches) for match in faceMatches: print('FaceId:' + match['Face']['FaceId']) print('ImageId:' + match['Face']['ImageId']) print('Similarity: ' + "{:.2f}".format(match['Similarity']) + "%") print('Confidence: ' + str(match['Face']['Confidence']))
-
保存并运行正在进行的代码。如果有匹配项,则表示图像中识别出的人已经是集合的一部分,无需继续执行下一步操作。在这种情况下,您可以只允许用户访问应用程序。
调用 IndexFaces
操作
假设在您搜索的集合中未找到匹配项,则需要将该用户的人脸添加到您的集合中。您可以通过调用 IndexFaces
操作来完成操作。当您致电时 IndexFaces,Amazon Rekognition 会提取您输入图像中识别出的人脸的面部特征,并将数据存储在指定的集合中。
-
首先编写代码以调用
IndexFaces
。将的image
值替换为要用作 IndexFaces 操作输入图像的本地文件的名称。您还需要将photo_name
的值替换为输入图像所需的名称。请确保将collection_id
的值替换为您之前创建的集合的 ID。接下来,将region
的值替换为与您的账户关联的区域名称。您还需要为MaxFaces
输入参数指定一个值,该参数定义了图像中应编制索引的最大人脸数。该参数的默认值为 1。import boto3 def add_faces_to_collection(target_file, photo, collection_id, region): client = boto3.client('rekognition', region_name=region) imageTarget = open(target_file, 'rb') response = client.index_faces(CollectionId=collection_id, Image={'Bytes': imageTarget.read()}, ExternalImageId=photo, MaxFaces=1, QualityFilter="AUTO", DetectionAttributes=['ALL']) print(response) print('Results for ' + photo) print('Faces indexed:') for faceRecord in response['FaceRecords']: print(' Face ID: ' + faceRecord['Face']['FaceId']) print(' Location: {}'.format(faceRecord['Face']['BoundingBox'])) print(' Image ID: {}'.format(faceRecord['Face']['ImageId'])) print(' External Image ID: {}'.format(faceRecord['Face']['ExternalImageId'])) print(' Confidence: {}'.format(faceRecord['Face']['Confidence'])) print('Faces not indexed:') for unindexedFace in response['UnindexedFaces']: print(' Location: {}'.format(unindexedFace['FaceDetail']['BoundingBox'])) print(' Reasons:') for reason in unindexedFace['Reasons']: print(' ' + reason) return len(response['FaceRecords']) image = 'image-file-name' collection_id = 'collection-id-name' photo_name = 'desired-image-name' region = "region-name" indexed_faces_count = add_faces_to_collection(image, photo_name, collection_id, region) print("Faces indexed count: " + str(indexed_faces_count))
-
保存并运行正在进行的代码。确定是否要保存
IndexFaces
操作返回的任何数据,例如分配给图像中人物的 FaceID。下一节将探讨如何保存这些数据。在继续操作之前,请复制返回的FaceId
、ImageId
和Confidence
值。
将图像和 FaceID 数据存储在 Amazon S3 和 Amazon DynamoDB 中
获取输入图像的人脸 ID 后,可以将图像数据保存在 Amazon S3 中,而人脸数据和图像 URL 可以输入到 DynamoDB 等数据库中。
-
编写代码,将输入图像上传到 Amazon S3 数据库。在下面的代码示例中,将
bucket
的值替换为您要将文件上传到的存储桶的名称,然后将file_name
的值替换为您要存储在 Amazon S3 存储桶中的本地文件的名称。提供一个用于识别 Amazon S3 存储桶中文件的密钥名称,方法是将key_name
的值替换为您想要为图像文件命名的名称。您要上传的文件与之前的代码示例中定义的文件相同,也就是您使用的输入文件 IndexFaces。最后,将region
的值替换为与您的账户关联的区域名称。import boto3 import logging from botocore.exceptions import ClientError # store local file in S3 bucket bucket = "amzn-s3-demo-bucket" file_name = "file-name" key_name = "key-name" region = "region-name" s3 = boto3.client('s3', region_name=region) # Upload the file try: response = s3.upload_file(file_name, bucket, key_name) print("File upload successful!") except ClientError as e: logging.error(e)
-
保存并运行后续代码示例,将您的输入图像上传到 Amazon Amazon S3。
-
您还需要将返回的人脸 ID 保存到数据库中。这可以通过创建 DynamoDB 数据库表,然后将人脸 ID 上传到该表来完成。以下代码示例将创建 DynamoDB 表。请注意,您只需要运行一次创建此表的代码。在以下代码中,将
region
的值替换为与您的账户关联的区域的值。您还需要将database_name
的值替换为您想要给 DynamoDB 表的名称。import boto3 # Create DynamoDB database with image URL and face data, face ID def create_dynamodb_table(table_name, region): dynamodb = boto3.client("dynamodb", region_name=region) table = dynamodb.create_table( TableName=table_name, KeySchema=[{ 'AttributeName': 'FaceID', 'KeyType': 'HASH' # Partition key },], AttributeDefinitions=[ { 'AttributeName': 'FaceID', 'AttributeType': 'S' }, ], ProvisionedThroughput={ 'ReadCapacityUnits': 10, 'WriteCapacityUnits': 10 } ) print(table) return table region = "region-name" database_name = 'database-name' dynamodb_table = create_dynamodb_table(database_name, region) print("Table status:", dynamodb_table)
-
保存并运行后续代码以创建您的表。
-
创建表后,您可以将返回的内容上传 FaceId 到表中。为此,您需要使用表函数与表建立连接,然后使用
put_item
函数上传数据。在以下代码示例中,将
bucket
的值替换为包含您上传到 Amazon S3 的输入图像的存储桶名称。您还需要将file_name
的值替换为您上传到 Amazon S3 存储桶的输入文件的名称,并将key_name
的值替换为您之前用于识别输入文件的密钥。最后,将region
的值替换为与您的账户关联的区域名称。这些值应与步骤 1 中提供的值相匹配。将分配给人脸的 FaceId ImageId、和置信度值
AddDBEntry
存储在集合中。在下面的函数中提供您在后续IndexFaces
节的步骤 2 中保存的值。import boto3 from pprint import pprint from decimal import Decimal import json # The local file that was stored in S3 bucket bucket = "amzn-s3-demo-bucket" file_name = "file-name" key_name = "key-name" region = "region-name" # Get URL of file file_url = "https://s3.amazonaws.com/{}/{}".format(bucket, key_name) print(file_url) # upload face-id, face info, and image url def AddDBEntry(file_name, file_url, face_id, image_id, confidence): dynamodb = boto3.resource('dynamodb', region_name=region) table = dynamodb.Table('FacesDB-4') response = table.put_item( Item={ 'ExternalImageID': file_name, 'ImageURL': file_url, 'FaceID': face_id, 'ImageID': image_id, 'Confidence': json.loads(json.dumps(confidence), parse_float=Decimal) } ) return response # Mock values for face ID, image ID, and confidence - replace them with actual values from your collection results dynamodb_resp = AddDBEntry(file_name, file_url, "FACE-ID-HERE", "IMAGE-ID-HERE", confidence-here) print("Database entry successful.") pprint(dynamodb_resp, sort_dicts=False)
-
保存并运行后续代码示例,将返回的人脸 ID 数据存储在表中。
现有用户登录
在集合中注册用户后,可以使用 SearchFacesByImage
操作在返回时对其进行身份验证。您需要获取输入图像,然后使用 DetectFaces
检查输入图像的质量。这决定了在运行 SearchFacesbyImage
操作之前是否使用了合适的图像。
致电 DetectFaces 行动
-
您将使用
DetectFaces
操作来检查人脸图像的质量,并确定摄像头拍摄的图像是否适合由SearchFacesByImage
操作处理。输入图像应仅包含一张人脸。以下代码示例获取输入图像并将其提供给DetectFaces
操作。在以下代码示例中,将
photo
的值替换为本地目标图像的名称,并将region
的值替换为与您的账户关联的区域名称。import boto3 import json def detect_faces(target_file, region): client=boto3.client('rekognition', region_name=region) imageTarget = open(target_file, 'rb') response = client.detect_faces(Image={'Bytes': imageTarget.read()}, Attributes=['ALL']) print('Detected faces for ' + photo) for faceDetail in response['FaceDetails']: print('The detected face is between ' + str(faceDetail['AgeRange']['Low']) + ' and ' + str(faceDetail['AgeRange']['High']) + ' years old') print('Here are the other attributes:') print(json.dumps(faceDetail, indent=4, sort_keys=True)) # Access predictions for individual face details and print them print("Gender: " + str(faceDetail['Gender'])) print("Smile: " + str(faceDetail['Smile'])) print("Eyeglasses: " + str(faceDetail['Eyeglasses'])) print("Emotions: " + str(faceDetail['Emotions'][0])) return len(response['FaceDetails']) photo = 'photo-name' region = 'region-name' face_count=detect_faces(photo, region) print("Faces detected: " + str(face_count)) if face_count == 1: print("Image suitable for use in collection.") else: print("Please submit an image with only one face.")
-
保存并运行代码。
致电 SearchFacesByImage 行动
-
编写代码,使用
SearchFacesByImage
将检测到的人脸与集合中的人脸进行比较。您将使用后续“新用户注册”部分中显示的代码,并为SearchFacesByImage
操作提供输入图像。在以下代码示例中,将
collectionId
的值更改为要搜索的集合。您还要将bucket
的值更改为 Amazon S3 存储桶的名称,将fileName
的值更改为该存储桶中的图像文件。将region
的值替换为与您的账户关联的区域名称。您还需要通过将threshold
的值替换为选定的百分位数来指定相似度阈值。import boto3 bucket = 'amzn-s3-demo-bucket' collectionId = 'collection-id-name' region = "region-name" fileName = 'file-name' threshold = 70 maxFaces = 1 client = boto3.client('rekognition', region_name=region) # input image should be local file here, not s3 file with open(fileName, 'rb') as image: response = client.search_faces_by_image(CollectionId=collectionId, Image={'Bytes': image.read()}, FaceMatchThreshold=threshold, MaxFaces=maxFaces)
-
保存并运行代码。
查看返回的 FaceID 和置信度
现在,您可以 FaceId 通过打印出响应元素(如 “相似度” 和 “ FaceId置信度” 属性)来检查匹配项的信息。
faceMatches = response['FaceMatches'] print(faceMatches) for match in faceMatches: print('FaceId:' + match['Face']['FaceId']) print('ImageId:' + match['Face']['ImageId']) print('Similarity: ' + "{:.2f}".format(match['Similarity']) + "%") print('Confidence: ' + str(match['Face']['Confidence']))