取得映像方向與週框方塊座標 - 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 中繼資料,請使用第三方程式庫或自行撰寫程式碼。如需詳細資訊,請參閱可交換映像檔案格式版本 2.32

當您知道映像的方向後,就可以撰寫程式碼加以旋轉並正確顯示。

顯示週框方塊

分析映像中人臉的 Amazon Rekognition Image 操作也會傳回人臉周圍的週框方塊座標。如需詳細資訊,請參閱BoundingBox

若要在您的應用程式中於人臉周圍顯示週框方塊 (類似下圖所示的方塊),請在您的程式碼中使用週框方塊座標。操作傳回的週框方塊座標會反映映像的方向。如果您必須旋轉映像才能將其正確顯示,可能需要移動週框方塊座標。

臉部以紅色方塊反白顯示的輪廓圖示。

在 Exif 中繼資料內有方向資訊時顯示週框方塊

如果 Exif 中繼資料包含映像的方向,Amazon Rekognition Image 操作會執行下列操作:

  • 在操作回應的方向修正欄位中傳回 null。若要旋轉映像,請在您的程式碼中使用 Exif 中繼資料提供的方向。

  • 傳回已旋轉為 0 度的週框方塊座標。若要在正確位置顯示週框方塊,請使用傳回的座標。您不需要移動該座標。

範例:取得映像方向與映像的週框方塊座標

下列範例示範如何使用適用於 AWS SDK 來取得 Exif 映像的方向資料,並透过 RecognizeCelebrities 操作偵測到之名人的週框方塊座標。

注意

自 2021 年 8 月起,已停止使用該 OrientationCorrection 欄位估算映像方向的支援。API 回應中包含之此欄位的任何傳回值將永遠為零。

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/枕狀映像程式庫來取得映像寬度和高度。如需詳細資訊,請參閱枕狀。此範例會保留 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())); } }