获取图像方向和边界框坐标 - Amazon Rekognition

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

获取图像方向和边界框坐标

使用 Amazon Rekognition Image 的应用程序通常需要显示 Amazon Rekognition Image 操作检测到的图像并在检测到的人脸周围显示框。要在您的应用程序中正确显示图像,您需要知道图像的方向。您可能需要校正此方向。对于某些 .jpg 文件,图像的方向包含在图像的可交换图像文件格式 (Exif) 元数据中。

要在人脸周围显示一个框,您需要人脸边界框的坐标。如果该框的方向不正确,则可能需要调整这些坐标。Amazon Rekognition Image 人脸检测操作会返回每个检测到的人脸的边界框坐标,但它不会估计没有 Exif 元数据的 .jpg 文件的坐标。

以下示例演示如何获取图像中检测到的人脸的边界框坐标

使用此示例中的信息确保您的图像定向准确以及边界框显示在您的应用程序中的正确位置。

由于用于旋转并显示图像和边界框的代码取决于您使用的语言和环境,因此我们不会在代码中解释如何显示图像和边界框,或如何从 Exif 元数据获取方向信息。

查找图像的方向

要在您的应用程序中正确显示图像,您可能需要旋转图像。下图朝向 0 度并正确显示。

代表用户帐户或个人资料图片的通用个人资料图标。

但是,下图将逆时针旋转 90 度。要正确显示它,您需要找到图像的方向并使用代码中的信息将图像旋转到 0 度。

代表用户帐户或个人资料图片的通用个人资料图标,逆时针旋转 90 度。

一些 .jpg 格式的图像的方向信息包含在 Exif 元数据中。如果可用,则图像的 Exif 元数据包含方向。在 Exif 元数据中,您可以在 orientation 字段中找到图像的方向。虽然 Amazon Rekognition Image 会发现 Exif 元数据中存在图像方向信息,但它不会提供对该信息的访问权限。要访问图像中的 Exif 元数据,请使用第三方库或编写您自己的代码。有关更多信息,请参阅 Exif 版本 2.32

如果您知道图像的方向,可编写代码来旋转并正确显示它。

显示边界框

分析图像中人脸的 Amazon Rekognition Image 操作还将返回人脸周围的边界框的坐标。有关更多信息,请参阅BoundingBox

要在您的应用程序中围绕人脸显示与下图中所示的框类似的边界框,请在代码中使用边界框坐标。操作返回的边界框坐标反应图像的方向。如果您必须旋转图像才能正确显示它,您可能需要转换边界框坐标。

个人资料图标,脸部以红色方块突出显示。

在 Exif 元数据中存在方向信息时显示边界框

如果图像的方向包含在 Exif 元数据中,则 Amazon Rekognition Image 操作将执行下列操作:

  • 在操作响应的方向校正字段中返回 null。要旋转图像,请在代码中使用 Exif 元数据中提供的方向。

  • 返回已朝向 0 度的边界框坐标。要将边界框显示在正确位置,请使用返回的坐标。您无需转换它们。

示例:获取图像的图像方向和边界框坐标

以下示例说明如何使用 AWS SDK 获取 Exif 图像方向数据和通过 RecognizeCelebrities 操作检测到的名人的边界框坐标。

注意

自 2021 年 8 月起,已停止支持使用 OrientationCorrection 字段估算图像方向。API 响应中包含的该字段的任何返回值将始终为 NULL。

Java

此示例将从本地文件系统加载图像,调用 RecognizeCelebrities 操作,确定图像的高度和宽度并计算已旋转图像的人脸的边界框坐标。此示例未演示如何处理存储在 Exif 元数据中的方向信息。

在函数 main 中,请将 photo 的值替换为存储在本地的 .png 或 .jpg 格式的图像的名称和路径。

//Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. //PDX-License-Identifier: MIT-0 (For details, see https://github.com/awsdocs/amazon-rekognition-developer-guide/blob/master/LICENSE-SAMPLECODE.) package com.amazonaws.samples; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.List; import javax.imageio.ImageIO; import com.amazonaws.services.rekognition.AmazonRekognition; import com.amazonaws.services.rekognition.AmazonRekognitionClientBuilder; import com.amazonaws.services.rekognition.model.Image; import com.amazonaws.services.rekognition.model.RecognizeCelebritiesRequest; import com.amazonaws.services.rekognition.model.RecognizeCelebritiesResult; import com.amazonaws.util.IOUtils; import com.amazonaws.services.rekognition.model.AmazonRekognitionException; import com.amazonaws.services.rekognition.model.BoundingBox; import com.amazonaws.services.rekognition.model.Celebrity; import com.amazonaws.services.rekognition.model.ComparedFace; public class RotateImage { public static void main(String[] args) throws Exception { String photo = "photo.png"; //Get Rekognition client AmazonRekognition amazonRekognition = AmazonRekognitionClientBuilder.defaultClient(); // Load image ByteBuffer imageBytes=null; BufferedImage image = null; try (InputStream inputStream = new FileInputStream(new File(photo))) { imageBytes = ByteBuffer.wrap(IOUtils.toByteArray(inputStream)); } catch(Exception e) { System.out.println("Failed to load file " + photo); System.exit(1); } //Get image width and height InputStream imageBytesStream; imageBytesStream = new ByteArrayInputStream(imageBytes.array()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); image=ImageIO.read(imageBytesStream); ImageIO.write(image, "jpg", baos); int height = image.getHeight(); int width = image.getWidth(); System.out.println("Image Information:"); System.out.println(photo); System.out.println("Image Height: " + Integer.toString(height)); System.out.println("Image Width: " + Integer.toString(width)); //Call GetCelebrities try{ RecognizeCelebritiesRequest request = new RecognizeCelebritiesRequest() .withImage(new Image() .withBytes((imageBytes))); RecognizeCelebritiesResult result = amazonRekognition.recognizeCelebrities(request); // The returned value of OrientationCorrection will always be null System.out.println("Orientation: " + result.getOrientationCorrection() + "\n"); List <Celebrity> celebs = result.getCelebrityFaces(); for (Celebrity celebrity: celebs) { System.out.println("Celebrity recognized: " + celebrity.getName()); System.out.println("Celebrity ID: " + celebrity.getId()); ComparedFace face = celebrity.getFace() ; ShowBoundingBoxPositions(height, width, face.getBoundingBox(), result.getOrientationCorrection()); System.out.println(); } } catch (AmazonRekognitionException e) { e.printStackTrace(); } } public static void ShowBoundingBoxPositions(int imageHeight, int imageWidth, BoundingBox box, String rotation) { float left = 0; float top = 0; if(rotation==null){ System.out.println("No estimated estimated orientation. Check Exif data."); return; } //Calculate face position based on image orientation. switch (rotation) { case "ROTATE_0": left = imageWidth * box.getLeft(); top = imageHeight * box.getTop(); break; case "ROTATE_90": left = imageHeight * (1 - (box.getTop() + box.getHeight())); top = imageWidth * box.getLeft(); break; case "ROTATE_180": left = imageWidth - (imageWidth * (box.getLeft() + box.getWidth())); top = imageHeight * (1 - (box.getTop() + box.getHeight())); break; case "ROTATE_270": left = imageHeight * box.getTop(); top = imageWidth * (1 - box.getLeft() - box.getWidth()); break; default: System.out.println("No estimated orientation information. Check Exif data."); return; } //Display face location information. System.out.println("Left: " + String.valueOf((int) left)); System.out.println("Top: " + String.valueOf((int) top)); System.out.println("Face Width: " + String.valueOf((int)(imageWidth * box.getWidth()))); System.out.println("Face Height: " + String.valueOf((int)(imageHeight * box.getHeight()))); } }
Python

此示例使用 PIL/Pillow 图像库来获取图像宽度和高度。有关更多信息,请参阅 Pillow。此示例将保留 exif 元数据,您在应用程序中的其他地方可能需要这些元数据。

在函数 main 中,请将 photo 的值替换为存储在本地的 .png 或 .jpg 格式的图像的名称和路径。

#Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. #PDX-License-Identifier: MIT-0 (For details, see https://github.com/awsdocs/amazon-rekognition-developer-guide/blob/master/LICENSE-SAMPLECODE.) import boto3 import io from PIL import Image # Calculate positions from from estimated rotation def show_bounding_box_positions(imageHeight, imageWidth, box): left = 0 top = 0 print('Left: ' + '{0:.0f}'.format(left)) print('Top: ' + '{0:.0f}'.format(top)) print('Face Width: ' + "{0:.0f}".format(imageWidth * box['Width'])) print('Face Height: ' + "{0:.0f}".format(imageHeight * box['Height'])) def celebrity_image_information(photo): client = boto3.client('rekognition') # Get image width and height image = Image.open(open(photo, 'rb')) width, height = image.size print('Image information: ') print(photo) print('Image Height: ' + str(height)) print('Image Width: ' + str(width)) # call detect faces and show face age and placement # if found, preserve exif info stream = io.BytesIO() if 'exif' in image.info: exif = image.info['exif'] image.save(stream, format=image.format, exif=exif) else: image.save(stream, format=image.format) image_binary = stream.getvalue() response = client.recognize_celebrities(Image={'Bytes': image_binary}) print() print('Detected celebrities for ' + photo) for celebrity in response['CelebrityFaces']: print('Name: ' + celebrity['Name']) print('Id: ' + celebrity['Id']) # Value of "orientation correction" will always be null if 'OrientationCorrection' in response: show_bounding_box_positions(height, width, celebrity['Face']['BoundingBox']) print() return len(response['CelebrityFaces']) def main(): photo = 'photo' celebrity_count = celebrity_image_information(photo) print("celebrities detected: " + str(celebrity_count)) if __name__ == "__main__": main()
Java V2

此代码取自 AWS 文档 SDK 示例 GitHub 存储库。请在此处查看完整示例。

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.RecognizeCelebritiesRequest; import software.amazon.awssdk.services.rekognition.model.Image; import software.amazon.awssdk.services.rekognition.model.RecognizeCelebritiesResponse; import software.amazon.awssdk.services.rekognition.model.Celebrity; import software.amazon.awssdk.services.rekognition.model.ComparedFace; import software.amazon.awssdk.services.rekognition.model.RekognitionException; import software.amazon.awssdk.services.rekognition.model.BoundingBox; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.*; import java.util.List; /** * Before running this Java V2 code example, set up your development * environment, including your credentials. * * For more information, see the following documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html */ public class RotateImage { public static void main(String[] args) { final String usage = """ Usage: <sourceImage> Where: sourceImage - The path to the image (for example, C:\\AWS\\pic1.png).\s """; if (args.length != 1) { System.out.println(usage); System.exit(1); } String sourceImage = args[0]; Region region = Region.US_EAST_1; RekognitionClient rekClient = RekognitionClient.builder() .region(region) .build(); System.out.println("Locating celebrities in " + sourceImage); recognizeAllCelebrities(rekClient, sourceImage); rekClient.close(); } public static void recognizeAllCelebrities(RekognitionClient rekClient, String sourceImage) { try { BufferedImage image; InputStream sourceStream = new FileInputStream(sourceImage); SdkBytes sourceBytes = SdkBytes.fromInputStream(sourceStream); image = ImageIO.read(sourceBytes.asInputStream()); int height = image.getHeight(); int width = image.getWidth(); Image souImage = Image.builder() .bytes(sourceBytes) .build(); RecognizeCelebritiesRequest request = RecognizeCelebritiesRequest.builder() .image(souImage) .build(); RecognizeCelebritiesResponse result = rekClient.recognizeCelebrities(request); List<Celebrity> celebs = result.celebrityFaces(); System.out.println(celebs.size() + " celebrity(s) were recognized.\n"); for (Celebrity celebrity : celebs) { System.out.println("Celebrity recognized: " + celebrity.name()); System.out.println("Celebrity ID: " + celebrity.id()); ComparedFace face = celebrity.face(); ShowBoundingBoxPositions(height, width, face.boundingBox(), result.orientationCorrectionAsString()); } } catch (RekognitionException | FileNotFoundException e) { System.out.println(e.getMessage()); System.exit(1); } catch (IOException e) { e.printStackTrace(); } } public static void ShowBoundingBoxPositions(int imageHeight, int imageWidth, BoundingBox box, String rotation) { float left; float top; if (rotation == null) { System.out.println("No estimated estimated orientation."); return; } // Calculate face position based on the image orientation. switch (rotation) { case "ROTATE_0" -> { left = imageWidth * box.left(); top = imageHeight * box.top(); } case "ROTATE_90" -> { left = imageHeight * (1 - (box.top() + box.height())); top = imageWidth * box.left(); } case "ROTATE_180" -> { left = imageWidth - (imageWidth * (box.left() + box.width())); top = imageHeight * (1 - (box.top() + box.height())); } case "ROTATE_270" -> { left = imageHeight * box.top(); top = imageWidth * (1 - box.left() - box.width()); } default -> { System.out.println("No estimated orientation information. Check Exif data."); return; } } System.out.println("Left: " + (int) left); System.out.println("Top: " + (int) top); System.out.println("Face Width: " + (int) (imageWidth * box.width())); System.out.println("Face Height: " + (int) (imageHeight * box.height())); } }