

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 使用 Lambda 和 Python 检测图像中的标签
<a name="lambda-s3-tutorial-python"></a>

 AWS Lambda 是一项计算服务，无需预置或管理服务器即可使用它来运行代码。您可以从 Lambda 函数中调用 Rekognition API 操作。以下说明显示如何在 Python 中创建用来调用 `DetectLabels` 的 Lambda 函数。

Lambda 函数会调用 `DetectLabels` 并返回图像中检测到的一组标签和检测标签时所依据的置信度级别。

这些说明包括示例 Python 代码，该代码向您展示如何调用 Lambda 函数并向其提供来自 Amazon S3 存储桶或本地计算机的图像。

确保您选择的图像符合 Rekognition 的限制。有关图像[文件类型和大小限制的信息，请参阅 Rekognition 中的指南和DetectLabels 配额](https://docs.aws.amazon.com/rekognition/latest/dg/limits.html)以及 [API](https://docs.aws.amazon.com/rekognition/latest/APIReference/API_DetectLabels.html) 参考。

## 创建 Lambda 函数（控制台）
<a name="lambda-s3-tutorial-python-create"></a>

在此步骤中，您将创建一个空的 Lambda 函数和一个允许您的 Lambda 函数调用 `DetectLabels` 操作的 IAM 执行角色。在后续步骤中，您将添加源代码，也可以选择向 Lambda 函数添加层。

如果您使用的是存储在 Amazon S3 存储桶中的文档，则此步骤还演示了如何授予对存储您文档的存储桶的访问权限。

**创建 AWS Lambda 函数（控制台）**

1. 登录 AWS 管理控制台 并打开 AWS Lambda 控制台，网址为[https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)。

1. 选择**创建函数**。有关更多信息，请参阅[使用控制台创建 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/getting-started-create-function.html)。

1. 选择以下选项：
   + 选择**从头开始创作**。
   + 为**函数名称**输入一个值。
   + 对于**运行时系统**，请选择最新版本的 Python。
   + 对于**架构**，选择 **x86\_64**。

1. 选择**创建函数**以创建 AWS Lambda 函数。

1. 在函数页面上，选择**配置**选项卡。

1. 在**权限**窗格的**执行角色**下，选择角色名称以在 IAM 控制台中打开该角色。

1. 在**权限**选项卡中，依次选择**添加权限**和**创建内联策略**。

1. 选择 **JSON** 选项卡，并将该策略替换为以下策略：

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Action": "rekognition:DetectLabels",
               "Resource": "*",
               "Effect": "Allow",
               "Sid": "DetectLabels"
           }
       ]
   }
   ```

------

1. 选择**查看策略**。

1. 输入策略的名称，例如 *DetectLabels-access*。

1. 选择**创建策略**。

1. 如果您要在 Amazon S3 存储桶中存储用于分析的文档，则必须添加 Amazon S3 访问策略。为此，请在 AWS Lambda 控制台中重复步骤 7 到 11 并执行以下更改。

   1. 对于步骤 8，请使用以下策略。{{bucket/folder path}}替换为 Amazon S3 存储桶和您要分析的文档的文件夹路径。

------
#### [ JSON ]

****  

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Sid": "S3Access",
                  "Effect": "Allow",
                  "Action": "s3:GetObject",
                  "Resource": "arn:aws:s3:::{{bucket/folder path}}/*"
              }
          ]
      }
      ```

------

   1. 在步骤 10 中，选择不同的策略名称，例如 *S3Bucket-access*。

## （可选）创建层（控制台）
<a name="lambda-s3-tutorial-python-layer"></a>

您无需执行此步骤即可使用 Lambda 函数和调用 `DetectLabels`。

该`DetectLabels`操作作为适用于 Python 的 AWS SDK (Boto3) 的一部分包含在默认 Lambda Python 环境中。

如果您的 Lambda 函数的其他部分需要最新的 AWS 服务更新，而这些更新不在默认 Lambda Python 环境中，则可以执行此步骤将最新版本的 Boto3 SDK 作为层添加到您的函数中。

要将 SDK 添加为层，请先创建一个包含 Boto3 SDK 的 zip 文件存档。然后，创建一个层并将 zip 文件存档添加到该层。有关更多信息，请参阅[组合使用层与 Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/invocation-layers.html#invocation-layers-using)。

**创建并添加层（控制台）**

1. 打开命令提示符并输入以下命令，使用最新版本的 AWS SDK 创建部署包。

   ```
   pip install boto3 --target python/.
   zip boto3-layer.zip -r python/
   ```

1. 记下您在本过程的步骤 8 中使用的压缩文件 (boto3-layer.zip) 的名称。

1. 打开 AWS Lambda 控制台，网址为[https://console.aws.amazon.com/lambda/](https://console.aws.amazon.com/lambda/)。

1. 在导航窗格中，选择**层**。

1. 选择**创建层**。

1. 为**名称**和**描述**输入值。

1. 对于**代码输入种类**，选择**上传 .zip 文件**并选择**上传**。

1. 在对话框中，选择您在本过程步骤 1 中创建的 zip 文件存档 (boto3-layer.zip)。

1. 对于**兼容运行时系统**，请选择最新版本的 Python。

1. 选择**创建**以创建层。

1. 选择导航窗格菜单图标。

1. 在导航窗格中，选择**函数**。

1. 在资源列表中，选择您之前在[](#lambda-s3-tutorial-python-create)中创建的函数。

1. 选择**节点**选项卡。

1. 在**层**部分，选择**添加层**。

1. 选择**自定义层**。

1. 在**自定义层**中，选择您在步骤 6 中输入的层名称。

1. 在**版本**中，选择层版本，该版本应为 1。

1. 选择**添加**。

## 添加 Python 代码（控制台）
<a name="lambda-s3-tutorial-python-console-code"></a>

在此步骤中，您将使用 Lambda 控制台代码编辑器，向您的Lambda 函数添加 Python 代码。该代码使用 `DetectLabels` 操作检测图像中的标签。它返回在图像中检测到的一组标签，以及检测标签所依据的置信度级别。

您为 `DetectLabels` 操作提供的文档可以位于 Amazon S3 存储桶或本地计算机中。

**添加 Python 代码（控制台）**

1. 导航至**代码**选项卡。

1. 在代码编辑器中，将 **lambda\_function.py** 中的代码替换为以下代码：

   ```
   import boto3
   import logging
   from botocore.exceptions import ClientError
   import json
   import base64
   
   # Instantiate logger
   logger = logging.getLogger(__name__)
   
   # connect to the Rekognition client
   rekognition = boto3.client('rekognition')
   
   def lambda_handler(event, context):
   
       try:
           image = None
           if 'S3Bucket' in event and 'S3Object' in event:
               s3 = boto3.resource('s3')
               s3_object = s3.Object(event['S3Bucket'], event['S3Object'])
               image = s3_object.get()['Body'].read()
   
           elif 'image' in event:
               image_bytes = event['image'].encode('utf-8')
               img_b64decoded = base64.b64decode(image_bytes)
               image = img_b64decoded
   
   
           elif image is None:
               raise ValueError('Missing image, check image or bucket path.')
   
           else:
               raise ValueError("Only base 64 encoded image bytes or S3Object are supported.")
   
           response = rekognition.detect_labels(Image={'Bytes': image})
           lambda_response = {
               "statusCode": 200,
               "body": json.dumps(response)
           }
           labels = [label['Name'] for label in response['Labels']]
           print("Labels found:")
           print(labels)
   
       except ClientError as client_err:
   
          error_message = "Couldn't analyze image: " + client_err.response['Error']['Message']
   
          lambda_response = {
              'statusCode': 400,
              'body': {
                  "Error": client_err.response['Error']['Code'],
                  "ErrorMessage": error_message
              }
          }
          logger.error("Error function %s: %s",
                       context.invoked_function_arn, error_message)
   
   
       except ValueError as val_error:
   
           lambda_response = {
               'statusCode': 400,
               'body': {
                   "Error": "ValueError",
                   "ErrorMessage": format(val_error)
               }
           }
           logger.error("Error function %s: %s",
                        context.invoked_function_arn, format(val_error))
   
       return lambda_response
   ```

1. 选择**部署**以部署您的 Lambda 函数。

## 添加 Python 代码（控制台）
<a name="lambda-s3-tutorial-python-invoke"></a>

现在您已创建 Lambda 函数，可以调用它来检测图像中的标签。

在此步骤中，您在计算机上运行 Python 代码，该代码会将本地图像或 Amazon S3 存储桶中的图像传递给您的 Lambda 函数。

确保在创建 Lambda 函数的同一 AWS 区域运行代码。您可以在 Lambda 控制台的函数详情页面的导航栏中查看 Lambda 函数的 AWS 区域。

如果 Lambda 函数返回超时错误，请延长 Lambda 函数的超时时间。有关更多信息，请参阅[配置函数超时（控制台）](https://docs.aws.amazon.com/lambda/latest/dg/configuration-function-common.html#configuration-timeout-console)。

有关从您的代码调用 Lambda 函数的更多信息，请参阅[调用 AWS Lambda 函数](https://docs.aws.amazon.com/lambda/latest/dg/lambda-invocation.html)。

**试用您的 Lambda 函数**

1. 执行以下操作（如果尚未这样做）：

   1. 确保用户拥有 `lambda:InvokeFunction` 权限。您可以使用以下策略：

      您可以从 [Lambda 控制台](https://console.aws.amazon.com/lambda/)中的函数概述，获取 Lambda 函数的 ARN。

      要提供访问权限，请为您的用户、组或角色添加权限：
      + 中的用户和群组 AWS IAM Identity Center：

        创建权限集合。按照《AWS IAM Identity Center 用户指南》**中[创建权限集](https://docs.aws.amazon.com//singlesignon/latest/userguide/howtocreatepermissionset.html)的说明进行操作。
      + 通过身份提供者在 IAM 中托管的用户：

        创建适用于身份联合验证的角色。按照《IAM 用户指南》**中[针对第三方身份提供者创建角色（联合身份验证）](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_create_for-idp.html)的说明进行操作。
      + IAM 用户：
        + 创建您的用户可以担任的角色。按照《IAM 用户指南》**中[为 IAM 用户创建角色](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_roles_create_for-user.html)的说明进行操作。
        + （不推荐使用）将策略直接附加到用户或将用户添加到用户组。按照《IAM 用户指南》**中[向用户添加权限（控制台）](https://docs.aws.amazon.com//IAM/latest/UserGuide/id_users_change-permissions.html#users_change_permissions-add-console)中的说明进行操作。

   1. 安装和配置 AWS 适用于 Python 的开发工具包。有关更多信息，请参阅 [第 2 步：设置 AWS CLI 和 AWS SDKs](setup-awscli-sdk.md)。

1. 将以下代码保存到名为 `client.py` 的文件中：

   ```
   import boto3
   import json
   import base64
   import pprint
   
   # Replace with the name of your S3 bucket and image object key
   bucket_name = "name of bucket"
   object_key = "name of file in s3 bucket"
   # If using a local file, supply the file name as the value of image_path below
   image_path = ""
   
   # Create session and establish connection to client['
   session = boto3.Session(profile_name='developer-role')
   s3 = session.client('s3', region_name="us-east-1")
   lambda_client = session.client('lambda',  region_name="us-east-1")
   
   # Replace with the name of your Lambda function
   function_name = 'RekDetectLabels'
   
   def analyze_image_local(img_path):
   
       print("Analyzing local image:")
   
       with open(img_path, 'rb') as image_file:
           image_bytes = image_file.read()
           data = base64.b64encode(image_bytes).decode("utf8")
   
           lambda_payload = {"image": data}
   
           # Invoke the Lambda function with the event payload
           response = lambda_client.invoke(
               FunctionName=function_name,
               Payload=(json.dumps(lambda_payload))
           )
   
           decoded = json.loads(response['Payload'].read().decode())
           pprint.pprint(decoded)
   
   def analyze_image_s3(bucket_name, object_key):
   
       print("Analyzing image in S3 bucket:")
   
       # Load the image data from S3 into memory
       response = s3.get_object(Bucket=bucket_name, Key=object_key)
       image_data = response['Body'].read()
       image_data = base64.b64encode(image_data).decode("utf8")
   
        # Create the Lambda event payload
       event = {
           'S3Bucket': bucket_name,
           'S3Object': object_key,
           'ImageBytes': image_data
       }
   
       # Invoke the Lambda function with the event payload
       response = lambda_client.invoke(
               FunctionName=function_name,
               InvocationType='RequestResponse',
               Payload=json.dumps(event),
               )
   
       decoded = json.loads(response['Payload'].read().decode())
       pprint.pprint(decoded)
   
   def main(path_to_image, name_s3_bucket, obj_key):
   
       if str(path_to_image) != "":
           analyze_image_local(path_to_image)
       else:
           analyze_image_s3(name_s3_bucket, obj_key)
   
   if __name__ == "__main__":
       main(image_path, bucket_name, object_key)
   ```

1. 运行该代码。如果文档在 Amazon S3 存储桶中，请确保它与您之前在 [](#lambda-s3-tutorial-python-create) 步骤 12 中指定的存储桶相同。

   如果成功，代码会针对文档中检测到的每个块类型返回部分 JSON 响应。