Blog de Amazon Web Services (AWS)

Picturesocial – Cómo analizar imágenes usando Inteligencia Artificial

Por José Yapur, Senior Developer Advocate AWS

Iniciamos este viaje con Containers, Registries, Kubernetes, Terraform y algunos servicios de AWS que nos permitieron desplegar nuestra primera API, pero este viaje recién comienza. El Core de Picturesocial es la capacidad de añadir tags de forma automática en base a las imágenes subidas por los usuarios a la red social. En este episodio aprenderemos a utilizar servicios de Inteligencia Artificial en Amazon Web Services, con reconocimiento de imágenes y patrones.

 

¿Qué es detección de imágenes?

Como humanos, somos muy buenos reconociendo cosas que hemos visto antes. Puedes ver esta foto y de forma inmediata reconocer que es un gato echado sobre una laptop con unas flores en el fondo. Si además sabes un poco sobre gatos, tal vez puedas reconocer que este gato es un adorable gatito persa.

Las computadoras no poseen esta habilidad innata de reconocer diferentes cosas en una imagen, pero pueden ser entrenadas para hacerlo. Deep learning es una técnica de Machine Learning que puede ser utilizada para permitir a las computadoras reconocer objetos en imágenes con diferentes niveles de confianza. Para que esto funcione, Deep Learning requiere que entrenemos modelos con miles de imágenes etiquetadas con: gato, flores, laptop y cualquier objeto que queramos reconocer. Esto necesita una cantidad significativa de data, tiempo y poder de cómputo, haciendo que sea difícil que entrenemos los modelos por nuestra cuenta.

Afortunadamente para nosotros, somos capaces de añadir capacidades de detección de imágenes a Picturesocial sin tener que crear, entrenar o desplegar nuestros propios modelos de Machine Learning, esto por medio de Amazon Rekognition, de forma que convertimos todo ese proceso en un simple llamado a un API.

¿Qué es Amazon Rekognition?

Amazon Rekognition es un servicio de Inteligencia Artificial (IA o AI en inglés) que puede ser usado para permitir a nuestras aplicaciones analizar imágenes por medio de una simple API. No requiere que conozcas de Deep Learning, solo necesitas llamar al API de Amazon Rekognition para recibir información de la imagen analizada.

En Picturesocial, vamos a usar Rekognition para automáticamente etiquetar las imágenes subidas por los usuarios. Para hacer esto, usaremos el API de Rekognition llamada DetectLabels que reciben una imagen como input y devuelven una lista de etiquetas. Una etiqueta puede ser un objeto, escena o concepto. Por ejemplo, la imagen del gatito de arriba podría contener etiquetas como “Gato”, “Laptop”, “Flores” (objetos), “Oficina” (escena) e “Interiores” (concepto)

Yo tengo un S3 Bucket creado previamente que se llama Picturesocial y donde he subido esa misma imagen de Dalí, mi gato, llamada cat.jpg. Lo que haré será armar la estructura del llamado al API de Rekognition especificando la cantidad máxima de etiquetas que devolverá y la confianza mínima de cada etiqueta para que sea incluida en la respuesta. La confianza significa la certeza que tiene Rekognition sobre la identificación de una etiqueta en particular.

Petición de Prueba

{
    "Image": {
        "S3Object": {
            "Bucket": "Picturesocial",
            "Name": "cat.jpg"
        }
    },
    "MaxLabels": 10,
    "MinConfidence": 75
}

Rekognition analizará nuestra imagen y devolverá de respuesta la lista de etiquetas, el nivel de confianza y la ubicación de cada objeto localizado en la imagen.

Respuesta de prueba

{
    "Labels": [
        {
            "Name": "Laptop",
            "Confidence": 99.94806671142578,
            "Instances": [
                {
                    "BoundingBox": {
                        "Width": 0.7708674073219299,
                        "Height": 0.6782196164131165,
                        "Left": 0.21325060725212097,
                        "Top": 0.32108595967292786
                    },
                    "Confidence": 80.35874938964844
                }
            ]
        },
        {
            "Name": "Cat",
            "Confidence": 92.20580291748047,
            "Instances": [
                {
                    "BoundingBox": {
                        "Width": 0.8352921605110168,
                        "Height": 0.5242066979408264,
                        "Left": 0,
                        "Top": 0.4561519920825958
                    },
                    "Confidence": 92.20580291748047
                }
            ]
        }
    ]
}

La imagen a continuación es la interpretación de los resultados de la respuesta. Rekognition fue capaz de identificar una laptop y un gato dentro de las áreas señaladas.

En este episodio, vamos a desarrollar un API que detectará las etiquetas de las imágenes subidas por los usuarios de Picturesocial, almacenadas en un Amazon S3 Bucket. Este API será creado usando .NET 6 y el Web API Template. Además, vamos a tener un método que reciba 2 parámetros: 1/ El nombre del archivo y 2/ el nombre del Bucket, sin embargo, vamos a implementar el API para solo recibir el nombre del archivo y establecer el nombre del Bucket a uno por defecto.

Pre-requisitos

O

  • Si esta es tu primera vez trabajando con AWS CLI o necesitas un refresh de como setear tus credenciales en el terminal te sugiero seguir este paso a paso: https://aws.amazon.com/es/getting-started/guides/setup-environment/. Si no quieres instalar todo desde cero, en este mismo link podrás seguir los pasos para configurar Amazon Cloud9 que es un entorno de desarrollo virtual, que incluye casi todo el toolset que necesitas para este paso a paso.

Paso a Paso

  • Primero vamos a crear la Web API usando .NET CLI. El nombre del API lo especificamos usando el parámetro -n, en nuestro caso, el API se llamará “pictures”

dotnet new webapi -n pictures

  • El paso anterior debió crear un directorio Pictures con toda la estructura del proyecto. Abrimos el proyecto recién creado usando VS Code. Usaremos el siguiente comando en la terminal, esta es una forma cool de hacerlo pero puedes simplemente abrir el folder en VS Code y será lo mismo :)

code pictures/

  • Si miramos la estructura del proyecto nos daremos cuenta que se ha creado un Controller por defecto llamado “WeatherForecastController.cs”, así mismo la clase “WeatherForecast.cs

  • Vamos a renombrar el archivo del Controller como “PictureController.cs” y vamos a eliminar la clase “WeatherForecast.cs
  • Añadimos los paquetes que vamos a usar para este proyecto, en el mismo terminal que usamos para crear el Web API, vamos a ir al directorio “pictures”

cd pictures

  • Y usando el .NET CLI añadiremos los siguientes paquetes dentro de nuestro proyecto.

dotnet add package AWSSDK.Rekognition
dotnet add package AWSSDK.SecurityToken
dotnet add package AWSSDK.Core

  • Volvemos a VS Code y dentro del directorio pictures vamos a crear la clase Labels.cs, esta clase será para reconstruir la respuesta de Rekognition y devolver los datos en formato de Lista.
namespace pictures
{
    public class Labels
    {
        public string Name { get; set; } = default!;
        public float Probability { get; set; }
    }
}
  • Abrimos PictureController.cs y añadimos las referencias a los paquetes al inicio del archivo. De esta forma podemos usar los paquetes de AWS dentro de nuestra API.

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon.Rekognition;
using Amazon.Rekognition.Model;

  • Creamos la ruta para nuestro API Controller, de esta forma podremos llamar al API en este formato: http://url/api/pictures/

namespace pictures.Controllers;
[ApiController]
[Route("api/[controller]")]

  • Cambiamos el nombre del Controller para que se vea exactamente así:

public class PictureController : ControllerBase

  • Y definimos el método “DetectLabels” que usará HTTP Get en el path «/» y recibiendo un parámetro llamado «photo». Estamos configurando el parámetro bucket establecido por defecto debido a que solo usaremos un Amazon S3 Bucket por ahora. Adicionalmente, estamos definiendo el método como «async» o asíncrono debido a que Rekognition detectaré las etiquetas de forma asíncrona. Retornaremos la respuesta como una lista JSON de Labels por medio del tipo «IEnumerable<Labels>«.
  • En este punto deberías crear un Amazon S3 Bucket en la misma región que estás usando para Amazon Rekognition, en nuestro caso usaremos us-east-1

[HttpGet("{photo}")]
public async Task<IEnumerable<Labels>> DetectLabels(string photo, string? bucket = "REPLACE-WITH-YOUR-BUCKET-NAME")
{

  • Inicializamos el cliente de Amazon Rekognition y establecemos el endpoint a nuestra región us-east-1, de la misma forma declaramos e inicializamos nuestra lista de objetos de la clase Labelsque creamos previamente.

var rekognitionClient = new AmazonRekognitionClient(Amazon.RegionEndpoint.USEast1);
var responseList = new List<Labels>();

  • Vamos a preparar el payload para que Rekognition detecte las etiquetas especificando que solo necesitamos 10 etiquetas (MaxLabels) y solo aquellas que tengan un mínimo de 80% de confianza (MinConfidence)
DetectLabelsRequest detectlabelsRequest = new DetectLabelsRequest()
{
    Image = new Image()
    {
        S3Object = new S3Object()
        {
            Name = photo,
            Bucket = bucket
        },
    },
    MaxLabels = 10,
    MinConfidence = 80F
};
  • Finalmente, configuraremos que la petición se envíe de forma asíncrona y vamos iterando por cada etiqueta, almacenándoles en la lista responseList que creamos previamente para luego terminar el método retornando la lista.

var detectLabelsResponse = await rekognitionClient.DetectLabelsAsync(detectlabelsRequest);
foreach (Label label in detectLabelsResponse.Labels)
    responseList.Add(new Labels{
        Name = label.Name,
        Probability = label.Confidence
    });
return responseList;

  • El Controller final de csdebería quedar así:

using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Amazon.Rekognition;
using Amazon.Rekognition.Model;

namespace pictures.Controllers;

[ApiController]
[Route("api/[controller]")]
public class PictureController : ControllerBase
{
    [HttpGet("{photo}")]
    public async Task<IEnumerable<Labels>> DetectLabels(string photo, string? bucket = "")
    {
        var rekognitionClient = new AmazonRekognitionClient(Amazon.RegionEndpoint.USEast1);
        var responseList = new List<Labels>();

        DetectLabelsRequest detectlabelsRequest = new DetectLabelsRequest()
        {
            Image = new Image()
            {
                S3Object = new S3Object()
                {
                    Name = photo,
                    Bucket = bucket
                },
            },
            MaxLabels = 10,
            MinConfidence = 80F
        };
            
        var detectLabelsResponse = await rekognitionClient.DetectLabelsAsync(detectlabelsRequest);
        foreach (Label label in detectLabelsResponse.Labels)
            responseList.Add(new Labels{
                Name = label.Name,
                Probability = label.Confidence
            });
        return responseList;
    }
}

  • Editamos el archivo launchSettings.json que se encuentra dentro del directorio Properties y reemplazamos su contenido por lo siguiente. Acá lo único que estamos haciendo es indicar que utilice el puerto 5075 y bajo HTTP exclusivamente.

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:40317",
      "sslPort": 44344
    }
  },
  "profiles": {
    "pictures": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5075",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

  • Guardamos todo y probamos el API ejecutando en el terminal el siguiente comando:

dotnet run

  • Deberías obtener algo similar a este output, junto con la que será la URL local del servicio.

info: Microsoft.Hosting.Lifetime[0]
Building...
info: Microsoft.Hosting.Lifetime[14]
Now listening on: http://localhost:5075
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development

  • Subamos una foto a nuestro S3 Bucket para probar. En mi caso he subido 2, una de mi gato llamada 1634160049537.jpg y otra wendy.jpg del diseño de un álbum de música.

  • Voy a construir la URL de consulta usando la imagen 1634160049537.jpg y pegar todo en el navegador.

http://localhost:5075/api/pictures/1634160049537.jpg

  • El resultado debería verse similar a este. Como puedes ver, hemos reestructurado la respuesta para que utilice el formato que necesitamos para Picturesocial.

{
"name": "Furniture",
"probability": 99.809166
},
{
"name": "Cat",
"probability": 99.543724
},
{
"name": "Computer Keyboard",
"probability": 99.439415
},
{
"name": "Computer",
"probability": 99.439415
},
{
"name": "Electronics",
"probability": 99.439415
},
{
"name": "Table",
"probability": 98.87616
},
{
"name": "Glasses",
"probability": 98.35254
},
{
"name": "Desk",
"probability": 98.324265
},
{
"name": "Pc",
"probability": 90.02448
},
{
"name": "Monitor",
"probability": 90.019455
}

  • ¡Y eso es todo lo que necesitamos para tener el servicio de auto-hashtag listo para nuestra red social! Si quieres clonar todo el proyecto en vez de construirlo de cero también puedes clonar el repositorio usando la branch ep5:

git clone https://github.com/aws-samples/picture-social-sample/ -b ep5

Si llegaste hasta acá significa que ahora estás usando servicios de IA en AWS. En el siguiente episodio aprenderemos sobre la integración de servicios y acceso a nivel de Pods usando Kubernetes y Amazon Identity and Access Management con OpenID Connect y vamos a desplegar esta API a Kubernetes. No olvides revisar el video y nos leemos en el siguiente episodio.


Sobre el autor

José Yapur es Senior Developer Advocate en AWS con experiencia en Arquitectura de Software y pasión por el desarrollo especialmente en .NET y PHP. Trabajó como Arquitecto de Soluciones por varios años, ayudando a empresas y personas en LATAM.

 

 

 

Ana Cunha es Developer Advocate para AWS en América Latina.