Confira neste artigo técnico da série NÃO reinvente a roda! Como controlar completamente seus projetos de Visão Personalizada da Azure.
Falamos, no artigo anterior, que a Visão Computacional é a forma como as máquinas podem “enxergar o mundo” e como implementá-la utilizando os Serviços Cognitivos da Azure já pré estabelecidos. Mas e caso você necessite treinar com um conjunto específico e definir, pra IA, o quê é o quê? Bom, nesse caso você utilizaria o Serviço Cognitivo da Azure de Visão Personalizada. Nele, você pode criar projetos que contarão com seus próprios conjuntos de imagens, tags referentes às essas imagens e treinar para um resultado específico.
Tudo isso é possível apenas com o portal de Visão Personalizada, mas exploraremos como controlar tudo isso via código!
Visão Personalizada no Azure
Assim como o Serviço de Visão Computacional, o Serviço de Visão Personalizada da Azure também é usado para analisar e detectar informações relevantes em imagens, com a diferença de ser completamente customizável para o seu domínio e ainda sem precisar de expertise em machine learning.
Este artigo será dividido em três partes devido a quantidade de operações que podem ser feitas na Visão Personalizada e, por ser o terceiro da série, vamos continuar construindo a aplicação que começamos no primeiro artigo: NÃO reinvente a roda! Serviços cognitivos da Azure: Face, e demos continuidade em todos os da série NÃO reinvente a roda! Portanto, confere lá os outros artigos e fique por dentro de tudo que estamos fazendo!
Este artigo terá todos os controles referentes aos Projetos de Visão Personalizada. Como criá-los, editá-los, excluí-los e listá-los.
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 CustomVision.
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 treinamento e outro para predição do serviço de visão personalizada e obtenha a chave e o endpoint do recurso de treinamento, como na imagem a seguir.
3. Obtenha as informações do portal de Visão Personalizada
Após isso, realize login no portal de Visão Personalizada. A página aberta é a página de projetos que, caso seja seu primeiro login, não listará nenhum. No canto superior direito da página há um ícone de engrenagem. Clique nele para ir às configurações dos projetos.
Na página de configurações você verá seus dois recursos recém criados, tanto o de treinamento quanto o de predição. Essa página conterá as informações restantes que usaremos ao longo desse e de suas continuações.
4. Conecte o Treinamento do Serviço de Visão Personalizada ao seu projeto
Voltando ao projeto no VIsual Studio, vamos renomear o arquivo Class1.cs para algo mais palatável. Renomeio para Treinamento.cs.
Abra o Package Manager Console e execute o seguinte comando para adicionar as bibliotecas do Serviço Cognitivo de Visão Personalizada ao projeto que chamamos de CustomVision.
dotnet add .CustomVision package Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training --version 1.0.0
Não esqueça, também, de conectar o projeto CustomVision 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 CustomVision. Assim o projeto AzureCognitiveServices conseguirá acessar o projeto CustomVisione consumir o que precisar.
5. Implemente o Treinamento da Visão Personalizada na classe Treinamento.cs
Começo colocando todos os Usings necessários para o funcionamento correto da classe:
using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training; using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading;
Depois adicione as variáveis de instância que utilizaremos nessa primeira parte do artigo:
namespace CustomVision { public class Treinamento { private const string _chaveDeTreinamento = \"<sua chave de treinamento>\"; private const string _endpoint = \"<seu endpoint>\"; private readonly ICustomVisionTrainingClient _servicoCognitivoDeVisaoPersonalizadaTreinamento;
Lembre de substituir \"<sua chave>\"
e \"<sua chave>\"
pelos valores obtidos no passo 2. Configure o Azure.
A interface ICustomVisionTrainingClient
é, justamente, a interface que utilizaremos para chamar os métodos que o Serviço Cognitivo de Visão Personalizada nos disponibiliza.
Crie um método construtor para que, sempre que essa classe for instanciada, a variável _servicoCognitivoDeVisaoPersonalizadaTreinamento
seja instanciada também.
public Treinamento() => _servicoCognitivoDeVisaoPersonalizadaTreinamento = new CustomVisionTrainingClient() { ApiKey = _chaveDeTreinamento, Endpoint = _endpoint };
Nessa parte do artigo, manipulamos apenas os Projetos da Visão Personalizada. Portante, o restante da classe terá apenas os código referentes aos Projetos.
Adicione os códigos abaixo e não esqueça de fechar todas as chaves da classe:
public IEnumerable<Project> ListarProjetos() => _servicoCognitivoDeVisaoPersonalizadaTreinamento.GetProjects(); public void CriarProjeto(string nome, string descrição = \"\") => _servicoCognitivoDeVisaoPersonalizadaTreinamento.CreateProject(nome, descricao); public void EditarProjeto(string idDoProjeto, Project projeto) => _servicoCognitivoDeVisaoPersonalizadaTreinamento.UpdateProject(new Guid(idDoProjeto), projeto); public void ExcluirProjeto(string idDoProjeto) => _servicoCognitivoDeVisaoPersonalizadaTreinamento.DeleteProject(new Guid(idDoProjeto)); public Project CarregarProjeto(string idDoProjeto) => ListarProjetos().FirstOrDefault(p => p.Id.ToString().Equals(idDoProjeto)) ?? new Project(); } }
Essas são as operações que podemos manipular em um Projeto. As operações básicas de listar, carregar, criar, editar e excluir.
Cada um dos métodos faz uma dessas coisas, conforme seu nome.
Todos são bem simples e similares, apenas recebem os parâmetros necessários para chamar os métodos da interface _servicoCognitivoDeVisaoPersonalizadaTreinamento
e devolvem seu resultado, com exceção do CarregarProjeto
(), este utiliza um null-coalescing (o símbolo de ??) para retornar uma nova instância de Project
(), caso o retorno original seja nulo.
A classe inteira pode ser visualizada no github.
6. Crie o arquivo SalvarProjeto.cshtml no projeto AzureCognitiveServices
Dentro do projeto AzureCognitiveServices cria uma nova pasta dentro da pasta Vision, que está dentro da pasta Pages e a chame de CustomVision. Nesta pasta criada agora, adicione uma Razor Page e a chame de SalvarProjeto.cshtm.
Nela, criaremos o formulário responsável por ter as informações do cadastro de um Projeto, que é bem simples, composto de Nome e Descrição.
Vamos usá-la tanto para cadastrar um novo Projeto, quanto para editar um Projeto existente.
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 CustomVision; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models;
Adicione agora as variáveis que utilizaremos na classe.
namespace AzureCognitiveServices { public class SalvarProjetoModel : PageModel { private readonly Treinamento _treinamento; public Project Projeto { get; private set; }
Temos apenas duas variáveis. A primeira Treinamento _treinamento é responsável por chamar os métodos da classe que criamos em 5. Implemente o Treinamento da Visão Personalizada na classe Treinamento.cs. Já a outra, Project Projeto é o projeto que criaremos, ou editaremos nessa classe.
Crie o método construtor.
public SalvarProjetoModel() => _treinamento = new Treinamento();
O método construtor apenas cria uma nova instância de Treinamento
() para ser usada no restante da classe.
Agora crie o método get
que será executado sempre que esta página for aberta.
public void OnGet(string idDoProjeto) => Projeto = _treinamento.CarregarProjeto(idDoProjeto);
O método get
apenas carregará um projeto específico que será passado por parâmetro. Como este método é executado sempre que a página é aberta, o parâmetro esperado por ele (string
idDoProjeto) será passado na URL, quando houver.
Por último, crie o método post
para capturar os envios do formulário HTML e não esqueça de fechar as chaves da classe.
public IActionResult OnPost(string idDoProjeto) { var nome = Request.Form[\"nome\"]; var descrição = Request.Form[\"descrição\"]; if (string.IsNullOrWhiteSpace(idDoProjeto)) _treinamento.CriarProjeto(nome, descricao); else _treinamento.EditarProjeto(idDoProjeto, new Project { Name = nome, Description = descrição }); return RedirectToPage(\"/Vision/CustomVision/Projetos\"); } } }
Este método começa um pouco diferente do que vimos até agora, pois o tipo de retorno é IActionResult
e, mesmo sendo um post
, tem um parâmetro (string
idDoProjeto).
Isto é porque, no final do método, iremos redirecionar o usuário para uma outra página (que criaremos mais a frente, ainda neste artigo) e, por isso, é necessário esse tipo de retorno. Já o parâmetro, é devido a informação que pode, ou não, estar na URL. No decorrer do método, fazemos uma verificação nele, caso ele não exista, significa que teremos que criar um novo Projeto, caso exista, teremos que editar o Projeto que foi passado por parâmetro, ambos pegando informações do formulário HTML.
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.SalvarProjetoModel @{ ViewData[\"Title\"] = \"Salvar Projeto\"; } <h1>Salvar Projeto @Model.Projeto?.Name</h1>
Coloque o seguinte código HTML no restante do arquivo:
<form method=\"post\"> <div> <div> <div> <label for=\"nome\">* Nome do projeto:</label> <input type=\"text\" value=\"@Model.Projeto?.Name\" name=\"nome\" id=\"nome\" required /> </div> </div> </div> <div> <div> <div> <label for=\"descrição\">Descrição do projeto:</label> <textarea name=\"descrição\" id=\"descrição\" rows=\"4\">@Model.Projeto?.Description</textarea> </div> </div> </div> <div> <div> <div> <button type=\"reset\" data-dismiss=\"modal\">Limpar campos</button> <button type=\"submit\">Salvar projeto</button> </div> </div> </div> </form>
Este código tem apenas o HTML que gerará um formulário contendo os campos de Nome e Descrição, necessários para a criação de um Projeto, sendo que o campo Nome é obrigatório. E, por fim, botões para limpar os campos ou concluir a operação.
Além disso, como há a possibilidade de ser uma edição, os campos têm seus valores preenchidos pelos valores do Projeto, caso ele exista.
Os arquivos inteiros podem ser visualizados no github, tanto o arquivo de HTML, quando a classe do servidor.
7. Crie o arquivo Projetos.cshtml no projeto AzureCognitiveServices
Dentro do projeto AzureCognitiveServices use a pasta CustomVision para criar uma Razor Page e a chame de Projetos.cshtml.
Ela será responsável por listar todos os projetos existentes, bem como redirecionar para todos os outros recursos que trataremos nesse artigo e suas outras partes, como a adição de tags, fotos e predição.
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 CustomVision; using Microsoft.AspNetCore.Mvc.RazorPages; using Microsoft.Azure.CognitiveServices.Vision.CustomVision.Training.Models; using System.Collections.Generic; using System.Linq;
Adicione agora as variáveis que utilizaremos na classe.
namespace AzureCognitiveServices { public class ProjetosModel : PageModel { private readonly Treinamento _treinamento; public IEnumerable<Project> Projetos { get; private set; } public bool PodeAdicionarNovosProjetos { get; private set; }
Essa classe também tem uma variável Treinamento
_treinamento
para acessar os métodos dessa classe que criamos, assim como tem IEnumerable <Projetos>
, que é responsável por conter os Projetos existentes, por fim há a bool
PodeAdicionarNovosProjetos
, que nos dirá se é possível, ou não, adicionar novos projetos levando em consideração a cota padrão de 2 Projetos do recurso gratuito de Visão Personalizada.
Crie o método construtor e o método que ele chama.
public ProjetosModel() { _treinamento = new Treinamento(); ListarProjetos(); } private void ListarProjetos() { Projetos = _treinamento.ListarProjetos(); PodeAdicionarNovosProjetos = Projetos.Count() < 2; }
O método construtor, além de criar uma nova instância de Treinamento
()
que será usada ao longo da classe, também invoca o método ListarProjetos
()
que, por sua vez, além de listar os Projetos existentes, também verifica a quantidade deles para alimentar a variável PodeAdicionarNovosProjetos
.
Por último, crie o método post
e um método que será usado apenas no HTML. Além disso, não esqueça de fechar todas as chaves da classe.
public void OnPost() { _treinamento.ExcluirProjeto(Request.Form[\"idDoProjeto\"]); ListarProjetos(); } public IEnumerable<Tag> ListarTags(Project projeto) => _treinamento.ListarTags(projeto); } }
O método post dessa classe é bem curto, apenas com uma ação, pois todas as outras serão redirecionadas para outras páginas. Primeiro ele exclui um Projeto selecionado e, depois, executa o método ListarProjetos
()
para listá-los novamente. Não se preocupe com a exclusão, a pergunta de confirmação da ação é feita no HTML.
O outro método, IEnumerable<Tag>
ListarTags()
, será apenas usado no HTML para listar as tags existentes em um projeto específico. O controle de tags será feito na segunda parte deste artigo.
Isso encerra o código da parte do servidor. Vamos voltar a parte do HTML, que deve ter isso como código inicial. O mantenha assim.
@page @model AzureCognitiveServices.ProjetosModel @{ ViewData[\"Title\"] = \"Projetos\"; } <h1>Projetos</h1>
Coloque o seguinte código HTML no restante do arquivo:
@if (Model.PodeAdicionarNovosProjetos) { <br /> <br /> <a asp-page=\"/Vision/CustomVision/SalvarProjeto\">Novo Projeto</a> } @if (Model.Projetos.Any()) { <br /> <br /> <fieldset> <legend>Projetos já existentes</legend> <div> @foreach (var projeto in Model.Projetos) { <div> <div> <div> <h5>@projeto.Name</h5> <h6>@projeto.Description</h6> <p>Tags: @Model.ListarTags(projeto).Aggregate(string.Empty, (atual, tag) => $\"{atual}{tag.Name} ({tag.ImageCount} fotos); \")</p> <div> <a asp-page=\"/Vision/CustomVision/SalvarProjeto\" asp-route-idDoProjeto=\"@projeto.Id\">Editar</a> <a asp-page=\"/Vision/CustomVision/TagsDoProjeto\" asp-route-idDoProjeto=\"@projeto.Id\">Tags</a> <a asp-page=\"/Vision/CustomVision/AdicaoDeFotos\" asp-route-idDoProjeto=\"@projeto.Id\">Adicionar foto</a> <a asp-page=\"/Vision/CustomVision/Predicao\" asp-route-idDoProjeto=\"@projeto.Id\">Predizer</a> <a href=\"#\" data-toggle=\"modal\" data-target=\"#[email protected]\">Excluir</a> </div> </div> </div> </div> <div id=\"[email protected]\" tabindex=\"-1\" role=\"dialog\" aria-labelledby=\"[email protected]\" aria-hidden=\"true\"> <div role=\"document\"> <div> <div> <h5 id=\"[email protected]\">Projeto @projeto.Name</h5> <button type=\"button\" data-dismiss=\"modal\" aria-label=\"Close\"> <span aria-hidden=\"true\">×</span> </button> </div> <div> <p>Tem certeza que deseja excluir o projeto?</p> </div> <div> <form method=\"post\"> <input type=\"hidden\" value=\"@projeto.Id\" name=\"idDoProjeto\" id=\"idDoProjeto\" /> <button type=\"button\" data-dismiss=\"modal\">Cancelar</button> <button type=\"submit\">Excluir projeto</button> </form> </div> </div> </div> </div> } </div> </fieldset> }
O código HTML dessa página começa utilizando a variável Model
.PodeAdicionarNovosProjetos
, acessando a Model, para verificar se é possível, ou não adicionar novos projetos. Caso seja, um botão é mostrado que redireciona para a página que criamos anteriormente.
Ele segue verificando se já há algum Projeto cadastrado e, se houver, exibe o código HTML restante.
Há, depois, um foreach
que varre toda nossa lista de Projetos IEnumerable<Project>
Projetos
e cria uma parte do HTML para cada Projeto nessa lista.
Nesta parte há vários links que redirecionam para páginas específicas de cada ação possível de um projeto: editar, editar suas tags, adicionar fotos, predizer e excluir (criaremos todas nas próximas partes do artigo). Note que o redirecionamento é o mesmo utilizado antes, mas há uma declaração a mais asp-route-idDoProjeto
=
\"@projeto.Id\"
, essa declaração diz que, para a página que estou redirecionando, há uma variável que deve ir junto da rota (na URL) e se chama idDoProjeto
, seu valor será o Id do Projeto ao qual essa parte do HTML está sendo gerado.
Essa declaração é bem simples e útil. A parte asp-route-
é fixa, o restante é mutável para nossas necessidades, no nosso caso, uma variável chamada idDoProjeto
, que será recebida pela página destino. O URL ficará assim com essa declaração: /Vision/CustomVision/SalvarProjeto?idDoProjeto=[conteúdo]
, por exemplo.
Note, também, que a ação de excluir não redireciona para página alguma, tampouco executa o método post
, ela apenas abre uma modal, que está sendo criada logo abaixo. Essa modal é exibida para confirmação de exclusão e é criada para cada Projeto existente. Caso haja uma confirmação, aí sim o método post é executado e o Projeto é excluído.
Os arquivos inteiros podem ser visualizados no github, tanto o arquivo de HTML, quando a classe do servidor.
8. Adicione ao menu a página de Projetos criada
Agora que tudo está criado nessa primeira parte do artigo, 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 artigo sobre Serviços Cognitivos da Azure Face 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 Visão Computacional, adicione o seguinte código:
<a asp-page=\"/Vision/CustomVision/Projetos\">Visão Personalizada</a>
Isso fará com que o menu tenha mais uma opção, similar a imagem a seguir.
Conclusão
Este artigo, devido às várias opções que o Serviço Cognitivo de Visão Personalizada, terá que ser dividido em três partes.
Nesta primeira parte, além de termos continuado o projeto criado no primeiro artigo técnico da série, implementamos a criação de Projetos para a Visão Personalizada da Azure. Esse é o ponto de partida para criarmos nossas próprias regras de definição e tageamento de imagens para usarmos no nosso domínio específico.
Com isso, a estrutura atual do seu projeto deve estar se parecendo assim:
Mesmo sendo o passo inicial, já percebemos que a criação dos projetos que terão nossas configurações é extremamente rápida e simples. Além disso, há a possibilidade de tudo ser feito através do portal de Visão Personalizada, o que nos poupa ainda mais tempo, o que nos reduz o custo.
Todo o projeto está disponível no github com uma licença que possibilita colaboração. Sinta-se a vontade.