aws 亚马逊_Amazon AWS Rekognition教程

本文是关于Amazon AWS Rekognition的教程,它是一个提供图像和视频分析服务的AWS。服务能检测物体、人物、场景,识别面部,并能与已知面部匹配。文章详细介绍了如何使用Rekognition进行图像和视频操作,包括检测标签、人脸、创建和管理集合,以及视频操作。此外,还涵盖了项目设置、视频分析和如何在Java中实现基本功能。
TensorFlow-v2.15

TensorFlow-v2.15

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

aws 亚马逊

1.简介

Amazon Rekognition是提供图像和视频分析服务的Amazon Web Service(AWS)。 您可以提供图像或视频,该服务将检测物体,人物和场景。 检测到的面部也可以与一组已知面部进行匹配。 这允许实现用例,例如用户验证,人数统计或公共安全。

该服务基于亚马逊的深度学习技术,该技术也在其他服务中使用。 要使用该服务,不需要有关基础技术的知识,就可以简单地调用现有的API并处理调用的结果。

有两种不同的API集:一种用于分析图像,另一种用于视频分析。 两者都可以执行您的应用程序可以使用的对象检测和识别。 例如,您可以开发一个应用程序,使用户可以通过脸部或某些对象搜索他们的照片集。 因此,您将让您的应用程序将图像或视频数据发送到Amazon Rekognition,并使其返回有关上传资料的元数据。 您的应用程序使用此元数据管理数据库,并允许用户在其中进行搜索。

通过视频API,您可以跟踪存储的视频中或来自实时摄像机的视频流中的人。 通过这种方式,可以通知您是否在存储的视频中或在实时摄像机的前面检测到已知人物。

2.基础知识

在开始之前,我们必须学习一些有关图像检测和识别的概念。

label可以引用图像或视频中的不同项目:

  • 对象:花,树,桌子等
  • 事件:婚礼,生日聚会等
  • 概念:景观,傍晚,自然等
  • 活动:下车等。

Amazon Rekognition具有专门的操作,可将所有检测到的标签返回到图像或视频上。

Rekognition服务还将返回其在图像或视频中检测到的面部以及地标信息(例如眼位和检测到的情绪)。 您可以将人员注册到集合中,并让Amazon在提交的图像上搜索这些人员。 后一个功能称为“面部搜索”。

在视频上,可以通过不同的帧跟踪一个人。 该服务提供有关检测的面部和框内位置的信息。

作为一项特殊功能,Amazon Rekognition还可以识别图像和视频中的数千名名人。 跟踪信息告诉您某个演员出现在电影的哪个部分。

一个有趣的选项是检测图像中的文本并将其转换为机器可读的文本。 这样,您就可以检测图像中的车牌号或开发可帮助残障人士识别餐厅中路牌或菜单卡的应用程序。

最后但并非最不重要的一点是,Amazon Rekognition Service还可以帮助检测图像和视频上的不安全内容,例如裸露,泳装或内衣。

图像分析的API是同步的,并且将JSON文档作为输入并返回JSON响应。 图像可以是Amazon S3存储桶中提供的jpeg或png文件,也可以是byte64编码的图像。

随着视频分析花费更多时间,视频API是异步的。 这意味着您通过通过Amazon S3存储桶提供视频来开始处理,后端通过向SNS主题发送消息来通知您有关结果。 Amazon SNS是一种消息服务,用于使用发布/订阅范式进行通知。

如果您想分析流视频内容,则视频是通过Amazon Kinesis提供的,后端通过必须实现的流处理器通知您有关识别的信息。

要搜索面部,您必须创建一个包含要检测的面部的集合。 由于这些面Kong存储在Amazon Rekognition服务中,因此对这些集合的操作也称为“存储操作”。 与这些“存储操作”相反,可以在不将任何信息存储在Amazon服务器上的情况下调用“非存储操作”。 这些“非存储操作”包括检测标签和面Kong,识别名人或检测文本的操作。

“存储操作”将有关检测到的面部的信息存储在Amazon Rekognition服务中。 此信息也称为模板。 由深度学习算法的特定版本计算出的模板可能与新版本不兼容。 因此,必须使用新版本的算法使用相同的图像数据再次计算模板。 正如亚马逊所说,“模型版本”与带有面Kong的集合有关。 由于无法将现有集合升级到新的“模型版本”,因此必须创建一个新集合(对于新的“模型版本”)并再次添加所有图像。 否则,随着时间的推移,您可能会遇到兼容性问题。

3.项目设置

在本教程中,我们将使用Java作为编程语言,并使用maven作为构建工具。 我们将创建一个小示例应用程序,以演示Amazon Rekognition的基本功能。

它要求您已安装Java> = 1.8和Maven> = 3.0。

第一步,我们将在命令行上创建一个简单的maven项目:

mvn archetype:generate -DgroupId=com.javacodegeeks.aws -DartifactId=rekognition -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

此命令将在文件系统中创建以下结构:

|-- src
|   |-- main
|   |   `-- java
|   |       `-- com
|   |           `-- javacodegeeks
|   |                `-- aws
|   `-- test
|   |   `-- java
|   |       `-- com
|   |           `-- javacodegeeks
|   |                `-- aws
`-- pom.xml

pom.xml定义了我们将用作依赖项的库:

<properties>
    <aws.version>1.11.401</aws.version>
</properties>

<dependencies>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-rekognition</artifactId>
        <version>${aws.version}</version>
    </dependency>
    <dependency>
        <groupId>com.amazonaws</groupId>
        <artifactId>aws-java-sdk-core</artifactId>
        <version>${aws.version}</version>
    </dependency>
</dependencies>

工件aws-java-sdk-rekognition包含用于Amazon Rekognition Web服务的即用型Java API,而工件aws-java-sdk-core包含一组较大的Amazon AWS开发工具包使用的代码。 由于aws-java-sdk-coreaws-java-sdk-rekognition的可传递依赖aws-java-sdk-rekognition ; 因此,您也可以忽略它,因为maven会自动获取它。

我们的Maven工件的结果应该是一个包含所有依赖项的jar文件,以便我们可以在命令行上轻松执行它。 因此,我们将maven-assembly-plugin添加到我们的构建中,并告诉它哪个类包含我们要执行的main()方法:

<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.javacodegeeks.aws.App</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

由于com.javacodegeeks.aws.App类是之前由maven原型插件创建的,因此我们现在可以构建模块:

mvn clean package

成功构建之后,我们可以通过以下方式启动应用程序:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar

现在,我们拥有一个运行中的构建,我们必须创建一个Amazon AWS账户。 因此,打开https://aws.amazon.com/ ,选择“创建一个AWS账户”并按照说明进行操作。 在此注册过程中,您将收到一个电话,并使用电话的键盘输入PIN。

一旦可以访问您的AWS账户,就应该创建一个有权访问Amazon Rekognition API的用户。 例如, 此说明如何执行此操作。

在这两个步骤的最后,您应该拥有一个带ID和密钥的AWS访问密钥。 这些凭证可以存储在本地系统上的AWS凭证配置文件中:

  • 在Linux,macOS或Unix上:〜/ .aws / credentials
  • 在Windows上:C:\ Users \ USERNAME \ .aws \ credentials(其中USERNAME是您的用户名)

该文件包含以下几行:

aws_access_key_id = 
aws_secret_access_key =

用您的帐户的实际值替换右侧的占位符。

此外,您还可以在AWS配置文件中设置要使用的默认AWS区域:

  • 在Linux,macOS或Unix上:〜/ .aws / config
  • 在Windows上:C:\ Users \ USERNAME \ .aws \ config(其中USERNAME是您的用户名)

配置文件具有以下内容:

region =

在右侧的占位符替换为您的AWS区域(例如us-east-1或eu-west-1)。

4.图像操作

在本章中,我们将仔细研究可用的图像操作。

4.1检测标签

首先,我们让Amazon Rekognition在提供的图像上检测标签。

因此,我们通过一些简单的代码通过main()方法扩展了App类,这些代码通过命令行参数调用我们的新类DetectLabels

public class App {

    public static void main(String[] args) {
    if (args.length == 0) {
        System.err.println("Please provide at least one argument.");
        return;
    }
    switch (args[0]) {
    case "detect-labels":
        DetectLabels detectLabels = new DetectLabels();
        detectLabels.run(args);
        break;
    default:
        System.err.println("Unknown argument: " + args[0]);
        return;
    }
    }
}

在下一步中,我们创建一个简单的工厂类来实例化AmazonRekognition对象。 此实例提供对Amazon Rekognition的所有API方法的访问:

public class ClientFactory {

    public static AmazonRekognition createClient() {
    ClientConfiguration clientConfig = new ClientConfiguration();
    clientConfig.setConnectionTimeout(30000);
    clientConfig.setRequestTimeout(60000);
    clientConfig.setProtocol(Protocol.HTTPS);

    AWSCredentialsProvider credentialsProvider = new ProfileCredentialsProvider();

    return AmazonRekognitionClientBuilder
        .standard()
        .withClientConfiguration(clientConfig)
        .withCredentials(credentialsProvider)
        .withRegion("eu-west-1")
        .build();
    }
}

Amazon AWS开发工具包使用构建器模式来创建合适的配置。 方法standard()将所有选项初始化为默认值。 之后,我们提供特定的客户端配置。 这应该演示如何调整例如连接超时和请求超时。 除此之外,我们还将HTTPS设置为传输协议。 可以为客户端设置许多其他选项。

正如我们之前创建的credentials文件一样,我们可以使用ProfileCredentialsProvider将AWS凭证传递给应用程序。 这将使代码检查credentials文件并从那里获取凭据。

由于我们已将此信息存储在config文件中,因此可以省略代码中提供的区域。 在这里,它仅显示我们使用构建器API可以完全控制所有选项。

在实现代码以创建Amazon Rekognition客户端之后,我们可以进一步了解如何检测提供的图像上的标签:

public class DetectLabels {

    public void run(String[] args) {

        if (args.length < 2) {
            System.err.println("Please provide an image.");
            return;
        }

        String imgPath = args[1];
        byte[] bytes;
        try {
            bytes = Files.readAllBytes(Paths.get(imgPath));
        } catch (IOException e) {
            System.err.println("Failed to load image: " + e.getMessage());
            return;
        }
        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);

        AmazonRekognition rekognition = ClientFactory.createClient();

        DetectLabelsRequest request = new DetectLabelsRequest()
            .withImage(new Image().withBytes(byteBuffer))
            .withMaxLabels(10);
        DetectLabelsResult result = rekognition.detectLabels(request);

        List 

我们传递给run()方法的String数组由命令行中的参数填充。 第一个参数用于调用上面的DetectLabels类(请参阅App类)。 因此,我们可以使用第二个参数来提供图像。 然后使用两个参数调用该应用程序:

java -jar target/rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar detect-labels img/work.jpg

当第一行检查命令行参数是否存在时,接下来的几行将图像文件的内容读取到byte数组中,并将其包装到ByteBuffer 。 然后是时候为Amazon Rekognition API创建客户端和DetectLabelsRequest实例了。 该请求对象由字节缓冲区和不返回超过10个标签的指令填充。 最后,此请求将传递到客户端的detectLabels()方法,并且返回的标签将打印在控制台上。

我们正在使用以下示例图像:

Amazon AWS Rekognition

输出将查找示例图像,如下所示:

Human: 99.18134
People: 99.18133
Person: 99.18134
Computer: 74.21879
Electronics: 74.21879
Laptop: 74.21879
Pc: 74.21879
Art: 71.1518
Modern Art: 71.1518
Afro Hairstyle: 70.530525

我们可以看到,Amazon Rekognition确保图像上有人类,有电脑/笔记本电脑和现代艺术品。 它甚至检测到图像左上方的“非洲发型”。

如果愿意,您现在可以扩展应用程序并将这些标签存储在数据库中,并让用户搜索它们。 对于更大的图像集合,您将有一种简单的方法,不仅可以通过图像中的文件名和元数据,还可以通过其内容来索引图像。

4.2检测人脸

Amazon Rekognition不仅可以检测标签,而且可以检测人脸。 在本节中,我们将更详细地探讨此功能。

首先,通过在命令行上接受另一个参数来扩展主类App

case "detect-faces":
    DetectFaces detectFaces = new DetectFaces();
    detectFaces.run(args);
    break;

新类DetectFaces的方法run(String[])如下所示:

public void run(String[] args) {

    if (args.length < 2) {
        System.err.println("Please provide an image.");
        return;
    }

    String imgPath = args[1];
    byte[] bytes;
    try {
        bytes = Files.readAllBytes(Paths.get(imgPath));
    } catch (IOException e) {
        System.err.println("Failed to load image: " + e.getMessage());
        return;
    }
    ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);

    AmazonRekognition rekognition = ClientFactory.createClient();

    DetectFacesRequest request = new DetectFacesRequest()
            .withImage(new Image().withBytes(byteBuffer))
            .withAttributes(Attribute.ALL);
    DetectFacesResult result = rekognition.detectFaces(request);

    String orientationCorrection = result.getOrientationCorrection();
    System.out.println("Orientation correction: " + orientationCorrection);

    List faceDetails = result.getFaceDetails();
    for (FaceDetail faceDetail : faceDetails) {

        printFaceDetails(faceDetail);
    }
}

它从第二个命令行参数中提取图像的文件名,并将所有字节读入数组。 这样,可以通过以下方式调用应用程序:

java -jar target/rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar detect-faces img/work.jpg

方法printFaceDetails()输出有关面部检测的所有可用信息:

private void printFaceDetails(FaceDetail faceDetail) {
    System.out.println("###############");

    AgeRange ageRange = faceDetail.getAgeRange();
    System.out.println("Age range: " + ageRange.getLow() + "-" + ageRange.getHigh());

    Beard beard = faceDetail.getBeard();
    System.out.println("Beard: " + beard.getValue() + "; confidence=" + beard.getConfidence());

    BoundingBox bb = faceDetail.getBoundingBox();
    System.out.println("BoundingBox: left=" + bb.getLeft() +
            ", top=" + bb.getTop() + ", width=" + bb.getWidth() +
            ", height=" + bb.getHeight());

    Float confidence = faceDetail.getConfidence();
    System.out.println("Confidence: " + confidence);

    List emotions = faceDetail.getEmotions();
    for (Emotion emotion : emotions) {
        System.out.println("Emotion: " + emotion.getType() +
                "; confidence=" + emotion.getConfidence());
    }

    Eyeglasses eyeglasses = faceDetail.getEyeglasses();
    System.out.println("Eyeglasses: " + eyeglasses.getValue() +
            "; confidence=" + eyeglasses.getConfidence());

    EyeOpen eyesOpen = faceDetail.getEyesOpen();
    System.out.println("EyeOpen: " + eyesOpen.getValue() +
            "; confidence=" + eyesOpen.getConfidence());

    Gender gender = faceDetail.getGender();
    System.out.println("Gender: " + gender.getValue() +
            "; confidence=" + gender.getConfidence());

    List landmarks = faceDetail.getLandmarks();
    for (Landmark lm : landmarks) {
        System.out.println("Landmark: " + lm.getType()
            + ", x=" + lm.getX() + "; y=" + lm.getY());
    }

    MouthOpen mouthOpen = faceDetail.getMouthOpen();
    System.out.println("MouthOpen: " + mouthOpen.getValue() +
            "; confidence=" + mouthOpen.getConfidence());

    Mustache mustache = faceDetail.getMustache();
    System.out.println("Mustache: " + mustache.getValue() +
            "; confidence=" + mustache.getConfidence());

    Pose pose = faceDetail.getPose();
    System.out.println("Pose: pitch=" + pose.getPitch() +
            "; roll=" + pose.getRoll() + "; yaw" + pose.getYaw());

    ImageQuality quality = faceDetail.getQuality();
    System.out.println("Quality: brightness=" +
            quality.getBrightness() + "; sharpness=" + quality.getSharpness());

    Smile smile = faceDetail.getSmile();
    System.out.println("Smile: " + smile.getValue() +
            "; confidence=" + smile.getConfidence());

    Sunglasses sunglasses = faceDetail.getSunglasses();
    System.out.println("Sunglasses=" + sunglasses.getValue() +
            "; confidence=" + sunglasses.getConfidence());

    System.out.println("###############");
}

该信息包括:

  • 边界框::包围脸部的框。
  • 置信度::盒子包含一张脸的置信度。
  • 面部界标::界标列表,每个界标(例如左眼,右眼和嘴巴)均描述x和y坐标。
  • 面部属性::描述面部的其他属性(例如性别,胡须等)。 对于大多数属性,置信度值指示Amazon Rekognition对该属性的确信程度。
  • 质量::脸部的亮度和清晰度。
  • 姿势::姿势描述图像内部人脸的旋转。
  • 情绪::一组检测到的情绪。

上面的示例代码使用withAttributes()方法告诉Amazon Rekognition返回所有可用的面部属性。 如果省略此参数,则该服务将仅返回BoundingBox,
信心,姿势,品质和地标。

还请注意方向校正的输出。 如果此值不为null ,则指示是否需要旋转图像。 在这种情况下,您不仅需要旋转图像本身,而且还必须旋转返回的边界框和地标。 如果该值为null ,则必须从其Exif元数据中提取图片的方向。 Amazon Rekognition在内部评估此值,但不会通过API返回它。

将示例代码与上面最后一部分中的示例图像一起运行将产生以下结果(缩短):

Orientation correction: ROTATE_0
###############
Age range: 35-52
Beard: false; confidence=63.299633
BoundingBox: left=0.67542213, top=0.503125, width=0.16322702, height=0.10875
Confidence: 99.99996
Emotion: HAPPY; confidence=33.592426
Emotion: CONFUSED; confidence=3.7694752
Emotion: ANGRY; confidence=3.3934474
Eyeglasses: false; confidence=99.92778
EyeOpen: true; confidence=99.999115
Gender: Male; confidence=99.92852
Landmark: eyeLeft, x=0.72928935; y=0.54335195
Landmark: eyeRight, x=0.77855927; y=0.5483551
Landmark: nose, x=0.7247987; y=0.56508356
Landmark: mouthLeft, x=0.72980136; y=0.58450377
Landmark: mouthRight, x=0.7671486; y=0.58911216
Landmark: leftPupil, x=0.73123896; y=0.54353833
Landmark: rightPupil, x=0.78261787; y=0.54776514
Landmark: leftEyeBrowLeft, x=0.71933734; y=0.53303427
Landmark: leftEyeBrowUp, x=0.7256926; y=0.5320847
Landmark: leftEyeBrowRight, x=0.7333774; y=0.5329594
Landmark: rightEyeBrowLeft, x=0.76563233; y=0.53686714
Landmark: rightEyeBrowUp, x=0.78357726; y=0.5374825
Landmark: rightEyeBrowRight, x=0.7988768; y=0.5429575
Landmark: leftEyeLeft, x=0.7218825; y=0.54265666
Landmark: leftEyeRight, x=0.7381058; y=0.54474115
Landmark: leftEyeUp, x=0.7287737; y=0.5410849
Landmark: leftEyeDown, x=0.7291001; y=0.54527205
Landmark: rightEyeLeft, x=0.77009064; y=0.5488282
Landmark: rightEyeRight, x=0.7880702; y=0.54891306
Landmark: rightEyeUp, x=0.778157; y=0.5459737
Landmark: rightEyeDown, x=0.7784402; y=0.55022097
Landmark: noseLeft, x=0.73085135; y=0.5707799
Landmark: noseRight, x=0.74700916; y=0.57319427
Landmark: mouthUp, x=0.7397919; y=0.58404857
Landmark: mouthDown, x=0.74021983; y=0.5951085
MouthOpen: false; confidence=91.05297
Mustache: false; confidence=95.113785
Pose: pitch=1.6241417; roll=11.053664; yaw-40.602734
Quality: brightness=49.62646; sharpness=99.93052
Smile: true; confidence=87.8063
Sunglasses=false; confidence=99.95385
###############
###############
Age range: 26-43
Beard: true; confidence=98.0061
BoundingBox: left=0.12851782, top=0.47375, width=0.23170732, height=0.154375
Confidence: 99.99996
[...]

我们可以看到,Amazon Rekognition服务检测到两张脸,一张留着胡须,一张没有胡须。 在这两种情况下,服务都非常确定它已检测到边界框内的人脸。 第一个检测是图像中心的人。 亚马逊的算法认为这个人很高兴,但是对此并不确定。 它检测到该人的眼睛张开,该人没有眼镜,并且是年龄在35-52岁之间的男性。 人的嘴没有张开,也没有胡须或墨镜。 但是,此人笑容约为87.8%。

在具有更多细节和人物的图像上,有时不清楚哪个检测属于哪张脸。 因此,在图像上绘制边框是有意义的。

如前所述,我们必须考虑图像的方向,并在必要时旋转边界框。 相应的代码如下所示:

private BoundingBox convertBoundingBox(BoundingBox bb, String orientationCorrection, int width, int height) {
    if (orientationCorrection == null) {
        System.out.println("No orientationCorrection available.");
        return null;
    } else {
        float left = -1;
        float top = -1;
        switch (orientationCorrection) {
        case "ROTATE_0":
            left = width * bb.getLeft();
            top = height * bb.getTop();
            break;
        case "ROTATE_90":
            left = height * (1 - (bb.getTop() + bb.getHeight()));
            top = width * bb.getLeft();
            break;
        case "ROTATE_180":
            left = width - (width * (bb.getLeft() + bb.getWidth()));
            top = height * (1 - (bb.getTop() + bb.getHeight()));
            break;
        case "ROTATE_270":
            left = height * bb.getTop();
            top = width * (1 - bb.getLeft() - bb.getWidth());
            break;
        default:
            System.out.println("Orientation correction not supported: " +
                    orientationCorrection);
            return null;
        }
        System.out.println("BoundingBox: left=" + (int)left + ", top=" +
                (int)top + ", width=" + (int)(bb.getWidth()*width) +
                ", height=" + (int)(bb.getHeight()*height));
        BoundingBox outBB = new BoundingBox();
        outBB.setHeight(bb.getHeight()*height);
        outBB.setWidth(bb.getWidth()*width);
        outBB.setLeft(left);
        outBB.setTop(top);
        return outBB;
    }
}

根据图像的方向,根据可用信息计算左坐标和上坐标。 此方法的返回值是一个新的BoundingBox ,它已经包含像素值,而不是相对于图像的宽度和高度给出的相对浮点数。

转换后的BoundingBox允许我们使用Java SDK类ImageIO加载图像,并为每个边界框绘制一个红色矩形:

private void drawBoundingBoxes(byte[] bytes, DetectFacesResult result) {
    int width;
    int height;
    BufferedImage img;
    Graphics2D graphics;
    try {
        img = ImageIO.read(new ByteArrayInputStream(bytes));
        width = img.getWidth();
        height = img.getHeight();
        graphics = img.createGraphics();
    } catch (IOException e) {
        System.err.println("Failed to read image: " + e.getLocalizedMessage());
        return;
    }
    System.out.println("Image: width=" + width + ", height=" + height);

    String orientationCorrection = result.getOrientationCorrection();
    System.out.println("Orientation correction: " + orientationCorrection);

    List faceDetails = result.getFaceDetails();
    for (FaceDetail faceDetail : faceDetails) {
        drawBoundingBox(faceDetail, orientationCorrection, width, height, graphics);
    }

    try {
        ImageIO.write(img, "jpg", new File("img_bb.jpg"));
    } catch (IOException e) {
        System.err.println("Failed to write image: " + e.getLocalizedMessage());
    }
}

private void drawBoundingBox(FaceDetail faceDetail, String orientationCorrection, int width, int height,
        Graphics2D graphics) {

    BoundingBox bb = faceDetail.getBoundingBox();
    BoundingBox cbb = convertBoundingBox(bb, orientationCorrection, width, height);
    if (cbb == null) {
        return;
    }

    graphics.setColor(Color.RED);
    graphics.setStroke(new BasicStroke(10));
    graphics.drawRect(cbb.getLeft().intValue(), cbb.getTop().intValue(),
            cbb.getWidth().intValue(), cbb.getHeight().intValue());
}

ImageIO.read()方法将图像加载到BufferedImage ,可以使用相应的ImageIO.write()方法进行存储。 在这两者之间,我们创建了Graphics2D实例,该实例允许我们在缓冲的图像上绘制矩形。 该示例代码为每个转换后的边界框绘制一个厚度为10像素的红色矩形:

Amazon AWS Rekognition

显然,我们可以看到两个边界框,并验证每个边界框都包含一个面。

4.3比较面Kong

API方法“比较面Kong”允许我们检测第二张图片(称为目标图片)中第一张图片(称为源图片)给出的面Kong。 如果源图像不是仅包含一个图像的经典肖像,则Amazon Rekognition将使用最大的脸Kong。 该服务将在目标图像中返回此脸部的所有匹配项,以及指示该服务如何确定目标图像中的人是源图像中的人的相似度值。

为了扩展我们的应用程序,我们将以下代码添加到App类的switch语句中:

case "compare-faces":
    CompareFaces compareFaces = new CompareFaces();
    compareFaces.run(args);
    break;

新的类CompareFaces如下所示:

public class CompareFaces {

    public void run(String[] args) {
        if (args.length < 3) {
            System.err.println("Please provide two images:  .");
            return;
        }

        ByteBuffer image1 = loadImage(args[1]);
        ByteBuffer image2 = loadImage(args[2]);
        if (image1 == null || image2 == null) {
            return;
        }

        CompareFacesRequest request = new CompareFacesRequest()
                .withSourceImage(new Image().withBytes(image1))
                .withTargetImage(new Image().withBytes(image2))
                .withSimilarityThreshold(70F);

        CompareFacesResult result = ClientFactory.createClient().compareFaces(request);

        List boundingBoxes = new ArrayList<>();
        List faceMatches = result.getFaceMatches();
        for (CompareFacesMatch match : faceMatches) {
            Float similarity = match.getSimilarity();
            System.out.println("Similarity: " + similarity);
            ComparedFace face = match.getFace();
            BoundingBox bb = face.getBoundingBox();
            boundingBoxes.add(bb);
        }

        BoundingBoxDrawer bbDrawer = new BoundingBoxDrawer();
        bbDrawer.drawBoundingBoxes(image2.array(), result.getTargetImageOrientationCorrection(), boundingBoxes);
    }

    private ByteBuffer loadImage(String imgPath) {
        byte[] bytes;
        try {
            bytes = Files.readAllBytes(Paths.get(imgPath));
        } catch (IOException e) {
            System.err.println("Failed to load image: " + e.getMessage());
            return null;
        }
        return ByteBuffer.wrap(bytes);
    }

}

我们希望用户提供两个图像:源图像和目标图像。 这两个图像均作为命令行参数提供,并使用loadImage()方法加载到ByteBuffer 。 在下一步中,代码创建一个CompareFacesRequest实例,并设置源图像和目标图像以及我们要使用的相似性阈值。 使用客户端的方法compareFaces()将该请求发送到Amazon Rekognition服务。

调用的结果是CompareFacesResult一个实例,该实例使用其方法getFaceMatches()传递潜在的匹配项。 对于每个匹配项,我们输出相似性并将边界框添加到列表中。 此列表稍后提供给BoundingBoxDrawer实例,该实例基本上包含上一个示例中的重构代码,并在目标图像上绘制边界框并将其保存在当前工作目录中。

现在,我们可以使用两个图像编译并启动程序:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar compare-faces img\dinner2.jpg img\dinner3.jpg

第一张图片是女人的画像:

Amazon AWS Rekognition

第二张图片显示了女人和男人:

Amazon AWS Rekognition

我们的示例应用程序输出以下信息:

Similarity: 96.0
Image: width=5760, height=3840
BoundingBox: left=2341, top=936, width=1076, height=1073

Amazon的算法非常确定(96.0%),目标图像上的女人与源图像上的女人是同一个人。 目标图像上的边界框告诉我们算法将女人定位在哪里:

Amazon AWS Rekognition

5.馆藏

集合是Amazon Rekognition中管理面Kong的基本单位。 您可以创建一个或多个集合并将其存储在其中。 之后,您可以搜索特定集合以进行面部匹配。 这与“比较面部”操作不同,后者仅允许在目标图像的源图像中搜索面部。

您在特定的Amazon区域内创建一个集合,并且该集合与当前的面部检测模型相关联。

例如,当您想监视商店中的客户时,集合有用的用例。 为了将员工与客户分开,您可以创建一个名为“ staff”的集合,并为公司所有员工注册面部图像。 现在,您只需要查询集合,就可以知道检测到的人脸是属于工作人员还是顾客。 您也可以与不允许进入建筑物的人员一起创建第二个收藏集。 如果您的应用程序从此集合中检测到人脸,则警报可能会通知工作人员。

5.1创建收藏

使用集合的第一步当然是创建集合。 以下代码段扩展了App类中的switch语句:

case "create-collection":
    CreateCollection cc = new CreateCollection();
    cc.run(args);
    break;

新的类CreateCollection看起来很简单:

public class CreateCollection {

    public void run(String[] args) {
        if (args.length < 2) {
            System.err.println("Please provide a collection name.");
            return;
        }

        String collectionName = args[1];

        CreateCollectionRequest request = new CreateCollectionRequest()
                .withCollectionId(collectionName);

        AmazonRekognition rekognition = ClientFactory.createClient();
        CreateCollectionResult result = rekognition.createCollection(request);

        Integer statusCode = result.getStatusCode();
        String collectionArn = result.getCollectionArn();
        String faceModelVersion = result.getFaceModelVersion();
        System.out.println("statusCode=" + statusCode + "\nARN="
            + collectionArn + "\nface model version=" + faceModelVersion);
    }
}

我们希望将一个集合名称作为参数,并将其传递给CreateCollectionRequestwithCollectionId()方法。 随后,该请求将作为参数传递给AmazonRekognition客户端的方法createCollection()

客户端响应包含状态代码,内部全局唯一的内部Amazon资源名称(ARN)和面部模型版本。

编译完类后,我们可以通过以下方式调用它:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar create-collection my-coll

这将产生以下示例输出:

statusCode=200
ARN=aws:rekognition:eu-west-1:047390200627:collection/my-coll
face model version=3.0

显然,该操作成功完成,并为面部模型版本3.0创建了一个名为my-coll的集合。

5.2列表集合

现在我们已经创建了第一个集合,现在该列出所有可用的集合了。

因此,我们在命令行参数评估器中添加了另一种情况:

case "list-collections":
    ListCollections lc = new ListCollections();
    lc.run(args);
    break;

ListCollections发送ListCollectionsRequest亚马逊Rekognition服务和打印所有返回的id:

public class ListCollections {

    public void run(String[] args) {

        ListCollectionsRequest request = new ListCollectionsRequest()
                .withMaxResults(100);

        AmazonRekognition rekognition = ClientFactory.createClient();
        ListCollectionsResult result = rekognition.listCollections(request);

        List collectionIds = result.getCollectionIds();
        while (collectionIds != null) {
            for (String id : collectionIds) {
                System.out.println(id);
            }

            String token = result.getNextToken();
            if (token != null) {
                result = rekognition.listCollections(request.withNextToken(token));
            } else {
                collectionIds = null;
            }
        }
    }
}

由于结果列表可能很长,因此API提供了分页选项。 如果有进一步的收集可用,它将返回一个令牌。 下一个请求必须提交此令牌,从而获得下一组收集标识符。

该类的编译版本可以通过以下方式执行:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar list-collections

仅创建了一个集合,输出如下所示:

my-coll

5.3删除收藏

最后,我们必须实现从Amazon Rekognition删除集合的功能。

与前面的两个步骤一样,我们扩展了App类:

case "delete-collection":
        DeleteCollection dc = new DeleteCollection();
        dc.run(args);
        break;

新类DeleteCollection只需创建一个DeleteCollectionRequest ,其ID为要删除的集合,然后将其发送到后端:

public class DeleteCollection {

    public void run(String[] args) {
        if (args.length < 2) {
            System.err.println("Please provide a collection name.");
            return;
        }

        String collectionId = args[1];

        DeleteCollectionRequest request = new DeleteCollectionRequest()
                .withCollectionId(collectionId);
        AmazonRekognition rekognition = ClientFactory.createClient();
        DeleteCollectionResult result = rekognition.deleteCollection(request);

        Integer statusCode = result.getStatusCode();
        System.out.println("Status code: " + statusCode);
    }
}

使用现有集合的ID调用它会导致以下输出:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar delete-collection my-coll
Status code: 200

5.4描述集合

在使用集合一段时间后,查询有关它的一些元数据会很有帮助。 因此,Amazon Rekognition API提供了“描述收集”方法。

对于实现,我们扩展App类:

case "describe-collection":
        DescribeCollection descc = new DescribeCollection();
        descc.run(args);
        break;

新的类DescribeCollection看起来像:

public class DescribeCollection {

    public void run(String[] args) {
        if (args.length < 2) {
            System.err.println("Please provide a collection name.");
            return;
        }

        DescribeCollectionRequest request = new DescribeCollectionRequest()
                .withCollectionId(args[1]);

        AmazonRekognition rekognition = ClientFactory.createClient();
        DescribeCollectionResult result = rekognition.describeCollection(request);

        System.out.println("ARN: " + result.getCollectionARN()
            + "\nFace Model Version: " + result.getFaceModelVersion()
            + "\nFace Count: " + result.getFaceCount()
            + "\nCreated: " + result.getCreationTimestamp());
    }
}

DescribeCollectionRequest仅取集合的名称,而结果提供给我们ARN,人脸模型版本,人脸计数和创建时间戳记:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar describe-collection my-coll
ARN: arn:aws:rekognition:eu-west-1:047390200627:collection/my-coll
Face Model Version: 3.0
Face Count: 0
Created: Fri Sep 07 21:28:05 CEST 2018

5.5索引面

现在我们知道如何使用集合,是时候插入一些面Kong了。 相应的API方法称为“索引面”。

为了将人脸插入到集合中,我们需要提供带有人脸的图像,Amazon Rekognition会将所有检测到的人脸插入到集合中。 在大多数情况下,您更喜欢只包含一个人的图像(例如,肖像),否则您可能会无意间将其他人/面部插入到集合中。 如果您不确定图像,当然可以使用“检测面Kong”方法检查Amazon Rekognition将检测到多少张面Kong。

该服务将不会存储您提供的图像。 它在内部创建有关检测到的脸部的数据结构,并将其存储在集合中。 当前无法直接访问此信息。 当您对集合执行搜索时,将间接使用它。 在这种情况下,Amazon Rekognition将尝试将提供的面部与集合中的所有面部进行匹配。 该服务当然会使用内部数据结构来执行此搜索,但是作为API的用户,您将无法与其联系。

如果要将集合中的匹配项与为索引此脸部而提供的图像相关联,则必须提供“外部标识符”。 在像我们这样的简单情况下,这可以是文件名,在更复杂的应用程序中,您可能必须跟踪Amazon Rekognition为检测到的每个脸部返回的脸部ID及其所在的图像。

第一步是扩展我们的主类:

case "index-faces":
    IndexFaces indf = new IndexFaces();
    indf.run(args);
    break;

IndexFaces类需要至少两个其他参数:一个检测到的面部应插入的集合以及至少一个图像:

public class IndexFaces {

    public void run(String[] args) {

        if (args.length < 3) {
            System.err.println("Please provide a collection and images:   ... ");
            return;
        }

        AmazonRekognition rekognition = ClientFactory.createClient();

        String collectionId = args[1];
        for (int i = 2; i < args.length; i++) {

            String imageArg = args[i];
            Path path = Paths.get(imageArg);
            ByteBuffer byteBuffer;
            try {
                byte[] bytes = Files.readAllBytes(path);
                byteBuffer = ByteBuffer.wrap(bytes);
            } catch (IOException e) {
                System.err.println("Failed to read file '" + imageArg + "': " + e.getMessage());
                continue;
            }

            IndexFacesRequest request = new IndexFacesRequest()
                    .withCollectionId(collectionId)
                    .withDetectionAttributes("ALL")
                    .withImage(new Image().withBytes(byteBuffer))
                    .withExternalImageId(path.getFileName().toString());
            IndexFacesResult result = rekognition.indexFaces(request);

            System.out.println("Indexed image '" + imageArg + "':");

            List faceRecords = result.getFaceRecords();
            for (FaceRecord rec : faceRecords) {
                FaceDetail faceDetail = rec.getFaceDetail();
                BoundingBox bb = faceDetail.getBoundingBox();
                System.out.println("Bounding box: left=" + bb.getLeft() +
                        "; top=" + bb.getTop() +
                        "; width=" + bb.getWidth() +
                        "; height=" + bb.getHeight());

                Face face = rec.getFace();
                System.out.println("Face-ID: " + face.getFaceId() +
                        "\nImage ID: " + face.getImageId() +
                        "\nExternal Image ID: " + face.getExternalImageId() +
                        "\nConfidence: " + face.getConfidence());
            }
        }
    }
}

对于每个提供的图像,将构造一个包含图像字节的ByteBuffer 。 该缓冲区传递到IndexFacesRequest的实例。 IndexFacesRequest还使用集合ID和外部图像ID来跟踪提供的图像,因为Amazon不会存储它。 此外,我们还告诉服务应检测到所有属性。 如前所述,默认情况下,仅处理面Kong的基本属性。

响应包含人脸记录列表。 每个记录都包含一个FaceDetailFace实例。 我们已经从“ Detect Faces”调用中了解了FaceDetail类, Face类提供了一个内部人脸ID,一个内部图像ID,我们提供的外部图像ID以及一个置信度值。

运行以上代码以提供先前创建的集合和两个图像结果,结果如下:

>java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar index-faces my-coll img\dinner1.jpg img\dinner2.jpg

Indexed image 'img\dinner1.jpg':
Bounding box: left=0.35050505; top=0.12651515; width=0.18787879; height=0.28181818
Face-ID: 7c1f2f31-7d88-4bb3-98e4-040edfe3c60a
Image ID: e6dd5551-bd19-5377-94f4-db69730e7ba3
External Image ID: dinner1.jpg
Confidence: 99.99777

Indexed image 'img\dinner2.jpg':
Bounding box: left=0.45353535; top=0.09249432; width=0.3050505; height=0.45792267
Face-ID: 0c8f1a0f-e401-4caf-8a5f-ec06d175f486
Image ID: b1dd15e7-4d08-5489-a14b-dd0dc009143a
External Image ID: dinner2.jpg
Confidence: 99.999916

Amazon Rekognition在提供的每张图像上检测到一张脸,并返回了脸ID,图像ID和外部ID(在我们的情况下为文件名)。 在这两种情况下,Amazon Rekognition都非常确定边界框包含一张脸。

现在,已经将这两张面Kong添加到集合my-coll ,我们可以使用“ describe-collection”命令进行验证:

>java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar describe-collection my-coll
ARN: arn:aws:rekognition:eu-west-1:047390200627:collection/my-coll
Face Model Version: 3.0
Face Count: 2
Created: Fri Sep 07 21:28:05 CEST 2018

5.6搜索面Kong

创建具有两个面Kong的集合后,我们现在可以将其与图像中的面Kong进行匹配。 因此,我们使用“按图像搜索脸部”方法,该方法会拍摄图像并在其上使用检测到的脸部来搜索集合。 或者,也可以通过“索引面Kong”调用返回的现有面KongID进行搜索。

我们的新代码从App类调用:

case "search-faces-by-image":
        SearchFacesByImage sfbi = new SearchFacesByImage();
        sfbi.run(args);
        break;

要通过图像搜索人脸,我们必须提供两个参数:集合和图像。

public class SearchFacesByImage {

    public void run(String[] args) {

        if (args.length < 3) {
            System.err.println("Please provide a collection and images:  ");
            return;
        }

        String collectionId = args[1];
        String imageArg = args[2];

        Path path = Paths.get(imageArg);
        ByteBuffer byteBuffer;
        try {
            byte[] bytes = Files.readAllBytes(path);
            byteBuffer = ByteBuffer.wrap(bytes);
        } catch (IOException e) {
            System.err.println("Failed to read file '" + imageArg + "': " + e.getMessage());
            return;
        }

        SearchFacesByImageRequest request = new SearchFacesByImageRequest()
                .withCollectionId(collectionId)
                .withImage(new Image().withBytes(byteBuffer));

        AmazonRekognition rekognition = ClientFactory.createClient();
        SearchFacesByImageResult result = rekognition.searchFacesByImage(request);

        List faceMatches = result.getFaceMatches();
        for (FaceMatch match : faceMatches) {
            Float similarity = match.getSimilarity();
            Face face = match.getFace();
            System.out.println("MATCH:" +
                    "\nSimilarity: " + similarity +
                    "\nFace-ID: " + face.getFaceId() +
                    "\nImage ID: " + face.getImageId() +
                    "\nExternal Image ID: " + face.getExternalImageId() +
                    "\nConfidence: " + face.getConfidence());
        }
    }
}

这两个参数都传递给SearchFacesByImageRequest的实例。 接收到的结果包含面部匹配列表。 每个FaceMatch告诉我们匹配项和集合FaceMatch脸的标识符的相似性:

>java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar search-faces-by-image my-coll img\dinner3.jpg
MATCH:
Similarity: 96.45872
Face-ID: 0c8f1a0f-e401-4caf-8a5f-ec06d175f486
Image ID: b1dd15e7-4d08-5489-a14b-dd0dc009143a
External Image ID: dinner2.jpg
Confidence: 9999.99

如果您将服务返回的“ Face-ID”进行比较,您会发现它与我们索引图像dinner2.jpg时得到的相同。 这符合我们之前提供的返回的“外部图像ID”。

6.视频操作

在本章中,我们将仔细研究可用的视频操作。

您可以使用Amazon Rekognition来检测视频中的以下内容:

  • 标签
  • 面Kong
  • 名流

为了分析视频资料,您必须将其存储在Amazon S3存储桶中。 由于所有操作都是异步的,因此可以通过调用例如StartLabelDetection启动操作。 异步作业完成后,它将向Amazon SNS主题发送通知消息。 可以通过查询Amazon Simple Queue Service(SQS)来检索此状态。 调用相应的get操作会将分析结果传递到您的应用程序。

除了使用Amazon SQS服务以外,还可以实施一个隶属于Amazon SNS主题的Amazon Lambda函数。 该函数将针对该主题上的每条消息被调用,并且可以随后在服务器端处理分析结果。

视频必须使用H.264编解码器进行编码。 支持的文件格式为MPEG-4和MOV。 一个视频文件可以包含一个或多个编解码器。 如果遇到任何困难,请验证特定文件是否包含H.264编码的内容。

视频的最大文件大小为8 GB。 如果文件较大,则必须先将其拆分为较小的块。

前面的部分显示了如何创建集合以及如何搜索图像中存储在集合中的面部。 视频也可以这样做。 这意味着您将创建一个集合和索引面。 然后,可以使用StartFaceSearch操作开始搜索集合中的人脸。

6.1准备

在开始实施第一个视频分析之前,我们必须设置一个IAM服务角色,该角色允许Amazon Rekognition访问Amazon SNS主题。 因此,转到Amazon AWS控制台内的IAM服务页面并创建一个新角色。 选择“ AWS服务”作为类型,选择“识别”作为服务:

Amazon AWS Rekognition

在下一步中,检查新角色是否附加了策略“ AmazonRekognitionServiceRole”:

Amazon AWS Rekognition

该角色允许Amazon Rekognition服务访问以“ AmazonRekognition”为前缀的SNS主题。

最后一步要求您为新角色指定名称:

Amazon AWS Rekognition

请写下该角色的ARN,稍后再用。

您需要确保所使用的用户至少具有以下权限:

  • 亚马逊SQSFullAccess
  • AmazonRekognitionFullAccess
  • AmazonS3ReadOnlyAccess

此外,我们向该IAM用户添加以下“内联策略”:

{
    "Version": "2012-10-17",
    "Statement": [{
        "Sid": "MySid",
        "Effect": "Allow",
        "Action": "iam:PassRole",
        "Resource": "arn:"
    }]
}

请用上面提到的ARN替换ARN。

现在是时候创建一个SNS主题了。 因此,导航到AWS控制台内的SNS服务并创建一个新主题。 请注意,主题名称必须以AmazonRekognition

Amazon AWS Rekognition

再次,请写下该主题的ARN。

有一个SNS主题,我们可以使用AWS内的SQS控制台为其创建标准队列:

Amazon AWS Rekognition

新队列应该存储先前创建的主题的消息。 因此,我们将此队列订阅主题:

Amazon AWS Rekognition

通过查看SQS队列的权限,验证SNS主题可以将消息发送到队列:

Amazon AWS Rekognition

最后,我们可以将视频上传到S3存储桶。 此处举例说明如何使用Amazon S3。 请注意,存储桶与SNS主题,SQS队列以及为您的应用程序配置的存储桶位于同一区域。

6.2检测标签

在完成所有设置操作之后,我们现在准备实施一个可检测视频中标签的应用程序。

因此,我们扩展了App类:

case "detect-labels-video":
        DetectLabelsVideo detectLabelsVideo = new DetectLabelsVideo();
        detectLabelsVideo.run(args);
        break;

此外,我们创建了一个名为DetectLabelsVideo的新类:

public class DetectLabelsVideo {

    private static final String SQS_QUEUE_URL = "https://sqs.eu-west-1.amazonaws.com/...";
    private static final String ROLE_ARN = "arn:aws:iam::...";
    private static final String SNS_TOPIC_ARN = "arn:aws:sns:...";

    public void run(String[] args) throws InterruptedException {

        if (args.length < 3) {
            System.err.println("Please provide a collection and images:  <video width="300" height="150">");
            return;
        }

        String s3Bucket = args[1];
        String video = args[2];

        NotificationChannel channel = new NotificationChannel()
            .withSNSTopicArn(SNS_TOPIC_ARN)
            .withRoleArn(ROLE_ARN);
        AmazonRekognition rekognition = ClientFactory.createClient();
        AmazonSQS sqs = ClientFactory.createSQSClient();

        String jobId = startLabelDetection(s3Bucket, video, channel, rekognition);

        System.out.println("Waiting for message with job-id:" + jobId);
        boolean jobFound = false;
        while (!jobFound) {
            List messages = sqs.receiveMessage(SQS_QUEUE_URL).getMessages();
            System.out.print(".");
            for (Message message : messages) {
                String body = message.getBody();
                try {
                    JsonNode jsonMessageTree = new ObjectMapper().readTree(body);
                    JsonNode msg = jsonMessageTree.get("Message");
                    JsonNode jsonResultTree = new ObjectMapper().readTree(msg.textValue());

                    JsonNode msgJobId = jsonResultTree.get("JobId");
                    JsonNode msgStatus = jsonResultTree.get("Status");

                    System.out.println("\nFound job: " + msgJobId);

                    if (msgJobId.asText().equals(jobId)) {
                        jobFound = true;
                        if (msgStatus.asText().equals("SUCCEEDED")) {
                            getResultsLabels(rekognition, jobId);
                        } else {
                            System.out.println("Video analysis did not succeed: " + msgStatus);
                        }
                        sqs.deleteMessage(SQS_QUEUE_URL, message.getReceiptHandle());
                    } else {
                        System.out.println("Job received was not job " + jobId + " but " + msgJobId);
                        sqs.deleteMessage(SQS_QUEUE_URL, message.getReceiptHandle());
                    }
                } catch (IOException e) {
                    System.err.println("Failed to parse message: " + e.getMessage());
                }
            }
            Thread.sleep(1000);
        }
    }

    private String startLabelDetection(String s3Bucket, String video, NotificationChannel channel,
            AmazonRekognition rekognition) {
        StartLabelDetectionRequest request = new StartLabelDetectionRequest()
                .withVideo(new Video()
                        .withS3Object(new S3Object()
                                .withBucket(s3Bucket)
                                .withName(video)))
                .withMinConfidence(50F)
                .withJobTag("DetectLabels")
                .withNotificationChannel(channel);

        StartLabelDetectionResult result = rekognition.startLabelDetection(request);
        System.out.println("Started label detection.");
        return result.getJobId();
    }

    private void getResultsLabels(AmazonRekognition rekognition, String jobId) {

        String token = null;
        do {

            GetLabelDetectionRequest request = new GetLabelDetectionRequest()
                    .withJobId(jobId)
                    .withMaxResults(10)
                    .withSortBy(LabelDetectionSortBy.TIMESTAMP);
            if (token != null) {
                request.withNextToken(token);
            }
            GetLabelDetectionResult result = rekognition.getLabelDetection(request);

            List labels = result.getLabels();
            for (LabelDetection detection : labels) {
                Label label = detection.getLabel();
                Long timestamp = detection.getTimestamp();
                System.out.println("Label: " + label.getName() +
                        "; confidence=" + label.getConfidence() +
                        "; ts=" + timestamp);
            }

            token = result.getNextToken();
        } while (token != null);
    }
}

第一步,请将常量SQS_QUEUE_URLROLE_ARNSNS_TOPIC_ARN的值SNS_TOPIC_ARN为您的值。 您可以通过在“详细信息”选项卡中的SQS服务页面中的AWS控制台中选择队列来获取SQS队列的URL。

该代码在开始时使用该角色的ARN和SNS主题创建一个NotificationChannel 。 该通道用于提交StartLabelDetectionRequest请求。 此外,此请求还使用存储桶和视频名称,检测的最低置信度以及作业的标签来指定Amazon S3中的视频位置。 结果消息包含在后台异步处理的作业的ID。

因此,我们的代码必须使用AmazonSQS实例轮询SQS队列。 这是由ClientFactory内部的一些新代码创建的:

public static AmazonSQS createSQSClient() {
    ClientConfiguration clientConfig = createClientConfiguration();

    return AmazonSQSClientBuilder
            .standard()
            .withClientConfiguration(clientConfig)
            .withCredentials(new ProfileCredentialsProvider())
            .withRegion("eu-west-1")
            .build();
}

ClientConfiguration与Rekognition客户端相同,因此我们可以将其重构为方法createClientConfiguration()

AmazonSQS提供了方法receiveMessage()来从SQS队列中收集新消息。 队列的URL作为此方法的第一个参数提供。 以下代码遍历所有消息并提取作业ID。 如果它与我们之前获得的相匹配,则将评估作业的状态。 在情况下,它SUCCEEDED ,我们可以查询的结果亚马逊Rekognition服务。

这是通过提交完成GetLabelDetectionRequest与作业ID,最大的结果和排序顺序的Rekognition服务。 由于列表可能很长,因此使用令牌对结果进行分页。 当结果包含“下一个令牌”时,我们必须提交另一个请求以检索剩余的结果。 对于每个检测到的标签,我们输出标签的名称,标签的置信度以及相对于视频开头的时间戳。

用户可以通过提供三个参数来启动应用程序:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar detect-labels-video javacodegeeks-videos people_walking.mp4

第一个参数是在我们的应用程序中启动的操作,第二个参数是S3存储桶,第三个参数是存储桶中视频的名称。 如前所述,请仔细检查存储桶是否位于您正在使用的AWS区域内。 在这里,我选择了与步行者一起观看的视频。 随时选择您拥有的任何H.264编码视频。

视频的示例输出如下所示:

Started label detection.
Waiting for message with job-id:563b31a1f1fa05a9cb917d270c7c500631bc13e159ea18e4e8bfa5d6ad689624
......
Found job: "563b31a1f1fa05a9cb917d270c7c500631bc13e159ea18e4e8bfa5d6ad689624"
Label: Crowd; confidence=58.403896; ts=0
Label: Human; confidence=98.9896; ts=0
Label: People; confidence=97.9793; ts=0
Label: Person; confidence=98.9896; ts=0
Label: Crowd; confidence=53.8455; ts=166
Label: Human; confidence=98.9825; ts=166
Label: People; confidence=97.965004; ts=166
Label: Person; confidence=98.9825; ts=166
Label: Human; confidence=98.9161; ts=375
Label: People; confidence=97.8322; ts=375
Label: Person; confidence=98.9161; ts=375
Label: Crowd; confidence=51.8283; ts=583
Label: Human; confidence=98.9411; ts=583
Label: People; confidence=97.8823; ts=583
Label: Person; confidence=98.9411; ts=583
Label: Human; confidence=98.896996; ts=792
Label: People; confidence=97.794; ts=792
Label: Person; confidence=98.896996; ts=792
Label: Human; confidence=99.0301; ts=959
Label: People; confidence=98.060104; ts=959
Label: Person; confidence=99.0301; ts=959
Label: Human; confidence=99.026695; ts=1167
Label: People; confidence=98.0535; ts=1167
Label: Person; confidence=99.026695; ts=1167
Label: Clothing; confidence=51.8821; ts=1376
[...]

如我们所见,该服务非常确定它已经检测到人群。 输出将被截断,因为其余示例视频将重复相同的输出。

6.3跟踪人员

视频分析的另一个有趣的操作是跟踪视频中的人员。 因此,Amazon Rekognition提供了StartPersonTrackingGetPersonTracking方法。

基本步骤与前面的示例相同。 首先,我们必须扩展App class

case "track-persons":
    TrackPersons trackPersons = new TrackPersons();
    trackPersons.run(args);
    break;

接下来,我们可以重用或重构上一示例中的类。 由于轮询消息队列的循环保持不变,因此我们只需startLabelDetection()以下两个方法替换两个方法startLabelDetection()getResultsLabels

private String startPersonTracking(String s3Bucket, String video, NotificationChannel channel,
        AmazonRekognition rekognition) {
    
    StartPersonTrackingRequest request = new StartPersonTrackingRequest()
            .withVideo(new Video()
                    .withS3Object(new S3Object()
                            .withBucket(s3Bucket)
                            .withName(video)))
            .withJobTag("track-person")
            .withNotificationChannel(channel);
    StartPersonTrackingResult result = rekognition.startPersonTracking(request);
    return result.getJobId();
}

private void getPersonTracking(AmazonRekognition rekognition, String jobId) {
    String token = null;
    do {
        GetPersonTrackingRequest request = new GetPersonTrackingRequest()
                .withJobId(jobId)
                .withMaxResults(10)
                .withSortBy(PersonTrackingSortBy.TIMESTAMP);
        if (token != null) {
            request.setNextToken(token);
        }
        GetPersonTrackingResult result = rekognition.getPersonTracking(request);
        List persons = result.getPersons();
        for (PersonDetection detection : persons) {
            PersonDetail person = detection.getPerson();
            Long index = person.getIndex();
            Long timestamp = detection.getTimestamp();
            System.out.println("Face with id " + index + " detected at " + timestamp + ".");
        }
        token = result.getNextToken();
    } while (token != null);
}

第一种方法创建并提交新的GetPersonTrackingRequest 。 该实例将视频在Amazon S3中的位置,作业标签和通知通道传输到Amazon Rekognition服务。 结果作业ID返回给此方法的调用者。 随后将其用于从SQS队列中获取正确的消息。 找到相应的消息后,将调用方法getPersonTracking() 。 它将带有作业ID,最大结果数和排序顺序的GetPersonTrackingRequest发送到后端。 响应包含带有PersonDetection对象的列表。 Eech PersonDetection提供视频中人物的索引(可用于跟踪后续列表中的人物),视频中检测的时间戳和有关面部检测的细节(在上面的代码中未显示)。

Starting the application on the video before shows the following sample output:

java -jar target\rekognition-1.0-SNAPSHOT-jar-with-dependencies.jar track-persons javacodegeeks-videos people_walking.mp4
Waiting for message with job-id:6ea86fa7c61860f5043077365930ff1aaafb39532cfe046ddca01ed138a075f6
............................................................................
Found job: "6ea86fa7c61860f5043077365930ff1aaafb39532cfe046ddca01ed138a075f6"
Face with id 0 detected at 0.
Face with id 1 detected at 0.
Face with id 2 detected at 0.
Face with id 3 detected at 0.
Face with id 4 detected at 0.
Face with id 5 detected at 0.
Face with id 3 detected at 41.
Face with id 4 detected at 41.
Face with id 5 detected at 41.
Face with id 6 detected at 41.
Face with id 3 detected at 125.
Face with id 4 detected at 125.
Face with id 5 detected at 125.
Face with id 0 detected at 166.
Face with id 3 detected at 166.
Face with id 4 detected at 166.
Face with id 5 detected at 166.
Face with id 6 detected at 166.
Face with id 3 detected at 250.

It is now up to you to extend the examples to a complete application.

7.下载源代码

That was Amazon AWS Rekognition Tutorial.

Download
You can download the full source codes of this example here: Amazon AWS Rekognition Tutorial

翻译自: https://www.javacodegeeks.com/2018/09/amazon-aws-rekognition-tutorial.html

aws 亚马逊

您可能感兴趣的与本文相关的镜像

TensorFlow-v2.15

TensorFlow-v2.15

TensorFlow

TensorFlow 是由Google Brain 团队开发的开源机器学习框架,广泛应用于深度学习研究和生产环境。 它提供了一个灵活的平台,用于构建和训练各种机器学习模型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值