A Visão Computacional é a forma como as máquinas podem “enxergar o mundo”. Para tal, é necessário um grande poder computacional para treiná-las, além de um grande e extremamente diversificado acervo de imagens para que as análises sejam mais precisa. Graças ao Serviço Cognitivo da Azure de Visão Computacional, podemos ignorar toda a preocupação e, apenas, implementar um já bem treinado, alimentado e estabelecido serviço de IA que analisa o conteúdo das imagens, que é o que faremos a seguir.
Visão Computacional no Azure
O serviço de Visão Computacional do Azure pode ser usado para analisar imagens e detectar informações interessantes e relevantes, como logos, celebridades, conteúdo adulto e/ou sensível e, até mesmo, obter uma descrição do que há nela, em diversos idiomas.
Neste artigo, o segundo da série, vamos continuar construindo a aplicação que começamos no artigo anterior NÃO reinvente a roda! Serviços cognitivos da Azure: Face. Portanto, confere lá o outro artigo e fique por dentro de tudo que estamos fazendo!
Este artigo terá diversos formulários de envio, tanto de URL quanto de arquivo de imagem, para exibir informações analisadas da imagem pelo Serviço Cognitivo da Azure de Visão Computacional.
Todo o código está disponível no github!
Então, vamos a mão na massa!
1. Tenha seu projeto
Criamos um projeto do tipo ASP.NET Core Web Application, com o template Web Application para ter o projeto criado voltado para o Razor Pages. Demos a ele o nome de AzureCognitiveServices. Confira no primeiro passo do primeiro artigo técnico da série e crie o seu projeto também.
Com o projeto criado e atualizado, veja a Solution Folder com nome de Vision, que é o nome da categoria que estamos explorando agora.
Dentro dessa Solution Folder, crie um novo Projeto do tipo Class Library (.NET Core) e o nomeie como ComputerVision.
Até esse ponto, a estrutura do projeto deve ser a seguinte:
2. Configure a Azure
Crie uma conta gratuita no Azure e, logo após, crie um recurso para utilizar o serviço de visão computacional e obtenha a chave e o endpoint do recurso, como na imagem a seguir.
3. Conecte o Serviço de Visão Computacional ao seu projeto
Voltando ao projeto no VIsual Studio, vamos renomear o arquivo Class1.cs para algo mais palatável. Renomeio para AnaliseDeImagem.cs.
Abra o Package Manager Console e execute o seguinte comando para adicionar as bibliotecas do Serviço Cognitivo de Visão Computacional ao projeto que chamamos de ComputerVision.
dotnet add .ComputerVision package Microsoft.Azure.CognitiveServices.Vision.ComputerVision --version 5.0.0
Não esqueça, também, de conectar o projeto ComputerVision ao projeto AzureCognitiveServices clicando com o botão direito em cima do projeto AzureCognitiveServices e indo a opção Add > Reference…, depois adicionando o projeto ComputerVision. Assim o projeto AzureCognitiveServices conseguirá acessar o projeto ComputerVision e consumir o que precisar.
4. Implemente a Visão Computacional na classe AnaliseDeImagem.cs
Começo colocando todos os Usings necessários para o funcionamento correto da classe:
using Microsoft.Azure.CognitiveServices.Vision.ComputerVision; using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks;
Depois adicione as variáveis de instância que utilizaremos nessa classe:
namespace ComputerVision { public class AnaliseDeImagem { private const string _chave = \"<sua chave>\"; private const string _endpoint = \"<seu endpoint>\"; private IComputerVisionClient _servicoCognitivoDeVisaoComputacional;
Lembre de substituir \"<sua chave>\"
e \"<seu endpoint>\"
pelos valores obtidos no passo 2. Configure o Azure.
A interface IComputerVisionClient
é, justamente, a interface que utilizaremos para chamar os métodos que o Serviço Cognitivo de Visão Computacional nos disponibiliza.
Crie um método construtor para que, sempre que essa classe for instanciada, a variável _servicoCognitivoDeVisaoComputacional
seja instanciada também.
public AnaliseDeImagem() => _servicoCognitivoDeVisaoComputacional = new ComputerVisionClient(new ApiKeyServiceClientCredentials(_chave)) { Endpoint = _endpoint };
Há duas formas de utilizar os serviços de Visão Computacional do Azure, por URL, ou por arquivo. Iremos utilizar ambas as formas. Para isso, crie os métodos abaixo:
public async Task<ImageAnalysis> AnalisarPorUrl(string url) => await _servicoCognitivoDeVisaoComputacional.AnalyzeImageAsync( url, new List<VisualFeatureTypes>() { VisualFeatureTypes.Categories, VisualFeatureTypes.Description, VisualFeatureTypes.Faces, VisualFeatureTypes.ImageType, VisualFeatureTypes.Tags, VisualFeatureTypes.Adult, VisualFeatureTypes.Color, VisualFeatureTypes.Brands }, language: \"pt\"); public async Task<ImageAnalysis> AnalisarPorArquivo(string localDoArquivo) { var arquivo = new FileStream(localDoArquivo, FileMode.Open); return await _servicoCognitivoDeVisaoComputacional.AnalyzeImageInStreamAsync( arquivo, new List<VisualFeatureTypes>() { VisualFeatureTypes.Categories, VisualFeatureTypes.Description, VisualFeatureTypes.Faces, VisualFeatureTypes.ImageType, VisualFeatureTypes.Tags, VisualFeatureTypes.Adult, VisualFeatureTypes.Color, VisualFeatureTypes.Brands }, language: \"pt\"); }
Repare que os métodos são bem similares, a diferença entre eles é que, no primeiro (AnalisarPorUrl()
) o método AnalyzeImageAsync
é chamado, enquanto no outro (AnalisarPorArquivo()
) o método AnalyzeImageInStreamAsync
é chamado. Além disso, no segundo método, há a captura do arquivo enviado ao servidor para enviá-lo ao Serviço.
Note que, em ambos os métodos, há uma extensa lista de VisualFeatureTypes
que são os pontos que serão analisados e, por último, há um parâmetro language:
\”pt\” o qual diz ao serviço que o retorno deve ser no idioma Português.
Há também o tipo de retorno como Task
, pois a biblioteca do serviço utiliza de métodos assíncronos e, como teremos uma grande quantidade de análise para fazer, devolvemos a classe ImageAnalysis
que é uma classe da própria biblioteca que contém o resultado da análise realizada.
Por fim, crie os métodos que interpretam a análise de um ponto específico e não esqueça de fechar todas as chaves da classe:
public string RetornarLegenda(ImageAnalysis analiseRealizada) { if (analiseRealizada.Description.Captions.Count == 0) return \"Não foi possível definir o que há na imagem.\"; var legendas = new List<string>(analiseRealizada.Description.Captions.Count); legendas .AddRange(analiseRealizada .Description .Captions .Select(c => $\"{c.Text} ({c.Confidence * 100:n2}% de certeza)\")); return string.Join(\" - \", legendas); } public string RetornarCategorias(ImageAnalysis analiseRealizada) { if (analiseRealizada.Categories.Count == 0) return \"Não foi possível categorizar a imagem.\"; var categorias = new List<string>(analiseRealizada.Categories.Count); categorias .AddRange(analiseRealizada .Categories .Select(c => $\"{c.Name} ({c.Score * 100:n2}% de certeza)\")); return string.Join(\" - \", categorias); } public string RetornarTags(ImageAnalysis analiseRealizada) { if (analiseRealizada.Tags.Count == 0) return \"Não foi possível tagear a imagem.\"; return analiseRealizada .Tags .Aggregate(string.Empty, (atual, tag) => $\"{atual}{tag.Name} ({tag.Confidence * 100:n2}% de certeza) - \"); } public string RetornarLogos(ImageAnalysis analiseRealizada) { if (analiseRealizada.Brands.Count == 0) return \"Não foi possível identificar logos na imagem.\"; var logos = new List<string>(analiseRealizada.Brands.Count); logos .AddRange(analiseRealizada .Brands .Select(l => $\"{l.Name} ({l.Confidence * 100:n2}% de certeza)\")); return string.Join(\" - \", logos); } public string RetornarRostos(ImageAnalysis analiseRealizada) { if (analiseRealizada.Faces.Count == 0) return \"Não foi possível identificar rostos na imagem.\"; var rostos = new List<string>(analiseRealizada.Faces.Count); rostos .AddRange(analiseRealizada .Faces .Select(f => $\"Possivelmente {(\"female\".Equals(f.Gender.ToString().ToLower()) ? \"mulher\" : \"homem\")} com {f.Age} anos.\")); return string.Join(\" - \", rostos); } public string RetornarConteudoAdultoOuSensivel(ImageAnalysis analiseRealizada) => $\"{(analiseRealizada.Adult.IsAdultContent ? \"Possui\" : \"Não possui\")} conteúdo adulto (score de conteúdo adulto: {analiseRealizada.Adult.AdultScore:n5}). {(analiseRealizada.Adult.IsRacyContent ? \"Possui\" : \"Não possui\")} conteúdo sensível (score de conteúdo sensível: {analiseRealizada.Adult.RacyScore:n5}).\"; public string RetornarEsquemaDeCores(ImageAnalysis analiseRealizada) => $\"A imagem {(analiseRealizada.Color.IsBWImg ? \"é\" : \"não é\")} em preto e branco e as cores dominantes são: {string.Join(\", \", analiseRealizada.Color.DominantColors)}\"; public string RetornarCelebridades(ImageAnalysis analiseRealizada) { if (analiseRealizada.Categories.Count == 0) return \"Não foi possível encontrar celebridades na imagem.\"; var celebridades = new List<string>(); foreach (var categoria in analiseRealizada.Categories) { if (categoria.Detail?.Celebrities is null || categoria.Detail?.Celebrities.Count == 0) continue; celebridades.AddRange( categoria .Detail .Celebrities .Select(c => $\"{c.Name} ({c.Confidence * 100:n2}% de certeza)\")); } return celebridades.Count == 0 ? \"Não foi possível encontrar celebridades na imagem.\" : string.Join(\" - \", celebridades); } public string RetornarPontosDeReferencia(ImageAnalysis analiseRealizada) { if (analiseRealizada.Categories.Count == 0) return \"Não foi possível encontrar pontos de referência na imagem.\"; var pontosDeReferencia = new List<string>(); foreach (var categoria in analiseRealizada.Categories) { if (categoria.Detail?.Landmarks is null || categoria.Detail?.Landmarks.Count == 0) continue; pontosDeReferencia.AddRange( categoria .Detail .Landmarks .Select(l => $\"{l.Name} ({l.Confidence * 100:n2}% de certeza)\")); } return pontosDeReferencia.Count == 0 ? \"Não foi possível encontrar pontos de referência na imagem.\" : string.Join(\" - \", pontosDeReferencia); } } }
Perceba que todos os métodos possuem um funcionamento similar:
- Recebem a análise previamente realizada por parâmetro;
- Verificam se a análise encontrou algo com o qual eles possam trabalhar. Caso não tenha encontrado, uma mensagem informativa é retornada;
- Interpretam a análise realizada e colhem as informações necessárias;
- Juntam tudo em uma
string
e devolvem o resultado.
Eles funcionam basicamente do mesmo jeito, como pode ver. E possuem o mesmo tipo de retorno, pois isso facilitará nosso trabalho na hora de juntar as respostas de análise e exibir na página.
A classe inteira pode ser visualizada no github.
5. Crie o arquivo ComputerVision.cshtml no projeto AzureCognitiveServices
Dentro do projeto AzureCognitiveServices utiliza a pasta dentro da pasta Pages chamada Vision. Nesta pasta previamente criada, adicione uma Razor Page e a chame de ComputerVision.cshtml.
Nela, criaremos diversos formulários, separados por grupos. Cada um responsável por analisar uma característica específica da imagem e, por fim, um que analisará a imagem por completo. Todos os grupos contarão com a possibilidade de análise por URL ou por arquivo.
Vamos, primeiro, editar o código do servidor. Para isso, clique com o botão direito no arquivo aberto e vá em Go to PageModel ou aperte o F7.
Esse arquivo é responsável pelo código C# desta página. Comece colocando os usings.
using ComputerVision; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models; using System.Collections.Generic; using System.IO;
Adicione agora as variáveis que utilizaremos na classe.
namespace AzureCognitiveServices { public class ComputerVisionModel : PageModel { public ICollection<string> Mensagens { get; private set; } public string AnaliseEscolhida { get; private set; } private IWebHostEnvironment _environment; private bool _analisarPorUrl; [BindProperty] public IFormFile Arquivo { get; set; }
Temos quatro variáveis. A variável ICollection<
string> Mensagens será responsável por capturar e exibir as informações das análises do arquivo anterior. Já a IWebHostEnvironment _environment
receberá informações sobre o ambiente que a aplicação está hospedada. A variável _analisarPorUrl
servirá como uma auxiliar para sabermos se a requisição veio por URL ou por arquivo. Por último temos a interface IFormFile
Arquivo com o atributo [
BindProperty]. Essa interface será o arquivo que poderemos enviar para análise e está marcado com o atributo para podermos ligá-lo a um campo no HTML.
Crie o método construtor.
public ComputerVisionModel(IWebHostEnvironment environment) => _environment = environment;
Aqui, no método construtor, estamos usando injeção de dependência para capturarmos as informações de ambiente.
Agora criaremos o método post do servidor para capturar os envios do formulário HTML:
public void OnPost() { string imagem; var pasta = string.Empty; if (Arquivo is null) { imagem = Request.Form[\"url\"]; _analisarPorUrl = true; } else { pasta = Path.Combine(_environment.ContentRootPath, \"imagens\"); if (!Directory.Exists(pasta)) Directory.CreateDirectory(pasta); var caminhoDoArquivo = Path.Combine(_environment.ContentRootPath, \"imagens\", Arquivo.FileName); using (var fileStream = new FileStream(caminhoDoArquivo, FileMode.Create)) Arquivo.CopyTo(fileStream); _analisarPorUrl = false; imagem = caminhoDoArquivo; } AnalisarImagem(imagem); if (!_analisarPorUrl) Directory.Delete(pasta, true); }
Como nossa página terá diversos formulários, separamos a interação de cada um deles em outros métodos (que serão criados a seguir). Mas, cada um dos grupos de formulário terá apenas dois tipos: 1) os formulários de URL, 2) os formulários de arquivo. Sendo assim, esse começo é igual para todos.
Portanto, caso a interface IFormFile Arquivo
seja nula, significa que o usuário optou por enviar uma URL, então simplesmente capturamos a informação enviada pelo campo url do formulário HTML e marcamos a variável _analisarPorUrl
como true
para indicar que a análise será por url.
Caso a interface não seja nula, temos alguns passos a mais. Primeiro começamos copiando a imagem enviada e colocando no servidor, numa pasta própria. Depois pegamos o caminho do arquivo criado e colocamos na variável que será enviada para análise, lembrando que este método pega o caminho e o converte para um FileStream
, e marcamos a variável _analisarPorUrl
como false
para indicar que a análise será por arquivo.
Por último chamamos o método AnalisarImagem(imagem) que realizará todas as análises necessárias, depois deletamos a pasta criada e todo seu conteúdo, caso necessário.
Agora, criaremos o método AnalisarImagem.
private void AnalisarImagem(string imagem) { var analiseDeImagem = new AnaliseDeImagem(); var analiseRealizada = _analisarPorUrl ? analiseDeImagem.AnalisarPorUrl(imagem).Result : analiseDeImagem.AnalisarPorArquivo(imagem).Result; Mensagens = new List<string>(); AnalisarLegenda(analiseDeImagem, analiseRealizada); AnalisarCategorias(analiseDeImagem, analiseRealizada); AnalisarTags(analiseDeImagem, analiseRealizada); AnalisarLogos(analiseDeImagem, analiseRealizada); AnalisarRostos(analiseDeImagem, analiseRealizada); AnalisarConteudoAdultoOuSensivel(analiseDeImagem, analiseRealizada); AnalisarEsquemaDeCores(analiseDeImagem, analiseRealizada); AnalisarCelebridades(analiseDeImagem, analiseRealizada); AnalisarPontosDeReferencia(analiseDeImagem, analiseRealizada); }
Esse método é responsável por fazer chamar o método que faz a análise, entendendo se ela foi requisitado por URL ou por arquivo. Para isso, ele instancia a classe AnaliseDeImagem e captura a análise realizada na variável analiseRealizada. Também instancia a ICollection<
string> Mensagens para utilizarmos ela na nossa página.
Por último, ela chama todos os métodos que interpretam pontos específicos da análise já realizada. Veja a seguir.
private void AnalisarLegenda(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"legenda\", \"Descrição\")) return; Mensagens.Add(analiseDeImagem.RetornarLegenda(analiseRealizada)); } private void AnalisarCategorias(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"categoria\", \"Categorias\")) return; Mensagens.Add(analiseDeImagem.RetornarCategorias(analiseRealizada)); } private void AnalisarTags(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"tags\", \"Tags\")) return; Mensagens.Add(analiseDeImagem.RetornarTags(analiseRealizada)); } private void AnalisarLogos(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"logos\", \"Logos\")) return; Mensagens.Add(analiseDeImagem.RetornarLogos(analiseRealizada)); } private void AnalisarRostos(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"rostos\", \"Rostos\")) return; Mensagens.Add(analiseDeImagem.RetornarRostos(analiseRealizada)); } private void AnalisarConteudoAdultoOuSensivel(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"adulto\", \"Conteúdo adulto ou sensível\")) return; Mensagens.Add(analiseDeImagem.RetornarConteudoAdultoOuSensivel(analiseRealizada)); } private void AnalisarEsquemaDeCores(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"cores\", \"Esquema de cores\")) return; Mensagens.Add(analiseDeImagem.RetornarEsquemaDeCores(analiseRealizada)); } private void AnalisarCelebridades(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"celebridades\", \"Celebridades\")) return; Mensagens.Add(analiseDeImagem.RetornarCelebridades(analiseRealizada)); } private void AnalisarPontosDeReferencia(AnaliseDeImagem analiseDeImagem, ImageAnalysis analiseRealizada) { if (!AnaliseEscolhidaFoi(\"landmark\", \"Pontos de referência\")) return; Mensagens.Add(analiseDeImagem.RetornarPontosDeReferencia(analiseRealizada)); }
Todos os métodos aqui funcionam exatamente da mesma forma:
- Recebem, por parâmetro, a classe que contém as interpretações específicas da análise e a análise previamente realizada.
- Verificam, através do método AnaliseEscolhidaFoi() (criaremos a seguir) se essa foi a análise escolhida. Caso não tenha sido, saem do método.
- Chamam o método correspondente que retorna um texto descritivo daquela interpretação específica e o adicionam a variável mensagem
Por fim, há o método AnaliseEscolhidaFoi() que verifica se a análise escolhida foi a do método que o consulta. Não esqueça, também, de fechar todas as chaves da classe.
private bool AnaliseEscolhidaFoi(string analiseEscolhida, string tituloDaAnaliseEscolhida) { if (!analiseEscolhida.Equals(Request.Form[\"analiseEscolhida\"]) && !\"tudo\".Equals(Request.Form[\"analiseEscolhida\"])) return false; AnaliseEscolhida = \"tudo\".Equals(Request.Form[\"analiseEscolhida\"]) ? \"Analise da imagem por completo\" : tituloDaAnaliseEscolhida; return true; } } }
Esse método verifica se a informação da análise escolhida, vinda do HTML, é igual a que o método está solicitando ou se a opção todas foi selecionada, pois se essa opção foi selecionada, todas as interpretações devem ser verificadas.
Depois, verifica qual o título da análise escolhida, também respeitando a opção todas.
Isso encerra o código da parte do servidor. Vamos voltar a parte do HTML.
A classe HTML terá o código inicial. O altere para isso:
@page @model AzureCognitiveServices.ComputerVisionModel @{ ViewData[\"Title\"] = \"Visão Computacional\"; } <h1>Visão Computacional</h1>
Coloque o seguinte código HTML no restante do arquivo:
<br /> <h2>Descrever a imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <input type=\"hidden\" value=\"legenda\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> <button type=\"submit\">Analisar imagem</button> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"legenda\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Categorizar a imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"categoria\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"categoria\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Gerar tags para a imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"tags\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"tags\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Verificar logos na imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"logos\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"logos\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Verificar rostos na imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"rostos\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"rostos\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Verificar conteúdo adulto ou sensível na imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"adulto\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"adulto\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Verificar esquema de cores na imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"cores\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"cores\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Verificar celebridades na imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"celebridades\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"celebridades\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Verificar pontos de referência na imagem</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"landmark\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"landmark\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> <br /> <br /> <h2>Analisar a imagem por completo</h2> <div> <div> <fieldset> <legend>Testar com uma URL</legend> <form method=\"post\"> <div> <label for=\"url\">URL de uma imagem:</label> <input type=\"url\" name=\"url\" id=\"url\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"tudo\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> <div> <fieldset> <legend>Testar com um arquivo</legend> <form method=\"post\" enctype=\"multipart/form-data\"> <div> <label for=\"arquivo\">Arquivo de uma imagem:</label> <input type=\"file\" asp-for=\"Arquivo\" id=\"arquivo\" /> </div> <button type=\"submit\">Analisar imagem</button> <input type=\"hidden\" value=\"tudo\" id=\"analiseEscolhida\" name=\"analiseEscolhida\" /> </form> </fieldset> </div> </div> @if (!(Model.Mensagens is null)) { <div id=\"modal\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"tituloModal\" aria-hidden=\"true\"> <div role=\"document\"> <div> <div> <h5 id=\"tituloModal\">@Model.AnaliseEscolhida</h5> <button type=\"button\" data-dismiss=\"modal\" aria-label=\"Close\"> <span aria-hidden=\"true\">×</span> </button> </div> <div> @foreach (var mensagem in Model.Mensagens) { <p>@mensagem</p> } </div> <div> <button type=\"button\" data-dismiss=\"modal\">Fechar</button> </div> </div> </div> </div> }
Por mais extenso que seja, isso é apenas código HTML simples. Como explicado anteriormente, essa página terá diversos formulários separados em grupos e foi isso que fizemos.
Cada grupo será responsável por uma análise específica na imagem e contém duas opções de formulário: por URL, ou por arquivo.
Há também, em cada um dos formulários, um campo invisível que nos diz qual é o tipo de análise que foi requisitada.
Por último, caso a variável Mensagens
do servidor não estiver nula, o que significa que o usuário fez alguma requisição e temos alguma resposta, o código HTML de uma modal é criada. No corpo dessa modal, criamos um parágrafo para cada iteração do foreach
, o que pode não fazer muita diferença quando analisamos uma característica específica, mas fica evidente quando analisamos todas as características juntas.
Os arquivos inteiros podem ser visualizados no github, tanto o arquivo de HTML, quando a classe do servidor.
6. Adicione ao menu a página criada e adicione a abertura automática de modais
Agora que tudo está criado, chegamos ao momento de adicionar ao menu a página criada. Para isso, vá na pasta Shared e abra o arquivo _Layout.cshtml. Esse arquivo tem todo o layout que é compartilhado por todas as páginas, o que se repete em todas, como menu e footer, por exemplo.
No primeiro artigo técnico da série criamos um menu para todos os serviços cognitivos da categoria Vision, então, apenas complemente esse menu com mais uma opção.
Logo abaixo da opção de Faces, adicione o seguinte código:
<a asp-page=\"/Vision/ComputerVision\">Visão Computacional</a>
Isso fará com que o menu tenha mais uma opção, similar a imagem a seguir.
Ainda no arquivo _Layout.cshtml a, vá até o final, onde se encontra o código @RenderSection
(\”Scripts\”, required: false) e crie o seguinte script antes do código citado:
<script type=\"text/Javascript\"> $(window).on(\'load\', function () { $(\'#modal\').modal(\'show\'); }); </script>
Esse script fará com que toda modal com o id modal seja exibida assim que a página carregar. Não se preocupe, a modal que criamos agora só terá o código HTML adicionado a página caso o usuário faça alguma alteração, o que é o exato momento que queremos exibí-la.
Conclusão
Continuamos o projeto criado no primeiro artigo técnico da série e, agora, a estrutura do seu projeto deve se parecer com isso.
Vimos, mais uma vez, que não há a necessidade de se dominar técnicas complicadas e difíceis para se ter uma implementação usual e eficiente de Inteligência Artificial com o Serviço Cognitivo da Azure de Visão Computacional.
Lembre-se sempre que tempo é custo e custo é o que precisamos diminuir sempre. Ao utilizar uma ferramenta já bem estabelecida, você consegue poupar tempo nos seus projetos. Opte por isso.
Todo o projeto está disponível no github com uma licença que possibilita colaboração. Sinta-se a vontade.