使用经过训练的模型分析图像 - Rekognition

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

使用经过训练的模型分析图像

要使用经过训练的 Amazon Rekognition 自定义标签模型分析图片,您可以调用标签 API。DetectCustomDetectCustomLabels 可以预测图像中是否包含特定的物体、场景或概念。

要调用 DetectCustomLabels,请指定以下内容:

  • 要使用的 Amazon Rekognition Custom Labels 模型的 Amazon 资源名称 (ARN)。

  • 您希望模型进行预测的图像。您可以提供输入图像作为图像字节数组(base64 编码的图像字节)或 Amazon S3 对象。有关更多信息,请参阅图像

自定义标签以自定义标签对象数组的形式返回。每个自定义标签代表图像中的单个物体、场景或概念。自定义标签包括:

  • 在图像中找到的物体、场景或概念的标签。

  • 在图像中找到的物体的边界框。边界框坐标显示物体在源图像中的位置。坐标值是占图像总体尺寸的比率。有关更多信息,请参阅BoundingBoxDetectCustomLabels仅当模型经过训练可以检测物体位置时,才会返回边界框。

  • Amazon Rekognition Custom Labels 对标签和边界框的准确性的置信度。

要根据检测置信度筛选标签,请为 MinConfidence 指定一个与所需置信度相匹配的值。例如,如果您需要对预测非常有信心,请为 MinConfidence 指定一个较高的值。要获取所有标签(无论置信度如何),请将 MinConfidence 的值指定为 0。

模型的性能部分通过模型训练期间计算的召回率和精度指标来衡量。有关更多信息,请参阅 评估模型的指标

要提高模型的精度,请为 MinConfidence 设置更高的值。有关更多信息,请参阅 减少假正例(更高的精度)

要提高模型的召回率,请使用较低的 MinConfidence 值。有关更多信息,请参阅 减少假负例(更好的召回率)

如果不为 MinConfidence 指定值,Amazon Rekognition Custom Labels 将根据该标签的假设阈值返回一个标签。有关更多信息,请参阅 假设阈值。可以从模型的训练结果中获取标签的假设阈值。有关更多信息,请参阅 训练模型(控制台)

通过使用 MinConfidence 输入参数,可为调用指定所需的阈值。检测到的置信度低于 MinConfidence 的值的标签不会在响应中返回。此外,标签的假设阈值不会影响在响应中包含该标签。

注意

Amazon Rekognition Custom Labels 指标将假设阈值表示为 0 到 1 之间的浮点值。MinConfidence 范围将阈值标准化为百分比值 (0-100)。来自的置信度响应 DetectCustomLabels 也会以百分比形式返回。

您可能想要为特定标签指定阈值。例如,当精度指标对于标签 A 来说是可接受的,但对于标签 B 来说却不可接受时。指定不同的阈值 (MinConfidence) 时,请考虑以下几点。

  • 如果您只对单个标签 (A) 感兴趣,请将 MinConfidence 的值设置为所需的阈值。在响应中,只有当置信度大于 MinConfidence 时,才会返回标签 A 的预测(以及其他标签)。您需要筛选掉返回的所有其他标签。

  • 如果要对多个标签应用不同的阈值,请执行以下操作:

    1. MinConfidence 指定值 0。值 0 可确保返回所有标签(无论测检置信度如何)。

    2. 对于返回的每个标签,通过检查标签置信度是否大于您想要的标签阈值来应用所需的阈值。

有关更多信息,请参阅 改进经过训练的 Amazon Rekognition Custom Labels 模型

如果您发现 DetectCustomLabels 返回的置信度值过低,请考虑重新训练模型。有关更多信息,请参阅 训练 Amazon Rekognition Custom Labels 模型。您可以通过指定 MaxResults 输入参数来限制 DetectCustomLabels 返回的自定义标签的数量。返回的结果按置信度由高到低的顺序排列。

有关调用 DetectCustomLabels 的其他示例,请参阅示例

有关如何保护 DetectCustomLabels 的信息,请参阅保护 DetectCustomLabels

检测自定义标签 (API)
  1. 如果您尚未执行以下操作,请:

    1. 确保您具有 DetectCustomLabelsAmazonS3ReadOnlyAccess 权限。有关更多信息,请参阅 设置 SDK 权限

    2. 安装和配置 AWS CLI 和 AWS SDK。有关更多信息,请参阅 步骤 4:设置 AWS CLI 和 AWS 软件开发工具包

  2. 训练和部署您的模型。有关更多信息,请参阅 创建 Amazon Rekognition Custom Labels 模型

  3. 确保调用 DetectCustomLabels 的用户可以访问您在步骤 2 中使用的模型。有关更多信息,请参阅 保护 DetectCustomLabels

  4. 将要分析的图像上传到 S3 存储桶。

    有关说明,请参阅《Amazon Simple Storage Service 用户指南》中的将对象上传到 Amazon S3Python、Java 和 Java 2 示例还向您展示了如何使用本地图像文件通过原始字节传递图像。文件必须小于 4 MB。

  5. 使用以下示例调用 DetectCustomLabels 操作。Python 和 Java 示例显示叠加了分析结果的图像,类似于如下图像。下图包含带有电位计、红外光电晶体管和 LED 组件的电路板的边界框和标签。

    带有电位计、红外光电晶体管和标有 LED 组件的电路板。
    AWS CLI

    此 AWS CLI 命令显示 DetectCustomLabels CLI 操作的 JSON 输出。更改以下输入参数的值。

    • bucket 更改为在步骤 4 中使用的 Amazon S3 存储桶的名称。

    • image 更改为在步骤 4 中上传的输入图像文件的名称。

    • projectVersionArn 更改为要使用的模型的 ARN。

    aws rekognition detect-custom-labels --project-version-arn model_arn \ --image '{"S3Object":{"Bucket":"bucket","Name":"image"}}' \ --min-confidence 70 \ --profile custom-labels-access
    Python

    以下示例代码显示在图像中找到的边界框和图像级标签。

    要分析本地图像,请运行该程序并提供以下命令行参数:

    • 要用于分析图像的模型的 ARN。

    • 本地图像文件的名称和位置。

    要分析存储在 Amazon S3 存储桶中的图像,请运行该程序并提供以下命令行参数:

    • 要用于分析图像的模型的 ARN。

    • 在步骤 4 中使用的 Amazon S3 存储桶中的图像的名称和位置。

    • --bucket 存储桶名称:在步骤 4 中使用的 Amazon S3 存储桶。

    请注意,此示例假设你的 Pillow 版本为 >= 8.0.0。

    # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: Apache-2.0 """ Purpose Amazon Rekognition Custom Labels detection example used in the service documentation: https://docs.aws.amazon.com/rekognition/latest/customlabels-dg/detecting-custom-labels.html Shows how to detect custom labels by using an Amazon Rekognition Custom Labels model. The image can be stored on your local computer or in an Amazon S3 bucket. """ import io import logging import argparse import boto3 from PIL import Image, ImageDraw, ImageFont from botocore.exceptions import ClientError logger = logging.getLogger(__name__) def analyze_local_image(rek_client, model, photo, min_confidence): """ Analyzes an image stored as a local file. :param rek_client: The Amazon Rekognition Boto3 client. :param s3_connection: The Amazon S3 Boto3 S3 connection object. :param model: The ARN of the Amazon Rekognition Custom Labels model that you want to use. :param photo: The name and file path of the photo that you want to analyze. :param min_confidence: The desired threshold/confidence for the call. """ try: logger.info("Analyzing local file: %s", photo) image = Image.open(photo) image_type = Image.MIME[image.format] if (image_type == "image/jpeg" or image_type == "image/png") is False: logger.error("Invalid image type for %s", photo) raise ValueError( f"Invalid file format. Supply a jpeg or png format file: {photo}" ) # get images bytes for call to detect_anomalies image_bytes = io.BytesIO() image.save(image_bytes, format=image.format) image_bytes = image_bytes.getvalue() response = rek_client.detect_custom_labels(Image={'Bytes': image_bytes}, MinConfidence=min_confidence, ProjectVersionArn=model) show_image(image, response) return len(response['CustomLabels']) except ClientError as client_err: logger.error(format(client_err)) raise except FileNotFoundError as file_error: logger.error(format(file_error)) raise def analyze_s3_image(rek_client, s3_connection, model, bucket, photo, min_confidence): """ Analyzes an image stored in the specified S3 bucket. :param rek_client: The Amazon Rekognition Boto3 client. :param s3_connection: The Amazon S3 Boto3 S3 connection object. :param model: The ARN of the Amazon Rekognition Custom Labels model that you want to use. :param bucket: The name of the S3 bucket that contains the image that you want to analyze. :param photo: The name of the photo that you want to analyze. :param min_confidence: The desired threshold/confidence for the call. """ try: # Get image from S3 bucket. logger.info("analyzing bucket: %s image: %s", bucket, photo) s3_object = s3_connection.Object(bucket, photo) s3_response = s3_object.get() stream = io.BytesIO(s3_response['Body'].read()) image = Image.open(stream) image_type = Image.MIME[image.format] if (image_type == "image/jpeg" or image_type == "image/png") is False: logger.error("Invalid image type for %s", photo) raise ValueError( f"Invalid file format. Supply a jpeg or png format file: {photo}") ImageDraw.Draw(image) # Call DetectCustomLabels. response = rek_client.detect_custom_labels( Image={'S3Object': {'Bucket': bucket, 'Name': photo}}, MinConfidence=min_confidence, ProjectVersionArn=model) show_image(image, response) return len(response['CustomLabels']) except ClientError as err: logger.error(format(err)) raise def show_image(image, response): """ Displays the analyzed image and overlays analysis results :param image: The analyzed image :param response: the response from DetectCustomLabels """ try: font_size = 40 line_width = 5 img_width, img_height = image.size draw = ImageDraw.Draw(image) # Calculate and display bounding boxes for each detected custom label. image_level_label_height = 0 for custom_label in response['CustomLabels']: confidence = int(round(custom_label['Confidence'], 0)) label_text = f"{custom_label['Name']}:{confidence}%" fnt = ImageFont.truetype('Tahoma.ttf', font_size) text_left, text_top, text_right, text_bottom = draw.textbbox((0, 0), label_text, fnt) text_width, text_height = text_right - text_left, text_bottom - text_top logger.info("Label: %s", custom_label['Name']) logger.info("Confidence: %s", confidence) # Draw bounding boxes, if present if 'Geometry' in custom_label: box = custom_label['Geometry']['BoundingBox'] left = img_width * box['Left'] top = img_height * box['Top'] width = img_width * box['Width'] height = img_height * box['Height'] logger.info("Bounding box") logger.info("\tLeft: {0:.0f}".format(left)) logger.info("\tTop: {0:.0f}".format(top)) logger.info("\tLabel Width: {0:.0f}".format(width)) logger.info("\tLabel Height: {0:.0f}".format(height)) points = ( (left, top), (left + width, top), (left + width, top + height), (left, top + height), (left, top)) # Draw bounding box and label text draw.line(points, fill="limegreen", width=line_width) draw.rectangle([(left + line_width, top+line_width), (left + text_width + line_width, top + line_width + text_height)], fill="black") draw.text((left + line_width, top + line_width), label_text, fill="limegreen", font=fnt) # draw image-level label text. else: draw.rectangle([(10, image_level_label_height), (text_width + 10, image_level_label_height+text_height)], fill="black") draw.text((10, image_level_label_height), label_text, fill="limegreen", font=fnt) image_level_label_height += text_height image.show() except Exception as err: logger.error(format(err)) raise def add_arguments(parser): """ Adds command line arguments to the parser. :param parser: The command line parser. """ parser.add_argument( "model_arn", help="The ARN of the model that you want to use." ) parser.add_argument( "image", help="The path and file name of the image that you want to analyze" ) parser.add_argument( "--bucket", help="The bucket that contains the image. If not supplied, image is assumed to be a local file.", required=False ) def main(): try: logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") # Get command line arguments. parser = argparse.ArgumentParser(usage=argparse.SUPPRESS) add_arguments(parser) args = parser.parse_args() label_count = 0 min_confidence = 50 session = boto3.Session(profile_name='custom-labels-access') rekognition_client = session.client("rekognition") if args.bucket is None: # Analyze local image. label_count = analyze_local_image(rekognition_client, args.model_arn, args.image, min_confidence) else: # Analyze image in S3 bucket. s3_connection = session.resource('s3') label_count = analyze_s3_image(rekognition_client, s3_connection, args.model_arn, args.bucket, args.image, min_confidence) print(f"Custom labels detected: {label_count}") except ClientError as client_err: print("A service client error occurred: " + format(client_err.response["Error"]["Message"])) except ValueError as value_err: print("A value error occurred: " + format(value_err)) except FileNotFoundError as file_error: print("File not found error: " + format(file_error)) except Exception as err: print("An error occurred: " + format(err)) if __name__ == "__main__": main()
    Java

    以下示例代码显示在图像中找到的边界框和图像级标签。

    要分析本地图像,请运行该程序并提供以下命令行参数:

    • 要用于分析图像的模型的 ARN。

    • 本地图像文件的名称和位置。

    要分析存储在 Amazon S3 存储桶中的图像,请运行该程序并提供以下命令行参数:

    • 要用于分析图像的模型的 ARN。

    • 在步骤 4 中使用的 Amazon S3 存储桶中的图像的名称和位置。

    • 包含在步骤 4 中使用的图像的 Amazon S3 存储桶。

    /* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package com.amazonaws.samples; import java.awt.*; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.List; import javax.imageio.ImageIO; import javax.swing.*; import java.io.FileNotFoundException; import java.awt.font.FontRenderContext; import java.util.logging.Level; import java.util.logging.Logger; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.nio.ByteBuffer; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import com.amazonaws.services.rekognition.AmazonRekognition; import com.amazonaws.services.rekognition.AmazonRekognitionClientBuilder; import com.amazonaws.services.rekognition.model.BoundingBox; import com.amazonaws.services.rekognition.model.CustomLabel; import com.amazonaws.services.rekognition.model.DetectCustomLabelsRequest; import com.amazonaws.services.rekognition.model.DetectCustomLabelsResult; import com.amazonaws.services.rekognition.model.Image; import com.amazonaws.services.rekognition.model.S3Object; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.S3ObjectInputStream; import com.amazonaws.services.rekognition.model.AmazonRekognitionException; import com.amazonaws.services.s3.model.AmazonS3Exception; import com.amazonaws.util.IOUtils; // Calls DetectCustomLabels and displays a bounding box around each detected image. public class DetectCustomLabels extends JPanel { private transient DetectCustomLabelsResult response; private transient Dimension dimension; private transient BufferedImage image; public static final Logger logger = Logger.getLogger(DetectCustomLabels.class.getName()); // Finds custom labels in an image stored in an S3 bucket. public DetectCustomLabels(AmazonRekognition rekClient, AmazonS3 s3client, String projectVersionArn, String bucket, String key, Float minConfidence) throws AmazonRekognitionException, AmazonS3Exception, IOException { logger.log(Level.INFO, "Processing S3 bucket: {0} image {1}", new Object[] { bucket, key }); // Get image from S3 bucket and create BufferedImage com.amazonaws.services.s3.model.S3Object s3object = s3client.getObject(bucket, key); S3ObjectInputStream inputStream = s3object.getObjectContent(); image = ImageIO.read(inputStream); // Set image size setWindowDimensions(); DetectCustomLabelsRequest request = new DetectCustomLabelsRequest() .withProjectVersionArn(projectVersionArn) .withImage(new Image().withS3Object(new S3Object().withName(key).withBucket(bucket))) .withMinConfidence(minConfidence); // Call DetectCustomLabels response = rekClient.detectCustomLabels(request); logFoundLabels(response.getCustomLabels()); drawLabels(); } // Finds custom label in a local image file. public DetectCustomLabels(AmazonRekognition rekClient, String projectVersionArn, String photo, Float minConfidence) throws IOException, AmazonRekognitionException { logger.log(Level.INFO, "Processing local file: {0}", photo); // Get image bytes and buffered image ByteBuffer imageBytes; try (InputStream inputStream = new FileInputStream(new File(photo))) { imageBytes = ByteBuffer.wrap(IOUtils.toByteArray(inputStream)); } // Get image for display InputStream imageBytesStream; imageBytesStream = new ByteArrayInputStream(imageBytes.array()); ByteArrayOutputStream baos = new ByteArrayOutputStream(); image = ImageIO.read(imageBytesStream); ImageIO.write(image, "jpg", baos); // Set image size setWindowDimensions(); // Analyze image DetectCustomLabelsRequest request = new DetectCustomLabelsRequest() .withProjectVersionArn(projectVersionArn) .withImage(new Image() .withBytes(imageBytes)) .withMinConfidence(minConfidence); response = rekClient.detectCustomLabels(request); logFoundLabels(response.getCustomLabels()); drawLabels(); } // Log the labels found by DetectCustomLabels private void logFoundLabels(List<CustomLabel> customLabels) { logger.info("Custom labels found"); if (customLabels.isEmpty()) { logger.log(Level.INFO, "No Custom Labels found. Consider lowering min confidence."); } else { for (CustomLabel customLabel : customLabels) { logger.log(Level.INFO, " Label: {0} Confidence: {1}", new Object[] { customLabel.getName(), customLabel.getConfidence() }); } } } // Sets window dimensions to 1/2 screen size, unless image is smaller public void setWindowDimensions() { dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); dimension.width = (int) dimension.getWidth() / 2; if (image.getWidth() < dimension.width) { dimension.width = image.getWidth(); } dimension.height = (int) dimension.getHeight() / 2; if (image.getHeight() < dimension.height) { dimension.height = image.getHeight(); } setPreferredSize(dimension); } // Draws the image containing the bounding boxes and labels. @Override public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; // Create a Java2D version of g. // Draw the image. g2d.drawImage(image, 0, 0, dimension.width, dimension.height, this); } public void drawLabels() { // Draws bounding boxes (if present) and label text. int boundingBoxBorderWidth = 5; int imageHeight = image.getHeight(this); int imageWidth = image.getWidth(this); // Set up drawing Graphics2D g2d = image.createGraphics(); g2d.setColor(Color.GREEN); g2d.setFont(new Font("Tahoma", Font.PLAIN, 50)); Font font = g2d.getFont(); FontRenderContext frc = g2d.getFontRenderContext(); g2d.setStroke(new BasicStroke(boundingBoxBorderWidth)); List<CustomLabel> customLabels = response.getCustomLabels(); int imageLevelLabelHeight = 0; for (CustomLabel customLabel : customLabels) { String label = customLabel.getName(); int textWidth = (int) (font.getStringBounds(label, frc).getWidth()); int textHeight = (int) (font.getStringBounds(label, frc).getHeight()); // Draw bounding box, if present if (customLabel.getGeometry() != null) { BoundingBox box = customLabel.getGeometry().getBoundingBox(); float left = imageWidth * box.getLeft(); float top = imageHeight * box.getTop(); // Draw black rectangle g2d.setColor(Color.BLACK); g2d.fillRect(Math.round(left + (boundingBoxBorderWidth)), Math.round(top + (boundingBoxBorderWidth)), textWidth + boundingBoxBorderWidth, textHeight + boundingBoxBorderWidth); // Write label onto black rectangle g2d.setColor(Color.GREEN); g2d.drawString(label, left + boundingBoxBorderWidth, (top + textHeight)); // Draw bounding box around label location g2d.drawRect(Math.round(left), Math.round(top), Math.round((imageWidth * box.getWidth())), Math.round((imageHeight * box.getHeight()))); } // Draw image level labels. else { // Draw black rectangle g2d.setColor(Color.BLACK); g2d.fillRect(10, 10 + imageLevelLabelHeight, textWidth, textHeight); g2d.setColor(Color.GREEN); g2d.drawString(label, 10, textHeight + imageLevelLabelHeight); imageLevelLabelHeight += textHeight; } } g2d.dispose(); } public static void main(String args[]) throws Exception { String photo = null; String bucket = null; String projectVersionArn = null; float minConfidence = 50; final String USAGE = "\n" + "Usage: " + "<model_arn> <image> <bucket>\n\n" + "Where:\n" + " model_arn - The ARN of the model that you want to use. \n\n" + " image - The location of the image on your local file system or within an S3 bucket.\n\n" + " bucket - The S3 bucket that contains the image. Don't specify if image is local.\n\n"; // Collect the arguments. If 3 arguments are present, the image is assumed to be // in an S3 bucket. if (args.length < 2 || args.length > 3) { System.out.println(USAGE); System.exit(1); } projectVersionArn = args[0]; photo = args[1]; if (args.length == 3) { bucket = args[2]; } DetectCustomLabels panel = null; try { AWSCredentialsProvider provider =new ProfileCredentialsProvider("custom-labels-access"); AmazonRekognition rekClient = AmazonRekognitionClientBuilder.standard() .withCredentials(provider) .withRegion(Regions.US_WEST_2) .build(); AmazonS3 s3client = AmazonS3ClientBuilder.standard() .withCredentials(provider) .withRegion(Regions.US_WEST_2) .build(); // Create frame and panel. JFrame frame = new JFrame("Custom Labels"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); if (args.length == 2) { // Analyze local image panel = new DetectCustomLabels(rekClient, projectVersionArn, photo, minConfidence); } else { // Analyze image in S3 bucket panel = new DetectCustomLabels(rekClient, s3client, projectVersionArn, bucket, photo, minConfidence); } frame.setContentPane(panel); frame.pack(); frame.setVisible(true); } catch (AmazonRekognitionException rekError) { String errorMessage = "Rekognition client error: " + rekError.getMessage(); logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (FileNotFoundException fileError) { String errorMessage = "File not found: " + photo; logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (IOException fileError) { String errorMessage = "Input output exception: " + fileError.getMessage(); logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (AmazonS3Exception s3Error) { String errorMessage = "S3 error: " + s3Error.getErrorMessage(); logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } } }
    Java V2

    以下示例代码显示在图像中找到的边界框和图像级标签。

    要分析本地图像,请运行该程序并提供以下命令行参数:

    • projectVersionArn:要用于分析图像的模型的 ARN。

    • photo:本地图像文件的名称和位置。

    要分析存储在 S3 存储桶中的图像,请运行该程序并提供以下命令行参数:

    • 要用于分析图像的模型的 ARN。

    • 在步骤 4 中使用的 S3 存储桶中的图像的名称和位置。

    • 包含在步骤 4 中使用的图像的 Amazon S3 存储桶。

    /* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: Apache-2.0 */ package com.example.rekognition; import software.amazon.awssdk.auth.credentials.ProfileCredentialsProvider; import software.amazon.awssdk.core.ResponseBytes; import software.amazon.awssdk.core.SdkBytes; import software.amazon.awssdk.core.sync.ResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.rekognition.RekognitionClient; import software.amazon.awssdk.services.rekognition.model.S3Object; import software.amazon.awssdk.services.rekognition.model.Image; import software.amazon.awssdk.services.rekognition.model.DetectCustomLabelsRequest; import software.amazon.awssdk.services.rekognition.model.DetectCustomLabelsResponse; import software.amazon.awssdk.services.rekognition.model.CustomLabel; import software.amazon.awssdk.services.rekognition.model.RekognitionException; import software.amazon.awssdk.services.rekognition.model.BoundingBox; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.model.GetObjectRequest; import software.amazon.awssdk.services.s3.model.GetObjectResponse; import software.amazon.awssdk.services.s3.model.NoSuchBucketException; import software.amazon.awssdk.services.s3.model.NoSuchKeyException; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.List; import java.awt.*; import java.awt.font.FontRenderContext; import java.awt.image.BufferedImage; import javax.imageio.ImageIO; import javax.swing.*; import java.util.logging.Level; import java.util.logging.Logger; // Calls DetectCustomLabels on an image. Displays bounding boxes or // image level labels found in the image. public class ShowCustomLabels extends JPanel { private transient BufferedImage image; private transient DetectCustomLabelsResponse response; private transient Dimension dimension; public static final Logger logger = Logger.getLogger(ShowCustomLabels.class.getName()); // Finds custom labels in an image stored in an S3 bucket. public ShowCustomLabels(RekognitionClient rekClient, S3Client s3client, String projectVersionArn, String bucket, String key, Float minConfidence) throws RekognitionException, NoSuchBucketException, NoSuchKeyException, IOException { logger.log(Level.INFO, "Processing S3 bucket: {0} image {1}", new Object[] { bucket, key }); // Get image from S3 bucket and create BufferedImage GetObjectRequest requestObject = GetObjectRequest.builder().bucket(bucket).key(key).build(); ResponseBytes<GetObjectResponse> result = s3client.getObject(requestObject, ResponseTransformer.toBytes()); ByteArrayInputStream bis = new ByteArrayInputStream(result.asByteArray()); image = ImageIO.read(bis); // Set image size setWindowDimensions(); // Construct request parameter for DetectCustomLabels S3Object s3Object = S3Object.builder().bucket(bucket).name(key).build(); Image s3Image = Image.builder().s3Object(s3Object).build(); DetectCustomLabelsRequest request = DetectCustomLabelsRequest.builder().image(s3Image) .projectVersionArn(projectVersionArn).minConfidence(minConfidence).build(); response = rekClient.detectCustomLabels(request); logFoundLabels(response.customLabels()); drawLabels(); } // Finds custom label in a local image file. public ShowCustomLabels(RekognitionClient rekClient, String projectVersionArn, String photo, Float minConfidence) throws IOException, RekognitionException { logger.log(Level.INFO, "Processing local file: {0}", photo); // Get image bytes and buffered image InputStream sourceStream = new FileInputStream(new File(photo)); SdkBytes imageBytes = SdkBytes.fromInputStream(sourceStream); ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes.asByteArray()); image = ImageIO.read(inputStream); setWindowDimensions(); // Construct request parameter for DetectCustomLabels Image localImageBytes = Image.builder().bytes(imageBytes).build(); DetectCustomLabelsRequest request = DetectCustomLabelsRequest.builder().image(localImageBytes) .projectVersionArn(projectVersionArn).minConfidence(minConfidence).build(); response = rekClient.detectCustomLabels(request); logFoundLabels(response.customLabels()); drawLabels(); } // Sets window dimensions to 1/2 screen size, unless image is smaller public void setWindowDimensions() { dimension = java.awt.Toolkit.getDefaultToolkit().getScreenSize(); dimension.width = (int) dimension.getWidth() / 2; if (image.getWidth() < dimension.width) { dimension.width = image.getWidth(); } dimension.height = (int) dimension.getHeight() / 2; if (image.getHeight() < dimension.height) { dimension.height = image.getHeight(); } setPreferredSize(dimension); } // Draws bounding boxes (if present) and label text. public void drawLabels() { int boundingBoxBorderWidth = 5; int imageHeight = image.getHeight(this); int imageWidth = image.getWidth(this); // Set up drawing Graphics2D g2d = image.createGraphics(); g2d.setColor(Color.GREEN); g2d.setFont(new Font("Tahoma", Font.PLAIN, 50)); Font font = g2d.getFont(); FontRenderContext frc = g2d.getFontRenderContext(); g2d.setStroke(new BasicStroke(boundingBoxBorderWidth)); List<CustomLabel> customLabels = response.customLabels(); int imageLevelLabelHeight = 0; for (CustomLabel customLabel : customLabels) { String label = customLabel.name(); int textWidth = (int) (font.getStringBounds(label, frc).getWidth()); int textHeight = (int) (font.getStringBounds(label, frc).getHeight()); // Draw bounding box, if present if (customLabel.geometry() != null) { BoundingBox box = customLabel.geometry().boundingBox(); float left = imageWidth * box.left(); float top = imageHeight * box.top(); // Draw black rectangle g2d.setColor(Color.BLACK); g2d.fillRect(Math.round(left + (boundingBoxBorderWidth)), Math.round(top + (boundingBoxBorderWidth)), textWidth + boundingBoxBorderWidth, textHeight + boundingBoxBorderWidth); // Write label onto black rectangle g2d.setColor(Color.GREEN); g2d.drawString(label, left + boundingBoxBorderWidth, (top + textHeight)); // Draw bounding box around label location g2d.drawRect(Math.round(left), Math.round(top), Math.round((imageWidth * box.width())), Math.round((imageHeight * box.height()))); } // Draw image level labels. else { // Draw black rectangle g2d.setColor(Color.BLACK); g2d.fillRect(10, 10 + imageLevelLabelHeight, textWidth, textHeight); g2d.setColor(Color.GREEN); g2d.drawString(label, 10, textHeight + imageLevelLabelHeight); imageLevelLabelHeight += textHeight; } } g2d.dispose(); } // Log the labels found by DetectCustomLabels private void logFoundLabels(List<CustomLabel> customLabels) { logger.info("Custom labels found:"); if (customLabels.isEmpty()) { logger.log(Level.INFO, "No Custom Labels found. Consider lowering min confidence."); } else { for (CustomLabel customLabel : customLabels) { logger.log(Level.INFO, " Label: {0} Confidence: {1}", new Object[] { customLabel.name(), customLabel.confidence() } ); } } } // Draws the image containing the bounding boxes and labels. @Override public void paintComponent(Graphics g) { Graphics2D g2d = (Graphics2D) g; // Create a Java2D version of g. // Draw the image. g2d.drawImage(image, 0, 0, dimension.width, dimension.height, this); } public static void main(String args[]) throws Exception { String photo = null; String bucket = null; String projectVersionArn = null; final String USAGE = "\n" + "Usage: " + "<model_arn> <image> <bucket>\n\n" + "Where:\n" + " model_arn - The ARN of the model that you want to use. \n\n" + " image - The location of the image on your local file system or within an S3 bucket.\n\n" + " bucket - The S3 bucket that contains the image. Don't specify if image is local.\n\n"; // Collect the arguments. If 3 arguments are present, the image is assumed to be // in an S3 bucket. if (args.length < 2 || args.length > 3) { System.out.println(USAGE); System.exit(1); } projectVersionArn = args[0]; photo = args[1]; if (args.length == 3) { bucket = args[2]; } float minConfidence = 50; ShowCustomLabels panel = null; try { // Get the Rekognition client // Get the Rekognition client. RekognitionClient rekClient = RekognitionClient.builder() .credentialsProvider(ProfileCredentialsProvider.create("custom-labels-access")) .region(Region.US_WEST_2) .build(); S3Client s3Client = S3Client.builder() .credentialsProvider(ProfileCredentialsProvider.create("custom-labels-access")) .region(Region.US_WEST_2) .build(); // Create frame and panel. JFrame frame = new JFrame("Custom Labels"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); if (args.length == 2) { // Analyze local image panel = new ShowCustomLabels(rekClient, projectVersionArn, photo, minConfidence); } else { // Analyze image in S3 bucket panel = new ShowCustomLabels(rekClient, s3Client, projectVersionArn, bucket, photo, minConfidence); } frame.setContentPane(panel); frame.pack(); frame.setVisible(true); } catch (RekognitionException rekError) { String errorMessage = "Rekognition client error: " + rekError.getMessage(); logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (FileNotFoundException fileError) { String errorMessage = "File not found: " + photo; logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (IOException fileError) { String errorMessage = "Input output exception: " + fileError.getMessage(); logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (NoSuchKeyException bucketError) { String errorMessage = String.format("Image not found: %s in bucket %s.", photo, bucket); logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } catch (NoSuchBucketException bucketError) { String errorMessage = "Bucket not found: " + bucket; logger.log(Level.SEVERE, errorMessage); System.out.println(errorMessage); System.exit(1); } } }

DetectCustomLabels 操作请求

DetectCustomLabels 操作中,您可将输入图像作为 base64 编码的字节数组提供,也可将其作为 Amazon S3 存储桶中存储的图像提供。以下示例 JSON 请求显示从 Amazon S3 存储桶加载的图像。

{ "ProjectVersionArn": "string", "Image":{ "S3Object":{ "Bucket":"string", "Name":"string", "Version":"string" } }, "MinConfidence": 90, "MaxLabels": 10, }

DetectCustomLabels 操作响应

来自 DetectCustomLabels 操作的以下 JSON 响应显示了在下图中检测到的自定义标签。

{ "CustomLabels": [ { "Name": "MyLogo", "Confidence": 77.7729721069336, "Geometry": { "BoundingBox": { "Width": 0.198987677693367, "Height": 0.31296101212501526, "Left": 0.07924537360668182, "Top": 0.4037395715713501 } } } ] }