用Python调用AWS Rekognition HTTP API的示例

11

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


1
你想使用HTTP API而不是boto3的原因是什么? - wkl
1个回答

22

关于代码的信息

目前对于使用AWS Rekognition的HTTP API的文档很少,但使用大多数代码用于访问AWS服务的HTTP端点的模型非常简单。

下面是有关代码的重要信息:

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

pip install requests
  • 该代码使用us-east-1区域。Rekognition目前支持us-east-1eu-west-1us-west-2,因此您可以根据需要修改代码以支持不同的区域终点

  • 它期望存在两个磁盘上要读取的文件,分别称为source.jpgtarget.jpg

    由于她是我看到的最近一部电影中的演员,所以我使用《星球大战:侠盗一号》中Felicity Jones的图片作为我的源和目标。

    source.jpg是:Felicity Jones source image

    target.jpg是:Felicity Jones target image

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

  • 您正在使用的AWS凭证应该具有有效的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))
    

    代码输出

    如果你成功运行了这段代码,应该会输出类似以下的内容:

    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 配置

    这段代码使用了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}}
    

    1
    我正在尝试使用boto3,因为它看起来更简单。初始调用不应该是这样的吗:client = boto3.client('rekognition', aws_access_key_id=key, aws_secret_access_key=secret, region_name=region) - jensph
    我能够在AWS控制台中使用Rekognition演示,但是当我使用boto3时出现错误:调用CompareFaces操作时发生错误(AccessDeniedException):用户:X未被授权执行:rekognition:CompareFaces。也许我需要仔细检查我的密钥,但我想确认客户端是否正确设置。 - jensph
    1
    @jensph 如果使用boto3,您可以在请求客户端时指定密钥/秘密/令牌/区域,也可以将它们指定为环境变量。我的代码示例假设后者。还有其他提供凭据的方法。至于您面临的另一个问题,听起来像是您的IAM策略没有授予使用“rekognition”资源的访问权限。 - wkl
    你关于IAM策略的看法是正确的。我已经下载了你使用的两张图片,但在运行上述boto3示例时,我遇到了以下错误:botocore.exceptions.ClientError: An error occurred (InvalidImageFormatException) when calling the CompareFaces operation: Invalid image encoding。我还尝试了其他图片和格式,但仍然出现相同的错误。 - jensph
    1
    @jensph - 我更新了我的boto示例 - 原来在使用boto3时不必像在HTTP API示例中那样对图像字节执行base64编码。 - wkl
    显示剩余2条评论

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接