Tutorial: Utilizar Visión de Azure AI para generar metadatos de imágenes en Azure Storage

En este tutorial, aprenderá a integrar el servicio Visión de Azure AI en una aplicación web para generar metadatos para las imágenes cargadas. Esto resulta útil para los escenarios de administración de activos digitales (DAM); por ejemplo, si una empresa quiere generar rápidamente leyendas descriptivas o palabras clave de búsqueda para todas sus imágenes.

Usará Visual Studio para escribir una aplicación web MVC que acepte imágenes cargadas por los usuarios y las almacene en Azure Blob Storage. Aprenderá a leer y escribir blobs en C# y a usar los metadatos del blob para adjuntar información adicional a los blobs que cree. A continuación, enviará cada imagen subida por el usuario a la API de Visión de Azure AI para generar un pie de foto y metadatos de búsqueda para la imagen. Por último, puede implementar la aplicación en la nube mediante Visual Studio.

En este tutorial se muestra cómo realizar las siguientes acciones:

  • Crear una cuenta de almacenamiento y contenedores de almacenamiento mediante Azure Portal
  • Crear una aplicación web en Visual Studio e implementarla en Azure
  • Utilizar la API de Visión AI de Azure para extraer información de las imágenes
  • Adjuntar metadatos a imágenes de Azure Storage
  • Comprobar los metadatos de las imágenes con el Explorador de Azure Storage

Sugerencia

La sección Utilizar Visión de Azure AI para generar metadatos es más relevante para el Análisis de Imágenes. Vaya a dicha sección si solo desea ver cómo se integra el análisis de imágenes en una aplicación establecida.

Si no tiene una suscripción a Azure, cree una cuenta gratuita antes de empezar.

Prerrequisitos

Crear una cuenta de almacenamiento

En esta sección, utilizará Azure Portal para crear una cuenta de almacenamiento. A continuación, creará un par de contenedores: uno para almacenar las imágenes cargadas por el usuario y otro para almacenar las miniaturas de imagen generadas a partir de las imágenes cargadas.

  1. En el explorador, inicie sesión en Azure Portal. Si se le pide que inicie sesión, hágalo con su cuenta Microsoft.

  2. Para crear una cuenta de almacenamiento, seleccione + Crear un recurso en la cinta de la izquierda. A continuación, seleccione Almacenamiento, seguido de Cuenta de almacenamiento.

    Creating a storage account

  3. Escriba un nombre único para la cuenta de almacenamiento en el campo Nombre y asegúrese de que se muestre una marca de verificación verde junto a él. El nombre es importante, ya que forma una parte de la dirección URL mediante la cual se accede a los blobs creados en esta cuenta. Coloque la cuenta de almacenamiento en un nuevo grupo de recursos llamado "IntellipixResources" y seleccione la región más cercana. Finalice seleccionando el botón Revisar + crear en la parte inferior de la pantalla para crear la nueva cuenta de almacenamiento.

    Nota

    Los nombres de las cuentas de almacenamiento pueden tener entre 3 y 24 caracteres y solo pueden incluir números y letras en minúscula. Además, el nombre que escriba debe ser único en Azure. Si alguien ha elegido el mismo nombre, se le notificará que el nombre no está disponible con un signo de exclamación rojo en el campo Nombre.

    Specifying parameters for a new storage account

  4. Seleccione Grupos de recursos en la cinta de la izquierda. A continuación, seleccione el grupo de recursos "IntellipixResources".

    Opening the resource group

  5. En la pestaña que se abre para el grupo de recursos, seleccione la cuenta de almacenamiento que ha creado. Si la cuenta de almacenamiento aún no está ahí, puede seleccionar Actualizar en la parte superior de la pestaña hasta que aparezca.

    Opening the new storage account

  6. En la pestaña de la cuenta de almacenamiento, seleccione Blobs para ver una lista de los contenedores asociados a esta cuenta.

    Viewing blobs button

  7. Actualmente, la cuenta de almacenamiento no tiene contenedores. Antes de poder crear un blob, debe crear un contenedor para almacenarlo. Seleccione + Contenedor para crear un nuevo contenedor. Escriba photos en el campo Nombre y seleccione Blob en el campo Nivel de acceso público. A continuación, seleccione Aceptar para crear un contenedor llamado "fotos".

    De manera predeterminada, los contenedores y su contenido son privados. Al seleccionar Blob como nivel de acceso, los blobs del contenedor "photos" son accesibles públicamente, pero no hacen que el propio contenedor sea público. Esto es lo que quiere, porque las imágenes almacenadas en el contenedor "photos" se vincularán desde una aplicación web.

    Creating a

  8. Repita el paso anterior para crear un contenedor llamado "thumbnails". Una vez más, asegúrese de que el campo Nivel de acceso público del contenedor esté establecido en Blob.

  9. Confirme que ambos contenedores se muestren en la lista de contenedores de esta cuenta de almacenamiento y que los nombres estén escritos correctamente.

    The new containers

  10. Cierre la pantalla "Blob service". Seleccione Teclas de acceso en el menú situado a la izquierda de la pantalla de la cuenta de almacenamiento y, a continuación, seleccione el botón Copiar situado junto a Tecla para Tecla1. Pegue esta clave de acceso en su editor de texto favorito para su uso posterior.

    Copying the access key

Ahora ha creado una cuenta de almacenamiento para almacenar las imágenes cargadas en la aplicación que va a crear y contenedores en los que almacenar las imágenes.

Ejecución del Explorador de Azure Storage

El Explorador de Azure Storage es una herramienta gratuita que proporciona una interfaz gráfica para trabajar con Azure Storage en equipos que ejecutan Windows, macOS y Linux. Proporciona la mayor parte de la misma funcionalidad que Azure Portal y ofrece otras características, como la capacidad de ver los metadatos de los blobs. En esta sección, usará el Explorador de Microsoft Azure Storage para ver los contenedores que ha creado en la sección anterior.

  1. Si no ha instalado el Explorador de Storage o desea asegurarse de que está ejecutando la versión más reciente, vaya a http://storageexplorer.com/, descárguelo e instálelo.

  2. Inicie el Explorador de Storage. Si se le pide que inicie sesión, hágalo con su cuenta Microsoft, la misma que usó para iniciar sesión en Azure Portal. Si no ve la cuenta de almacenamiento en el panel izquierdo del Explorador de almacenamiento, seleccione el botón Administrar cuentas resaltado a continuación y asegúrese de que tanto su cuenta Microsoft como la suscripción utilizada para crear la cuenta de almacenamiento se han agregado al Explorador de Storage.

    Managing accounts in Storage Explorer

  3. Seleccione la flecha pequeña situada junto a la cuenta de almacenamiento para mostrar su contenido y, a continuación, seleccione la flecha situada junto a Blob Containers. Confirme que los contenedores que ha creado se muestren en la lista.

    Viewing blob containers

Los contenedores están vacíos actualmente, pero esto cambiará una vez que se implemente la aplicación y empiece a cargar fotos. Tener el Explorador de Storage instalado le permitirá ver fácilmente lo que la aplicación escribe en Blob Storage.

Creación de una aplicación web en Visual Studio

En esta sección, creará una nueva aplicación web en Visual Studio y agregará código para implementar la funcionalidad básica necesaria para cargar imágenes, escribirlas en Blob Storage y mostrarlas en una página web.

  1. Inicie Visual Studio y use el comando Archivo -> Nuevo -> Proyecto para crear un nuevo proyecto de aplicación web ASP.NET de Visual C# llamado "Intellipix" (abreviatura de "Imágenes inteligentes").

    Creating a new Web Application project

  2. En el cuadro de diálogo "Nueva aplicación web ASP.NET", asegúrese de que esté seleccionado MVC. A continuación, seleccione Aceptar.

    Creating a new ASP.NET MVC project

  3. Tómese un momento para revisar la estructura del proyecto en el Explorador de soluciones. Entre otras cosas, hay una carpeta llamada Controllers (Controladores) que contiene los controladores MVC del proyecto y una carpeta llamada Views (Vistas) que contiene las vistas del proyecto. Trabajará con los recursos de estas carpetas y otras a medida que implemente la aplicación.

    The project shown in Solution Explorer

  4. Use el comando Depurar -> Iniciar sin depurar de Visual Studio (o pulse Ctrl+F5) para iniciar la aplicación en el explorador. Este es el aspecto de la aplicación en su estado actual:

    The initial application

  5. Cierre el explorador y vuelva a Visual Studio. En el Explorador de soluciones, haga clic con el botón derecho en el proyecto Intellipix y seleccione Administrar paquetes NuGet.... Seleccione Buscar. A continuación, escriba imageresizer en el cuadro de búsqueda y seleccione el paquete NuGet llamado ImageResizer. Por último, seleccione Instalar para instalar la última versión estable del paquete. ImageResizer contiene las API que va a utilizar para crear miniaturas de imágenes a partir de las imágenes cargadas en la aplicación. Acepte los cambios y acepte las licencias que se le presenten.

    Installing ImageResizer

  6. Repita este proceso para agregar el paquete NuGet llamado WindowsAzure.Storage al proyecto. Este paquete contiene las API para acceder a Azure Storage desde aplicaciones de .NET. Acepte los cambios y acepte las licencias que se le presenten.

    Installing WindowsAzure.Storage

  7. Abra el archivo Web.config y agregue la siguiente instrucción a la sección <appSettings>, reemplazando ACCOUNT_NAME por el nombre de la cuenta de almacenamiento que creó en la primera sección y ACCOUNT_KEY por la clave de acceso que guardó.

    <add key="StorageConnectionString" value="DefaultEndpointsProtocol=https;AccountName=ACCOUNT_NAME;AccountKey=ACCOUNT_KEY" />
    

    Importante

    El archivo Web.config está diseñado para contener información confidencial, como las claves de suscripción, y cualquier solicitud HTTP a un archivo con la extensión .config se controla mediante el motor de ASP.NET, que devuelve un mensaje que indica que "Este tipo de página no se proporciona". Sin embargo, si un atacante puede encontrar otra vulnerabilidad de seguridad que le permita ver el contenido del archivo Web.config, podrá exponer esa información. Consulte Protección de cadenas de conexión y otra información de configuración para conocer los pasos adicionales que puede seguir para proteger aún más los datos de Web.config.

  8. Abra el archivo llamado _Layout.cshtml en la carpeta Views/Shared del proyecto. En la línea 19, cambie "Nombre de la aplicación" a "Intellipix". La línea debe tener este aspecto:

    @Html.ActionLink("Intellipix", "Index", "Home", new { area = "" }, new { @class = "navbar-brand" })
    

    Nota

    En un proyecto MVC de ASP.NET, el archivo _Layout.cshtml es una vista especial que actúa como plantilla para otras vistas. Normalmente, en este archivo se define el contenido del encabezado y el pie de página que es común a todas las vistas.

  9. Haga clic con el botón derecho en la carpeta Models del proyecto y use el comando Agregar -> Clase... para agregar un archivo de clase llamado BlobInfo.cs a la carpeta. A continuación, reemplace la clase vacía BlobInfo por la siguiente definición de clase:

    public class BlobInfo
    {
        public string ImageUri { get; set; }
        public string ThumbnailUri { get; set; }
        public string Caption { get; set; }
    }
    
  10. Abra el archivo HomeController.cs, que encontrará en la carpeta Controllers (Controladores) del proyecto, y agregue las siguientes instrucciones using al principio del mismo:

    using ImageResizer;
    using Intellipix.Models;
    using Microsoft.WindowsAzure.Storage;
    using Microsoft.WindowsAzure.Storage.Blob;
    using System.Configuration;
    using System.Threading.Tasks;
    using System.IO;
    
  11. Reemplace el método Index del archivo HomeController.cs por la siguiente implementación:

    public ActionResult Index()
    {
        // Pass a list of blob URIs in ViewBag
        CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
        CloudBlobClient client = account.CreateCloudBlobClient();
        CloudBlobContainer container = client.GetContainerReference("photos");
        List<BlobInfo> blobs = new List<BlobInfo>();
    
        foreach (IListBlobItem item in container.ListBlobs())
        {
            var blob = item as CloudBlockBlob;
    
            if (blob != null)
            {
                blobs.Add(new BlobInfo()
                {
                    ImageUri = blob.Uri.ToString(),
                    ThumbnailUri = blob.Uri.ToString().Replace("/photos/", "/thumbnails/")
                });
            }
        }
    
        ViewBag.Blobs = blobs.ToArray();
        return View();
    }
    

    El nuevo método Index enumera los blobs del contenedor "photos" y pasa una matriz de objetos BlobInfo que representan esos blobs en la vista mediante la propiedad ViewBag de MVC de ASP.NET. Más adelante, modificará la vista para enumerar estos objetos y mostrar una colección de miniaturas de fotos. Las clases que usará para acceder a la cuenta de almacenamiento y enumerar los blobs (CloudStorageAccount, CloudBlobClient y CloudBlobContainer) proceden del paquete WindowsAzure.Storage que instaló mediante NuGet.

  12. Agregue el método siguiente a la clase HomeController en el archivo HomeController.cs:

    [HttpPost]
    public async Task<ActionResult> Upload(HttpPostedFileBase file)
    {
        if (file != null && file.ContentLength > 0)
        {
            // Make sure the user selected an image file
            if (!file.ContentType.StartsWith("image"))
            {
                TempData["Message"] = "Only image files may be uploaded";
            }
            else
            {
                try
                {
                    // Save the original image in the "photos" container
                    CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
                    CloudBlobClient client = account.CreateCloudBlobClient();
                    CloudBlobContainer container = client.GetContainerReference("photos");
                    CloudBlockBlob photo = container.GetBlockBlobReference(Path.GetFileName(file.FileName));
                    await photo.UploadFromStreamAsync(file.InputStream);
    
                    // Generate a thumbnail and save it in the "thumbnails" container
                    using (var outputStream = new MemoryStream())
                    {
                        file.InputStream.Seek(0L, SeekOrigin.Begin);
                        var settings = new ResizeSettings { MaxWidth = 192 };
                        ImageBuilder.Current.Build(file.InputStream, outputStream, settings);
                        outputStream.Seek(0L, SeekOrigin.Begin);
                        container = client.GetContainerReference("thumbnails");
                        CloudBlockBlob thumbnail = container.GetBlockBlobReference(Path.GetFileName(file.FileName));
                        await thumbnail.UploadFromStreamAsync(outputStream);
                    }
                }
                catch (Exception ex)
                {
                    // In case something goes wrong
                    TempData["Message"] = ex.Message;
                }
            }
        }
    
        return RedirectToAction("Index");
    }
    

    Este es el método al que se llama al cargar una foto. Almacena cada imagen cargada como un blob en el contenedor "photos", crea una imagen en miniatura a partir de la imagen original mediante el paquete ImageResizer y almacena la imagen en miniatura como un blob en el contenedor "thumbnails".

  13. Abra el archivo Index.cshmtl de la carpeta Views/Home del proyecto y reemplace su contenido por el código y marcado siguientes:

    @{
        ViewBag.Title = "Intellipix Home Page";
    }
    
    @using Intellipix.Models
    
    <div class="container" style="padding-top: 24px">
        <div class="row">
            <div class="col-sm-8">
                @using (Html.BeginForm("Upload", "Home", FormMethod.Post, new { enctype = "multipart/form-data" }))
                {
                    <input type="file" name="file" id="upload" style="display: none" onchange="$('#submit').click();" />
                    <input type="button" value="Upload a Photo" class="btn btn-primary btn-lg" onclick="$('#upload').click();" />
                    <input type="submit" id="submit" style="display: none" />
                }
            </div>
            <div class="col-sm-4 pull-right">
            </div>
        </div>
    
        <hr />
    
        <div class="row">
            <div class="col-sm-12">
                @foreach (BlobInfo blob in ViewBag.Blobs)
                {
                    <img src="@blob.ThumbnailUri" width="192" title="@blob.Caption" style="padding-right: 16px; padding-bottom: 16px" />
                }
            </div>
        </div>
    </div>
    
    @section scripts
    {
        <script type="text/javascript" language="javascript">
            if ("@TempData["Message"]" !== "") {
                alert("@TempData["Message"]");
            }
        </script>
    }
    

    El lenguaje que se usa aquí es Razor, que permite insertar código ejecutable en el marcado HTML. La instrucción @foreach hacia la mitad del archivo enumera los objetos BlobInfo pasados desde el controlador en ViewBag y crea elementos <img> de HTML a partir de ellos. La propiedad src de cada elemento se inicializa con el identificador URI del blob que contiene la miniatura de la imagen.

  14. Descargue y descomprima el archivo photos.zip del repositorio de datos de ejemplo de GitHub. Se trata de una variedad de fotos diferentes que puede usar para probar la aplicación.

  15. Guarde los cambios y pulse Ctrl+F5 para iniciar la aplicación en el explorador. A continuación, seleccione Cargar una foto y cargue una de las imágenes que ha descargado. Confirme que se muestre una versión en miniatura de la foto en la página.

    Intellipix with one photo uploaded

  16. Upload algunas imágenes más de la carpeta photos. Confirme que también aparecen en la página:

    Intellipix with three photos uploaded

  17. Haga clic con el botón derecho en el explorador y seleccione Ver código fuente de la página para ver el código fuente de la página. Busque los elementos <img> que representan las miniaturas de las imágenes. Observe que las direcciones URL asignadas a las imágenes hacen referencia directamente a los blobs de Blob Storage. Esto se debe a que ha establecido el Nivel de acceso público de los contenedores en Blob, lo que hace que se pueda acceder públicamente a los blobs que se encuentran dentro.

  18. Vuelva al Explorador de Azure Storage (o reinícielo si no lo dejó en ejecución) y seleccione el contenedor "photos" en la cuenta de almacenamiento. El número de blobs del contenedor debe ser igual al número de fotos que ha cargado. Haga doble clic en uno de los blobs para descargarlo y ver la imagen almacenada en el blob.

    Contents of the

  19. Abra el contenedor "thumbnails" en el Explorador de Storage. Abra uno de los blobs para ver las imágenes en miniatura generadas a partir de las cargas de imágenes.

La aplicación aún no ofrece una manera de ver las imágenes originales que ha cargado. Lo ideal es que al seleccionar una miniatura de imagen se muestre la imagen original. Agregará esa característica a continuación.

Adición de un elemento lightbox para ver fotos

En esta sección, usará una biblioteca gratuita de JavaScript de código abierto para agregar un visor lightbox que permita a los usuarios ver las imágenes originales que han cargado (en lugar de solo las miniaturas de imagen). Se le proporcionan los archivos. Todo lo que tiene que hacer es integrarlos en el proyecto y realizar una pequeña modificación en el archivo Index.cshtml.

  1. Descargue los archivos lightbox.css y lightbox.js desde el repositorio de código de GitHub.

  2. En el Explorador de soluciones, haga clic con el botón derecho en la carpeta Scripts del proyecto y use el comando Agregar -> Nuevo elemento... para crear el archivo lightbox.js. Pegue el contenido del archivo de ejemplo del repositorio de código de GitHub.

  3. Haga clic con el botón derecho en la carpeta "Content" (Contenido) del proyecto y use el comando Agregar -> Nuevo elemento... para crear el archivo lightbox.css. Pegue el contenido del archivo de ejemplo del repositorio de código de GitHub.

  4. Descargue y descomprima el archivo buttons.zip del repositorio de archivos de datos de GitHub: https://github.com/Azure-Samples/cognitive-services-sample-data-files/tree/master/ComputerVision/storage-lab-tutorial. Debe tener cuatro imágenes de botón.

  5. Haga clic con el botón derecho en el proyecto Intellipix en el Explorador de soluciones y use el comando Agregar -> Nueva carpeta para agregar una carpeta llamada "Images" (Imágenes) al proyecto.

  6. Haga clic con el botón derecho en la carpeta Images y use el comando Agregar -> Elemento existente... para importar las cuatro imágenes que descargó.

  7. Abra el archivo BundleConfig.cs de la carpeta "App_Start" del proyecto. Agregue la siguiente instrucción al método RegisterBundles en el archivo BundleConfig.cs:

    bundles.Add(new ScriptBundle("~/bundles/lightbox").Include(
              "~/Scripts/lightbox.js"));
    
  8. En el mismo método, busque la instrucción que crea un elemento StyleBundle a partir de "~/Content/css" y agregue lightbox.css a la lista de hojas de estilos de la agrupación. Esta es la instrucción modificada:

    bundles.Add(new StyleBundle("~/Content/css").Include(
              "~/Content/bootstrap.css",
              "~/Content/site.css",
              "~/Content/lightbox.css"));
    
  9. Abra el archivo _Layout.cshtml de la carpeta Views/Shared del proyecto y agregue la siguiente instrucción justo antes de la instrucción @RenderSection cerca de la parte inferior:

    @Scripts.Render("~/bundles/lightbox")
    
  10. La tarea final consiste en incorporar el visor lightbox en la página principal. Para ello, abra el archivo Index.cshtml (se encuentra en la carpeta Views/Home del proyecto) y reemplace el bucle @foreach por este:

    @foreach (BlobInfo blob in ViewBag.Blobs)
    {
        <a href="@blob.ImageUri" rel="lightbox" title="@blob.Caption">
            <img src="@blob.ThumbnailUri" width="192" title="@blob.Caption" style="padding-right: 16px; padding-bottom: 16px" />
        </a>
    }
    
  11. Guarde los cambios y pulse Ctrl+F5 para iniciar la aplicación en el explorador. A continuación, seleccione una de las imágenes que ha cargado anteriormente. Confirme que aparece un visor lightbox y que muestre una vista ampliada de la imagen.

    An enlarged image

  12. Seleccione X en la esquina inferior derecha de la caja de luz para cerrarla.

Ahora tiene una manera de ver las imágenes que ha cargado. El siguiente paso es hacer más cosas con esas imágenes.

Utilizar Visión de Azure AI para generar metadatos

Crear un recurso de Visión

Deberá crear un recurso de Computer Vision para su cuenta de Azure; este recurso administra el acceso al servicio Visión de Azure AI.

  1. Siga las instrucciones de Crear un recurso de servicios Azure AI para crear un recurso multiservicio o un recurso de Visión.

  2. A continuación, vaya al menú de su grupo de recursos y seleccione el recurso de Visión que ha creado. Copie la dirección URL de Punto de conexión a cualquier lugar en que pueda recuperarla fácilmente en un momento. Luego, seleccione Mostrar claves de acceso.

    Azure portal page with the endpoint URL and access keys link outlined

    Nota:

    Los nuevos recursos creados después del 1 de julio de 2019 usarán nombres de subdominio personalizados. Para obtener más información y una lista completa de puntos de conexión regionales, consulte Nombres de subdominios personalizados para los servicios de Azure AI.

  3. En la ventana siguiente, copie el valor de KEY 1 en el Portapapeles.

    Manage keys dialog, with the copy button outlined

Agregar credenciales de Visión de Azure AI

A continuación, agregará las credenciales necesarias a su aplicación para que pueda acceder a los recursos de Vision.

Vaya al archivo Web.config en la raíz del proyecto. Agregue las siguientes instrucciones a la sección <appSettings> del archivo, pero reemplace VISION_KEY por la clave que copió en el paso anterior y VISION_ENDPOINT por la dirección URL que guardó en el paso anterior.

<add key="SubscriptionKey" value="VISION_KEY" />
<add key="VisionEndpoint" value="VISION_ENDPOINT" />

En el Explorador de soluciones. Haga clic con el botón derecho en la solución de proyecto y seleccione Administrar paquetes NuGet. En el administrador de paquetes que se abre, seleccione Examinar, active Incluir versión preliminary busque Azure.AI.Vision.ImageAnalysis. Seleccione Instalar.

Incorporación del código de generación de metadatos

A continuación, agregará el código que realmente utiliza el servicio de Visión de Azure AI para crear metadatos para las imágenes.

  1. Abra el archivo HomeController.cs, que encontrará en la carpeta Controllers del proyecto, y agregue las siguientes using instrucciones al principio del mismo:

    using Azure;
    using Azure.AI.Vision.ImageAnalysis;
    using System;
    
  2. A continuación, vaya al método Upload; este método convierte y carga imágenes en Blob Storage. Agregue el código siguiente inmediatamente después del bloque que comienza por // Generate a thumbnail (o al final del proceso de creación de blobs de imágenes). Este código toma el blob que contiene la imagen (photo) y utiliza Azure AI Vision para generar una descripción para esa imagen. La API de Azure AI Vision también genera una lista de palabras clave que se aplican a la imagen. Tanto la descripción como las palabras clave generadas se almacenan en los metadatos del blob para que se pueden recuperar más adelante.

    // create a new ImageAnalysisClient
    ImageAnalysisClient client = new ImageAnalysisClient(
            new Uri(Environment.GetEnvironmentVariable(ConfigurationManager.AppSettings["VisionEndpoint"])),
            new AzureKeyCredential(ConfigurationManager.AppSettings["SubscriptionKey"]));
    
    VisualFeatures = visualFeatures = VisualFeatures.Caption | VisualFeatures.Tags;
    
    ImageAnalysisOptions analysisOptions = new ImageAnalysisOptions()
    {
        GenderNeutralCaption = true,
        Language = "en",
    };
    
    Uri imageURL = new Uri(photo.Uri.ToString());
    
    ImageAnalysisResult  result = client.Analyze(imageURL,visualFeatures,analysisOptions);
    
    // Record the image description and tags in blob metadata
    photo.Metadata.Add("Caption", result.Caption.Text);
    
    for (int i = 0; i < result.Tags.Values.Count; i++)
    {
        string key = String.Format("Tag{0}", i);
        photo.Metadata.Add(key, result.Tags.Values[i]);
    }
    
    await photo.SetMetadataAsync();
    
  3. A continuación, vaya al método Index en el mismo archivo. Este método enumera los blobs de imágenes almacenados en el contenedor de blobs de destino (como instancias de IListBlobItem) y los pasa a la vista de aplicación. Reemplace el bloque foreach de este método por el siguiente código. Este código llama a CloudBlockBlob.FetchAttributes para obtener los metadatos adjuntos de cada blob. Extrae la descripción generada por el equipo (caption) de los metadatos y la agrega al objeto BlobInfo, que se pasa a la vista.

    foreach (IListBlobItem item in container.ListBlobs())
    {
        var blob = item as CloudBlockBlob;
    
        if (blob != null)
        {
            blob.FetchAttributes(); // Get blob metadata
            var caption = blob.Metadata.ContainsKey("Caption") ? blob.Metadata["Caption"] : blob.Name;
    
            blobs.Add(new BlobInfo()
            {
                ImageUri = blob.Uri.ToString(),
                ThumbnailUri = blob.Uri.ToString().Replace("/photos/", "/thumbnails/"),
                Caption = caption
            });
        }
    }
    

Prueba de la aplicación

Guarde los cambios en Visual Studio y presione Ctrl+F5 para iniciar la aplicación en el explorador. Use la aplicación para cargar algunas imágenes más, ya sea desde el conjunto de fotos que descargó o desde su propia carpeta. Cuando mueva el puntero sobre una de las nuevas imágenes de la vista, debería aparecer una ventana de información sobre herramientas y mostrar el título de la imagen generado automáticamente.

The computer-generated caption

Para ver todos los metadatos adjuntos, use el Explorador de Azure Storage para ver el contenedor de almacenamiento que usa para las imágenes. Haga clic con el botón derecho en cualquiera de los blobs del mismo y seleccione Propiedades. En el cuadro de diálogo, verá una lista de pares clave-valor. La descripción de la imagen generada automáticamente se almacena en el elemento Caption y las palabras clave de búsqueda se almacenan en Tag0, Tag1, etc. Cuando haya terminado, seleccione Cancelar para cerrar el cuadro de diálogo.

Image properties dialog window, with metadata tags listed

Adición de un cuadro de búsqueda a la aplicación

En esta sección, agregará un cuadro de búsqueda a la página principal, lo que permite a los usuarios realizar búsquedas de palabras clave en las imágenes que han cargado. Las palabras clave son las generadas por la API de Visión de Azure AI y almacenadas en los metadatos blob.

  1. Abra el archivo Index.cshtml en la carpeta Views/Home del proyecto y agregue las siguientes instrucciones al elemento <div> vacío con el atributo class="col-sm-4 pull-right":

    @using (Html.BeginForm("Search", "Home", FormMethod.Post, new { enctype = "multipart/form-data", @class = "navbar-form" }))
    {
        <div class="input-group">
            <input type="text" class="form-control" placeholder="Search photos" name="term" value="@ViewBag.Search" style="max-width: 800px">
            <span class="input-group-btn">
                <button class="btn btn-primary" type="submit">
                    <i class="glyphicon glyphicon-search"></i>
                </button>
            </span>
        </div>
    }
    

    Este código y marcado agregan un cuadro de búsqueda y un botón Search (Buscar) a la página principal.

  2. Abra el archivo HomeController.cs, que encontrará en la carpeta Controllers (Controladores) del proyecto, y agregue el siguiente método a la clase HomeController:

    [HttpPost]
    public ActionResult Search(string term)
    {
        return RedirectToAction("Index", new { id = term });
    }
    

    Este es el método que se llama cuando el usuario selecciona el botón Buscar agregado en el paso anterior. Actualiza la página e incluye un parámetro de búsqueda en la dirección URL.

  3. Reemplace el método Index por la siguiente implementación:

    public ActionResult Index(string id)
    {
        // Pass a list of blob URIs and captions in ViewBag
        CloudStorageAccount account = CloudStorageAccount.Parse(ConfigurationManager.AppSettings["StorageConnectionString"]);
        CloudBlobClient client = account.CreateCloudBlobClient();
        CloudBlobContainer container = client.GetContainerReference("photos");
        List<BlobInfo> blobs = new List<BlobInfo>();
    
        foreach (IListBlobItem item in container.ListBlobs())
        {
            var blob = item as CloudBlockBlob;
    
            if (blob != null)
            {
                blob.FetchAttributes(); // Get blob metadata
    
                if (String.IsNullOrEmpty(id) || HasMatchingMetadata(blob, id))
                {
                    var caption = blob.Metadata.ContainsKey("Caption") ? blob.Metadata["Caption"] : blob.Name;
    
                    blobs.Add(new BlobInfo()
                    {
                        ImageUri = blob.Uri.ToString(),
                        ThumbnailUri = blob.Uri.ToString().Replace("/photos/", "/thumbnails/"),
                        Caption = caption
                    });
                }
            }
        }
    
        ViewBag.Blobs = blobs.ToArray();
        ViewBag.Search = id; // Prevent search box from losing its content
        return View();
    }
    

    Observe que el método Index ahora acepta el parámetro id, que contiene el valor que el usuario ha especificado en el cuadro de búsqueda. Un parámetro id vacío o que falta indica que se deben mostrar todas las fotos.

  4. Agregue el método auxiliar siguiente a la clase HomeController:

    private bool HasMatchingMetadata(CloudBlockBlob blob, string term)
    {
        foreach (var item in blob.Metadata)
        {
            if (item.Key.StartsWith("Tag") && item.Value.Equals(term, StringComparison.InvariantCultureIgnoreCase))
                return true;
        }
    
        return false;
    }
    

    El método Index llama a este método para determinar si las palabras clave de metadatos asociadas a un blob de imagen determinado contienen el término de búsqueda especificado por el usuario.

  5. Vuelva a iniciar la aplicación y cargue varias fotos. No dude en usar sus propias fotos, no solo las que se proporcionan con el tutorial.

  6. Escriba una palabra clave como "river" (río) en el cuadro de búsqueda. A continuación, seleccione el botón Buscar.

    Performing a search

  7. Los resultados de la búsqueda variarán en función de lo que haya especificado y de las imágenes que haya cargado. Sin embargo, el resultado debe ser una lista filtrada de imágenes cuyas palabras clave de metadatos incluyan todo o parte de la palabra clave que ha especificado.

    Search results

  8. Seleccione el botón Atrás del navegador para volver a mostrar todas las imágenes.

Casi hemos acabado. Es el momento de implementar la aplicación en la nube.

Implementar la aplicación en Azure

En esta sección, implementará la aplicación en Azure desde Visual Studio. Permitirá que Visual Studio cree una aplicación web de Azure automáticamente, lo que le evitará tener que ir a Azure Portal y crearla por separado.

  1. Haga clic con el botón derecho en el proyecto en el Explorador de soluciones y seleccione Publicar... en el menú contextual. Asegúrese de que Microsoft Azure App Service y Crear nuevo están seleccionados y, a continuación, seleccione el botón Publicar.

    Publishing the app

  2. En el siguiente cuadro de diálogo, seleccione el grupo de recursos "IntellipixResources" en Grupo de recursos. Seleccione el botón Nuevo... situado junto a "Plan de App Service" y cree un nuevo Plan de App Service en la misma ubicación que seleccionó para la cuenta de almacenamiento en Crear una cuenta de almacenamiento, aceptando los valores predeterminados en todos los demás casos. Finalice con el botón Crear.

    Creating an Azure Web App

  3. Transcurridos unos instantes, la aplicación aparecerá en una ventana del explorador. Observe la dirección URL en la barra de direcciones. La aplicación ya no se ejecuta localmente; está en la Web, donde es accesible públicamente.

    The finished product!

Si realiza cambios en la aplicación y desea insertar los cambios en la Web, vuelva a realizar el proceso de publicación. Todavía puede probar los cambios localmente antes de publicar en la Web.

Limpieza de recursos

Si desea seguir trabajando en la aplicación web, consulte la sección Pasos siguientes. Si no planea seguir usando esta aplicación, debe eliminar todos los recursos específicos de la misma. Para eliminar recursos, puede eliminar el grupo de recursos que contiene su suscripción a Azure Storage y el recurso Visión. De esta forma se quita la cuenta de almacenamiento, los blobs que se han cargado en ella y el recurso de App Service necesario para conectarse con la aplicación web ASP.NET.

Para eliminar el grupo de recursos, abra la pestaña Grupos de recursos del portal, vaya al grupo de recursos que utilizó para este proyecto y seleccione Eliminar grupo de recursos en la parte superior de la vista. Se le pedirá que escriba el nombre del grupo de recursos para confirmar que desea eliminarlo. Una vez eliminado, no se puede recuperar un grupo de recursos.

Pasos siguientes

Hay mucho más que puede hacer para usar Azure y desarrollar aún más la aplicación Intellipix. Por ejemplo, puede agregar soporte para autenticar usuarios y eliminar fotos, y en lugar de obligar al usuario a esperar a que los servicios de Azure AI procesen una foto tras una carga, puede usar Azure Functions para llamar a la API Azure AI Vision de forma asíncrona cada vez que se agregue una imagen al almacenamiento blob. También puede realizar cualquier otra operación de análisis de imágenes sobre la imagen, como se describe en la introducción.