I'd like to try Rekognition's CompareFaces, but I don't see a full example of the syntax for using the HTTP API. Assuming I have two images, how would I call this API from Python to retrieve a similarity score?
There is little documentation around using the HTTP API for AWS Rekognition, but it is pretty simple to use the model that most code uses to hit AWS service HTTP endpoints.
Important information about the code that follows:
You must have requests
installed. If you don't have it, you can run the following in your shell (doing it in virtualenv
is recommended).
pip install requests
The us-east-1
region is used. Rekognition is currently supported in us-east-1
, eu-west-1
, and us-west-2
so you can modify the code to support different region endpoints as you wish.
It expects two files to exist on disk for reading, called source.jpg
and target.jpg
.
As she's in the most recent movie I saw, I'm using images of Felicity Jones from Star Wars: Rogue One as my source and target.
The source.jpg
is:
The target.jpg
is:
It includes code to do signing with AWS Signature Version 4. There are libraries out there that will do the signature generation for you, but I didn't want to rely too much on third party libs in order to demonstrate a complete example.
The AWS credentials you're using should have a valid policy for Rekognition.
It was written for Python 2.7 (shouldn't be terribly difficult to move to Python 3).
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import base64
import datetime
import hashlib
import hmac
import json
import requests
# Key derivation functions
# http://docs.aws.amazon.com/general/latest/gr/signature-v4-examples.html#signature-v4-examples-python
def sign(key, msg):
return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()
def getSignatureKey(key, date_stamp, regionName, serviceName):
kDate = sign(('AWS4' + key).encode('utf-8'), date_stamp)
kRegion = sign(kDate, regionName)
kService = sign(kRegion, serviceName)
kSigning = sign(kService, 'aws4_request')
return kSigning
if __name__ == '__main__':
# Read credentials from the environment
access_key = os.environ.get('AWS_ACCESS_KEY_ID')
secret_key = os.environ.get('AWS_SECRET_ACCESS_KEY')
# Uncomment this line if you use temporary credentials via STS or similar
#token = os.environ.get('AWS_SESSION_TOKEN')
if access_key is None or secret_key is None:
print('No access key is available.')
sys.exit()
# This code shows the v4 request signing process as shown in
# http://docs.aws.amazon.com/general/latest/gr/sigv4-signed-request-examples.html
host = 'rekognition.us-east-1.amazonaws.com'
endpoint = 'https://rekognition.us-east-1.amazonaws.com'
service = 'rekognition'
# Currently, all Rekognition actions require POST requests
method = 'POST'
region = 'us-east-1'
# This defines the service target and sub-service you want to hit
# In this case you want to use 'CompareFaces'
amz_target = 'RekognitionService.CompareFaces'
# Amazon content type - Rekognition expects 1.1 x-amz-json
content_type = 'application/x-amz-json-1.1'
# Create a date for headers and the credential string
now = datetime.datetime.utcnow()
amz_date = now.strftime('%Y%m%dT%H%M%SZ')
date_stamp = now.strftime('%Y%m%d') # Date w/o time, used in credential scope
# Canonical request information
canonical_uri = '/'
canonical_querystring = ''
canonical_headers = 'content-type:' + content_type + '\n' + 'host:' + host + '\n' + 'x-amz-date:' + amz_date + '\n' + 'x-amz-target:' + amz_target + '\n'
# list of signed headers
signed_headers = 'content-type;host;x-amz-date;x-amz-target'
# Our source image: http://i.imgur.com/OK8aDRq.jpg
with open('source.jpg', 'rb') as source_image:
source_bytes = base64.b64encode(source_image.read())
# Our target image: http://i.imgur.com/Xchqm1r.jpg
with open('target.jpg', 'rb') as target_image:
target_bytes = base64.b64encode(target_image.read())
# here we build the dictionary for our request data
# that we will convert to JSON
request_dict = {
'SimilarityThreshold': 75.0,
'SourceImage': {
'Bytes': source_bytes
},
'TargetImage': {
'Bytes': target_bytes
}
}
# Convert our dict to a JSON string as it will be used as our payload
request_parameters = json.dumps(request_dict)
# Generate a hash of our payload for verification by Rekognition
payload_hash = hashlib.sha256(request_parameters).hexdigest()
# All of this is
canonical_request = method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers + '\n' + signed_headers + '\n' + payload_hash
algorithm = 'AWS4-HMAC-SHA256'
credential_scope = date_stamp + '/' + region + '/' + service + '/' + 'aws4_request'
string_to_sign = algorithm + '\n' + amz_date + '\n' + credential_scope + '\n' + hashlib.sha256(canonical_request).hexdigest()
signing_key = getSignatureKey(secret_key, date_stamp, region, service)
signature = hmac.new(signing_key, (string_to_sign).encode('utf-8'), hashlib.sha256).hexdigest()
authorization_header = algorithm + ' ' + 'Credential=' + access_key + '/' + credential_scope + ', ' + 'SignedHeaders=' + signed_headers + ', ' + 'Signature=' + signature
headers = { 'Content-Type': content_type,
'X-Amz-Date': amz_date,
'X-Amz-Target': amz_target,
# uncomment this if you uncommented the 'token' line earlier
#'X-Amz-Security-Token': token,
'Authorization': authorization_header}
r = requests.post(endpoint, data=request_parameters, headers=headers)
# Let's format the JSON string returned from the API for better output
formatted_text = json.dumps(json.loads(r.text), indent=4, sort_keys=True)
print('Response code: {}\n'.format(r.status_code))
print('Response body:\n{}'.format(formatted_text))
If you get the code running, it should output something like this:
Response code: 200
Response body:
{
"FaceMatches": [],
"SourceImageFace": {
"BoundingBox": {
"Height": 0.9448398351669312,
"Left": 0.12222222238779068,
"Top": -0.017793593928217888,
"Width": 0.5899999737739563
},
"Confidence": 99.99041748046875
}
}
The simplest thing you can do is to use boto3
.
The code would be simplified to something like the following, as all the signature generation and JSON work become unnecessary.
Be sure that you have configured boto3
with credentials in the environment or via the configuration file, or put your credentials inline with the code. For more information, see boto3
configuration.
The code for this uses the boto3
Rekognition API.
import pprint
import boto3
# Set this to whatever percentage of 'similarity'
# you'd want
SIMILARITY_THRESHOLD = 75.0
if __name__ == '__main__':
client = boto3.client('rekognition')
# Our source image: http://i.imgur.com/OK8aDRq.jpg
with open('source.jpg', 'rb') as source_image:
source_bytes = source_image.read()
# Our target image: http://i.imgur.com/Xchqm1r.jpg
with open('target.jpg', 'rb') as target_image:
target_bytes = target_image.read()
response = client.compare_faces(
SourceImage={ 'Bytes': source_bytes },
TargetImage={ 'Bytes': target_bytes },
SimilarityThreshold=SIMILARITY_THRESHOLD
)
pprint.pprint(response)
The above boto3
example should output this:
{u'FaceMatches': [],
'ResponseMetadata': {'HTTPHeaders': {'connection': 'keep-alive',
'content-length': '195',
'content-type': 'application/x-amz-json-1.1',
'date': 'Sat, 31 Dec 2016 23:15:56 GMT',
'x-amzn-requestid': '13edda2d-cfaf-11e6-9999-d3abf4c2feb3'},
'HTTPStatusCode': 200,
'RequestId': '13edda2d-cfaf-11e6-9999-d3abf4c2feb3',
'RetryAttempts': 0},
u'SourceImageFace': {u'BoundingBox': {u'Height': 0.9448398351669312,
u'Left': 0.12222222238779068,
u'Top': -0.017793593928217888,
u'Width': 0.5899999737739563},
u'Confidence': 99.99041748046875}}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With