从 Python 调用 AWS Rekognition HTTP API 的示例

An example of calling AWS Rekognition HTTP API from Python

我想尝试 Rekognition's CompareFaces,但我没有看到使用 HTTP API 的语法的完整示例。假设我有两张图片,我如何从 Python 中调用此 API 来检索相似度分数?

关于代码的信息

几乎没有关于将 HTTP API 用于 AWS Rekognition 的文档,但使用大多数代码用于命中 AWS 服务 HTTP 端点的模型非常简单。

有关以下代码的重要信息:

  • 您必须安装 requests。如果没有,您可以 运行 在 shell 中执行以下操作(建议在 virtualenv 中执行)。

    pip install requests
    
  • 使用了us-east-1区域。 us-east-1eu-west-1us-west-2 目前支持 Rekognition,因此您可以根据需要修改代码以支持 different region endpoints

  • 它希望磁盘上存在两个文件供读取,名为 source.jpgtarget.jpg

    因为她出现在我最近看的电影中,所以我使用 星球大战:侠盗一号 中 Felicity Jones 的图像作为我的来源和目标。

    source.jpg是:

    target.jpg是:

  • 它包含使用 AWS Signature Version 4 进行签名的代码。有一些库可以为您生成签名,但我不想过多依赖第三方库来演示完整示例。

  • 您使用的 AWS 凭证应该具有有效的 policy for Rekognition.

  • 它是为 Python 2.7 编写的(移动到 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))

代码输出

如果你得到代码 运行ning,它应该输出如下内容:

Response code: 200

Response body: 
{

    "FaceMatches": [],
    "SourceImageFace": {
        "BoundingBox": {
            "Height": 0.9448398351669312,
            "Left": 0.12222222238779068,
            "Top": -0.017793593928217888,
            "Width": 0.5899999737739563
        },
        "Confidence": 99.99041748046875
    }
}

真的,就用boto3

最简单的方法就是使用 boto3.

代码将简化为如下所示,因为所有签名生成和 JSON 工作都变得不必要了。

确保您已在环境中或通过配置文件配置 boto3 凭据,或者将您的凭据与代码内联。有关详细信息,请参阅 boto3 configuration

此代码使用 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)

上面的 boto3 例子应该输出这个:

{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}}