使用 Amazon Rekognition 和 Lambda 标记 Amazon S3 存储桶中的资产 - Amazon Rekognition

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

使用 Amazon Rekognition 和 Lambda 标记 Amazon S3 存储桶中的资产

在本教程中,您将创建一个自动标记位于 Amazon S3 存储桶中的数字资产的 AWS Lambda 函数。Lambda 函数会读取给定 Amazon S3 存储桶中的所有对象。对于存储桶中的每个对象,它都会将图像传递给 Amazon Rekognition 服务以生成一系列标签。每个标签都用于创建应用于图像的标签。在您执行 Lambda 函数后,它会根据给定 Amazon S3 存储桶中的所有图像自动创建标签并将其应用于图像。

例如,假设您运行了 Lambda 函数,并且在 Amazon S3 存储桶中存储了这张图片。

火山喷发,熔岩汩汩而下,火山灰遮天蔽日。

然后,应用程序会自动创建标签并将其应用于图像。

表中显示用于跟踪存储成本的标签,包括“自然”、“火山”、“喷发”、“熔岩”、“山脉”和“户外”,并带有数值。
注意

您在本教程中使用的服务是 AWS 免费套餐的一部分。完成本教程后,我们建议终止您在教程中创建的所有资源,这样您无需为此付费。

本教程使用适用于 Java 的 AWS SDK 版本 2。有关其他 Java V2 教程,请参阅AWS 文档 SDK 示例 GitHub 存储库

先决条件

在开始之前,您需要完成设置 AWS SDK for Java 中的步骤。然后确保执行以下操作:

  • Java 1.8 JDK。

  • Maven 3.6 或更高版本。

  • 一个含有 5-7 张自然图像的 Amazon S3 存储桶。这些图像由 Lambda 函数读取。

配置 IAM Lambda 角色

本教程使用 Amazon Rekognition 和 Amazon S3 服务。将 lambda 支持角色配置为具有允许其从 Lambda 函数调用这些服务的策略。

配置角色
  1. 登录 AWS Management Console 并打开 IAM 控制台,网址为https://console.aws.amazon.com/iam/

  2. 在导航窗格中,选择角色,然后选择创建角色

  3. 选择 AWS 服务,然后选择 Lambda

  4. 选择 Permissions(权限)选项卡。

  5. 搜索 AWSLambdaBasicExecutionRole

  6. 请选择下一个标签

  7. 选择审核

  8. 为角色命名 lambda 支持

  9. 选择创建角色

  10. 选择 lambda 支持以查看概述页面。

  11. 选择附加策略

  12. AmazonRekognitionFullAccess从策略列表中选择。

  13. 选择附加策略

  14. 搜索 A mazonS3 FullAccess,然后选择附加政策

创建项目

创建一个新的 Java 项目,然后使用所需的设置和依赖项配置 Maven pom.xml。确保您的 pom.xml 文件如下所示:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>WorkflowTagAssets</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <name>java-basic-function</name> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencyManagement> <dependencies> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>bom</artifactId> <version>2.10.54</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <dependencies> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-core</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.6</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.13.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-slf4j18-impl</artifactId> <version>2.13.3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.6.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.6.0</version> <scope>test</scope> </dependency> <dependency> <groupId>com.googlecode.json-simple</groupId> <artifactId>json-simple</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>s3</artifactId> </dependency> <dependency> <groupId>software.amazon.awssdk</groupId> <artifactId>rekognition</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.2</version> <configuration> <createDependencyReducedPom>false</createDependencyReducedPom> </configuration> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>

编写代码

使用 AWS Lambda 运行时 Java API 创建定义 Lambda 函数的 Java 类。在此示例中,Lambda 函数有一个名为 Handler 的 Java 类以及此用例所需的其他类。下图显示了项目中的 Java 类。请注意,所有 Java 类都位于名为 com.example.tags 的包中。

项目结构显示了用于标记工作流资产的 Java 类 AnalyzePhotos,例如、、Handler BucketItem、S3Service 和。 WorkItem

为代码创建以下 Java 类:

  • Handl@@ er 使用 Lambda Java 运行时 API 并执行本教程中描述的用例。 AWS 执行的应用程序逻辑位于 handleRequest 方法中。

  • S3Service 使用 Amazon S3 API 来执行 S3 操作。

  • AnalyzePhotos使用 Amazon Rekognition API 来分析图片。

  • BucketItem定义了存储 Amazon S3 存储桶信息的模型。

  • WorkItem定义存储亚马逊 Rekognition 数据的模型。

处理程序类

此 Java 代码代表处理程序类。该类会读取传递到 Lambda 函数的标志。s3Service。 ListBucketObjects方法返回一个 Lis t 对象,其中每个元素都是一个表示对象键的字符串值。如果标志值为真,则通过对列表进行迭代操作应用标签,并通过调用 s3Service.tagAssets 方法将标签应用于每个对象。如果标志值为假,则为 s 3Service。 deleteTagFrom调用删除标签的对象方法。另外,请注意,您可以使用LambdaLogger对象将消息记录到 Amazon CloudWatch 日志中。

注意

确保将存储桶名称分配给 bucketName 变量。

package com.example.tags; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.amazonaws.services.lambda.runtime.LambdaLogger; import java.util.ArrayList; import java.util.List; import java.util.Map; public class Handler implements RequestHandler<Map<String,String>, String> { @Override public String handleRequest(Map<String, String> event, Context context) { LambdaLogger logger = context.getLogger(); String delFlag = event.get("flag"); logger.log("FLAG IS: " + delFlag); S3Service s3Service = new S3Service(); AnalyzePhotos photos = new AnalyzePhotos(); String bucketName = "<Enter your bucket name>"; List<String> myKeys = s3Service.listBucketObjects(bucketName); if (delFlag.compareTo("true") == 0) { // Create a List to store the data. List<ArrayList<WorkItem>> myList = new ArrayList<>(); // loop through each element in the List and tag the assets. for (String key : myKeys) { byte[] keyData = s3Service.getObjectBytes(bucketName, key); // Analyze the photo and return a list where each element is a WorkItem. ArrayList<WorkItem> item = photos.detectLabels(keyData, key); myList.add(item); } s3Service.tagAssets(myList, bucketName); logger.log("All Assets in the bucket are tagged!"); } else { // Delete all object tags. for (String key : myKeys) { s3Service.deleteTagFromObject(bucketName, key); logger.log("All Assets in the bucket are deleted!"); } } return delFlag; } }

S3Service 类

以下类使用 Amazon S3 API 执行 S3 操作。例如,该getObjectBytes方法返回一个表示图像的字节数组。同样,该listBucketObjects方法返回一个 Lis t 对象,其中每个元素都是指定键名的字符串值。

package com.example.tags; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.PutObjectTaggingRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.services.s3.model.ListObjectsResponse; import software.amazon.awssdk.services.s3.model.S3Object; import software.amazon.awssdk.services.s3.model.GetObjectTaggingResponse; import software.amazon.awssdk.services.s3.model.ListObjectsRequest; import java.util.ArrayList; import java.util.List; import software.amazon.awssdk.services.s3.model.Tagging; import software.amazon.awssdk.services.s3.model.Tag; import software.amazon.awssdk.services.s3.model.GetObjectTaggingRequest; import software.amazon.awssdk.services.s3.model.DeleteObjectTaggingRequest; public class S3Service { private S3Client getClient() { Region region = Region.US_WEST_2; return S3Client.builder() .region(region) .build(); } public byte[] getObjectBytes(String bucketName, String keyName) { S3Client s3 = getClient(); try { GetObjectRequest objectRequest = GetObjectRequest .builder() .key(keyName) .bucket(bucketName) .build(); // Return the byte[] from this object. ResponseBytes<GetObjectResponse> objectBytes = s3.getObjectAsBytes(objectRequest); return objectBytes.asByteArray(); } catch (S3Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } return null; } // Returns the names of all images in the given bucket. public List<String> listBucketObjects(String bucketName) { S3Client s3 = getClient(); String keyName; List<String> keys = new ArrayList<>(); try { ListObjectsRequest listObjects = ListObjectsRequest .builder() .bucket(bucketName) .build(); ListObjectsResponse res = s3.listObjects(listObjects); List<S3Object> objects = res.contents(); for (S3Object myValue: objects) { keyName = myValue.key(); keys.add(keyName); } return keys; } catch (S3Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } return null; } // Tag assets with labels in the given list. public void tagAssets(List myList, String bucketName) { try { S3Client s3 = getClient(); int len = myList.size(); String assetName = ""; String labelName = ""; String labelValue = ""; // Tag all the assets in the list. for (Object o : myList) { // Need to get the WorkItem from each list. List innerList = (List) o; for (Object value : innerList) { WorkItem workItem = (WorkItem) value; assetName = workItem.getKey(); labelName = workItem.getName(); labelValue = workItem.getConfidence(); tagExistingObject(s3, bucketName, assetName, labelName, labelValue); } } } catch (S3Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } // This method tags an existing object. private void tagExistingObject(S3Client s3, String bucketName, String key, String label, String LabelValue) { try { // First need to get existing tag set; otherwise the existing tags are overwritten. GetObjectTaggingRequest getObjectTaggingRequest = GetObjectTaggingRequest.builder() .bucket(bucketName) .key(key) .build(); GetObjectTaggingResponse response = s3.getObjectTagging(getObjectTaggingRequest); // Get the existing immutable list - cannot modify this list. List<Tag> existingList = response.tagSet(); ArrayList<Tag> newTagList = new ArrayList(new ArrayList<>(existingList)); // Create a new tag. Tag myTag = Tag.builder() .key(label) .value(LabelValue) .build(); // push new tag to list. newTagList.add(myTag); Tagging tagging = Tagging.builder() .tagSet(newTagList) .build(); PutObjectTaggingRequest taggingRequest = PutObjectTaggingRequest.builder() .key(key) .bucket(bucketName) .tagging(tagging) .build(); s3.putObjectTagging(taggingRequest); System.out.println(key + " was tagged with " + label); } catch (S3Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } // Delete tags from the given object. public void deleteTagFromObject(String bucketName, String key) { try { DeleteObjectTaggingRequest deleteObjectTaggingRequest = DeleteObjectTaggingRequest.builder() .key(key) .bucket(bucketName) .build(); S3Client s3 = getClient(); s3.deleteObjectTagging(deleteObjectTaggingRequest); } catch (S3Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } }

AnalyzePhotos 班级

以下 Java 代码代表该AnalyzePhotos类。该类使用 Amazon Rekognition API 来分析图像。

package com.example.tags; import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rekognition.RekognitionClient; import software.amazon.awssdk.services.rekognition.model.Image; import software.amazon.awssdk.services.rekognition.model.DetectLabelsRequest; import software.amazon.awssdk.services.rekognition.model.DetectLabelsResponse; import software.amazon.awssdk.services.rekognition.model.Label; import software.amazon.awssdk.services.rekognition.model.RekognitionException; import java.util.ArrayList; import java.util.List; public class AnalyzePhotos { // Returns a list of WorkItem objects that contains labels. public ArrayList<WorkItem> detectLabels(byte[] bytes, String key) { Region region = Region.US_EAST_2; RekognitionClient rekClient = RekognitionClient.builder() .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) .region(region) .build(); try { SdkBytes sourceBytes = SdkBytes.fromByteArray(bytes); // Create an Image object for the source image. Image souImage = Image.builder() .bytes(sourceBytes) .build(); DetectLabelsRequest detectLabelsRequest = DetectLabelsRequest.builder() .image(souImage) .maxLabels(10) .build(); DetectLabelsResponse labelsResponse = rekClient.detectLabels(detectLabelsRequest); // Write the results to a WorkItem instance. List<Label> labels = labelsResponse.labels(); ArrayList<WorkItem> list = new ArrayList<>(); WorkItem item ; for (Label label: labels) { item = new WorkItem(); item.setKey(key); // identifies the photo. item.setConfidence(label.confidence().toString()); item.setName(label.name()); list.add(item); } return list; } catch (RekognitionException e) { System.out.println(e.getMessage()); System.exit(1); } return null ; } }

BucketItem 班级

以下 Java 代码表示存储 Amazon S3 对象数据的BucketItem类。

package com.example.tags; public class BucketItem { private String key; private String owner; private String date ; private String size ; public void setSize(String size) { this.size = size ; } public String getSize() { return this.size ; } public void setDate(String date) { this.date = date ; } public String getDate() { return this.date ; } public void setOwner(String owner) { this.owner = owner ; } public String getOwner() { return this.owner ; } public void setKey(String key) { this.key = key ; } public String getKey() { return this.key ; } }

WorkItem 班级

以下 Java 代码代表该WorkItem类。

package com.example.tags; public class WorkItem { private String key; private String name; private String confidence ; public void setKey (String key) { this.key = key; } public String getKey() { return this.key; } public void setName (String name) { this.name = name; } public String getName() { return this.name; } public void setConfidence (String confidence) { this.confidence = confidence; } public String getConfidence() { return this.confidence; } }

打包项目

使用以下 Maven 命令将项目打包成 .jar (JAR) 文件。

mvn package

JAR 文件位于目标文件夹(这是项目文件夹的子文件夹)。

文件资源管理器窗口显示目标文件夹,其中包含 WorkflowTagAssets -1.0-Snapshot.jar 等 JAR 文件以及其他项目文件和文件夹。
注意

请注意项目的 POM 文件maven-shade-plugin中使用了。此插件负责创建包含所需依赖项的 JAR。如果您尝试在没有此插件的情况下打包项目,则所需的依赖项不包含在 JAR 文件中,您将遇到. ClassNotFoundException

部署 Lambda 函数

  1. 打开 Lambda 控制台

  2. 选择创建函数

  3. 选择从头开始创作

  4. 基本信息部分,输入 cron 作为名称。

  5. 运行时系统中,选择 Java 8

  6. 选择使用现有角色,然后选择 lambda 支持(您创建的 IAM 角色)。

  7. 选择创建函数

  8. 对于代码输入种类,选择上传 .zip 文件或 .jar 文件

  9. 选择上传,然后浏览到您创建的 JAR 文件。

  10. 对于处理程序,输入函数的完全限定名称,例如 com.example.tags.Handler:handleRequestcom.example.tags 指定程序包,处理程序是后跟 :: 和方法名称的类)。

  11. 选择保存

测试 Lambda 方法

在教程的这一部分,您可以测试 Lambda 函数。

  1. 在 Lambda 控制台中,单击测试选项卡,然后输入以下 JSON。

    { "flag": "true" }
    使用标志键值对、“删除”和“格式化”按钮以及“调用”按钮测试事件 JSON 编辑器。
    注意

    传递 true 会标记数字资产,传递 false 会删除标签。

  2. 选择调用按钮。调用 Lambda 函数后,您会看到一条成功消息。

    执行结果消息带有“详细信息”按钮,表示操作成功。

恭喜,您创建了一个自动将标签应用于 Amazon S3 存储桶中的数字资产的 AWS Lambda 函数。如本教程开头所述,请务必在学习本教程时终止您创建的所有资源,以确保系统不会向您收费。

有关更多 AWS 多服务示例,请参阅AWS 文档 SDK 示例 GitHub 存储库