Na era das fotos digitais e reconhecimento facial para diversas coisas como realizar login, neste post vamos desmitificar um pouco este funcionalidade e veremos como criar o serviço de Face API do Azure e integra-lo no app

Cognitive Services

A demanda do mercado por softwares que sejam dotados de uma certa inteligencia tem crescido bastante nos ultimos anos. Com isso, a Microsoft tem ampliado seu investimento para prover ferramentas capazes de entregar esta demanda de maneira simples para os desenvolvedores.

Com isto, a Microsoft criou os Serviços Cognitivos (Cognitive Services) . Os Serviços cognitivos, de acordo com a Microsoft são:

Os Serviços Cognitivos colocam a IA ao alcance de todos os desenvolvedores, sem exigir experiência com machine learning. É necessária apenas uma chamada à API para inserir a funcionalidade de ver, ouvir, falar, pesquisar, entender e acelerar a tomada de decisão em seus aplicativos

O Serviços Cognitivos da Microsoft possuem diversas categorias e funcionalidades diferentes, como:

  • Detector de Anomalias
  • Análise de texto
  • Reconhecimento de voz
  • Tradução de fala
  • Face
  • Visão personalizada
  • Verificação ortográfica

Você pode conferir mais sobre os serviços cognitivos no site da plataforma.

Criando o serviço de reconhecimento facial

Para criar um serviço de reconhecimento facial, você vai precisar de uma conta no Microsoft Azure.

Caso você precise inserir um cartão de crédito, o serviço que usaremos neste post é gratuito.

Ao acessar o portal do Azure, procure por Cognitive Services:

portal-azure

Na próxima tela, clique em + Add

criar-recurso

Na página seguinte, o Azure irá nos mostrar uma lista de todos os serviços cognitivos disponíveis para serem utilizados. Busque por Face:

buscar por face

O Azure irá nos mostrar a pagina do serviço Face, vamos clicar então em Create.

Na tela seguinte será solicitado que informemos alguns dados sobre o serviço que estamos criando: Nome, Subscription, Location, Pricing tier e Resource Group.

Vamos configurar da seguinte maneira (sinta-se livre para configurar de modo diferente):

Nome do serviço: ReconhecimentoFacial (pode ser que o nome que você deseja, já esteja em uso. Neste caso, de um nome diferente)
Subscription: Ë sua conta do Azure, selecione a de sua preferencia
Location: Vamos selecionar Brazil South
Pricing tier: Vamos selecionar F0 (que é camada de preço gratuita do serviço)
Resource Group: Vamos selecionar o grupo do agrupador de recursos do Azure que vamos armazenar este serviço (pense nisto como uma pasta onde você irá manter os serviços juntos) vamos clicar m Create New e então informar no nome do resource group que será FaceRecognitionResourceGroup

configurar serviço

Para finalizar, vamos clicar em Create

Após finalizar o processo e o Azure terminar de criar o serviço, o portal irá te mostrar a tela de sucesso. Clique então em Go to resource

Integração com Xamarin.Forms

A integração com este serviço pode ser feita via SDK do Cognitive Services ou via chamada de API Rest. O SDK está disponível para C# e Phyton.

Neste post, nós iremos consumir o serviço via API.

Na documentação do Face API você irá encontrar diversos tutorias em varias linguagens, você pode consultar a documentação aqui

Vamos criar um novo projeto Xamarin.Forms e na MainPage.xaml vamos adicionar um Image, um botão com a label Tirar Foto e um botão com a label Identificar emoção:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="Facial.MainPage"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:d="http://xamarin.com/schemas/2014/forms/design"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d">
    <StackLayout Margin="10">
        <Image Source="{Binding Foto}" Margin="10" />
        <Button Command="{Binding TirarFotoCommand}" Text="Tirar foto" Margin="10"/>
        <Button Command="{Binding IdentificarEmoçãoCommand}" Text="Identificar emoção" Margin="10"/>
    </StackLayout>
</ContentPage>

Veja que no código acima, já definimos alguns bindings, um para o source da foto e outros dois para os commands dos botões.

Vamos criar a MainPageViewModel.cs e setar o contexto de binding na MainPage.xaml.cs

    public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
            BindingContext = new MainPageViewModel();
        }
    }

Para auxiliar o trabalho com a view model estou utilizando o pacote MVVMHelpers do James Montemagno

Para que seja possível utilizar a camera para tirar a foto e enviar para o serviço que criamos no Azure, vamos utilizar o Media.Plugin do Jame Montemagno, ele está disponível aqui e a utilização dele é bem simples, o README do GitHub é bem explicativo.

Após configurar o plugin de camera, vamos criar uma nova classe chamada FaceRecognitionService e vamos adicionar a tratativa da imagem e a chamada para API do Azure:

public class FaceRecognitionService
    {
        const string subscriptionKey = "SUA KEY";
        const string uriBase = "https://brazilsouth.api.cognitive.microsoft.com/face/v1.0/detect";

        public async Task<List<FaceResponse>> MakeAnalysisRequest(string imageFilePath)
        {
            var httpClient = new HttpClient();

            httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", subscriptionKey);

            string requestParameters = "returnFaceId=true&amp;returnFaceLandmarks=false" +
                "&amp;returnFaceAttributes=age,gender,headPose,smile,facialHair,glasses," +
                "emotion,hair,makeup,occlusion,accessories,blur,exposure,noise";

            string uri = uriBase + "?" + requestParameters;

            byte[] byteData = GetImageAsByteArray(imageFilePath);

            List<FaceResponse> result;

            using (ByteArrayContent content = new ByteArrayContent(byteData))
            {
                content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

                var response = await httpClient.PostAsync(uri, content);

                string contentString = await response.Content.ReadAsStringAsync();

                result = JsonConvert.DeserializeObject<List<FaceResponse>>(contentString);
            }

            return result;
        }

        private byte[] GetImageAsByteArray(string imageFilePath)
        {
            using (FileStream fileStream = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read))
            {
                BinaryReader binaryReader = new BinaryReader(fileStream);
                return binaryReader.ReadBytes((int)fileStream.Length);
            }
        }
    }

Na classe acima estamos criando duas constantes, uma para armazenar a chave do serviço de reconhecimento facil, Face, criado no portal do Azure e um chamada uriBase que será o endereço da API do azure que iramos chamar. Note que o endereço da API é padrão e está apontando para o local onde criamos o serviço.

Após isto, estamos criando o HTTP Client padrão do .NET e adicionando no header a chave que armazenamos na nossa constante criada acima.

Montamos a url que iremos enviar a foto passando alguns parâmetros, que são o que nós estamos pedindo como resposta para o Azure. Fazemos isto na variável requestParameters, note que estamos pedindo smile, facielHair, glasses, noise, emotion e outros. Estes são os dados que após fazer a análise, o Azure irá nos devolver.

O passo seguinte é utilizar o método de converter a imagem para um byte array e fazer o post para url contada com o urlBase + requestParameters (que são os dados que estamos pedindo como resposta do Azure).

Para finalizarmos esta parte e voltamos e partimos para a view model, ainda precisamos fazer mais algumas coisas. A primeira é acessar novamente o portal do Azure e copiar a Key1:

obter key1

Copie o valor de Key1 e preencha na subscriptionKey da classe FaceRecognitionService.

O objeto que será retornado pela API irá conter todas as informações que passamos no requestParameters na classe FaceRecognitionService. Nós não iremos utilizar todos estes dados, então para o exemplo do post, vamos criar duas nova classes: Uma chamada Face, que será o nosso modelo que armazenará o retorno e a classe FaceReponse que utilizaremos para deserializar o JSON de retorno do Azure:

 public class Face
    { 
        [JsonProperty("emotion")]
        public Dictionary<string, double> Emotions;

        public string CurrentEmotion()
        {
            var emotions = Emotions.OrderByDescending(x => x.Value);
            return emotions.FirstOrDefault().Key;

        }
    }
    public class FaceResponse
    {
        public Face FaceAttributes { get; set; }
    }

Ufa! A maior parte do trabalho já está feito! Agora vamos configurar a MainPageViewModel para realizar as chamadas:

[code language="csharp"]
  public class MainPageViewModel : BaseViewModel
    {
        public ICommand TirarFotoCommand { get; set; }
        public ICommand IdentificarEmoçãoCommand { get; set; }

        ImageSource foto;
        public ImageSource Foto
        {
            get => foto;
            set => SetProperty(ref foto, value);
        }

        private string Arquivo { get; set; }

        string emoção;
        public string Emoção
        {
            get => emoção;
            set => SetProperty(ref emoção, value);
        }


        public MainPageViewModel()
        {
            TirarFotoCommand = new Command(async () =>
            {
                await CrossMedia.Current.Initialize();

                if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
                {
                    Console.Write(@"Camera indisponível");
                    return;
                }

                var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
                {
                    Directory = "Exemplo",
                    Name = "teste.jpg"
                });

                if (file == null)
                    return;

                Arquivo = file.Path;

                Foto = ImageSource.FromStream(() =>
                {
                    var stream = file.GetStream();
                    file.Dispose();
                    return stream;
                });
            });

            IdentificarEmoçãoCommand = new Command(async () =>
            {
                var resultado = await new FaceRecognitionService().MakeAnalysisRequest(Arquivo);
                Emoção = resultado.FirstOrDefault().FaceAttributes.CurrentEmotion();
               await App.Current.MainPage.DisplayAlert("Emoção da foto", Emoção, "OK");
            });
        }
    }
[/code]

Na view model acima além dos commands e da propriedade para guardar a imagem, nós também criamos um propriedade do tipo string chamada de Arquivo que será responsável por armazenar o endereço da imagem para lermos no command de enviar a imagem posteriormente a execução do command de tirar foto. Também criamos a propriedade string chamada Emoção, ela será a variável que irá armazenar a emoção retornada pelo Azure e exibida em um alert.

Isso é tudo! Agora é só executar e ver o resultado!

resultado

Conclusão

Os serviços cognitivos são bem simples de serem consumidos e integrados com aplicações por ter a possibilidade de utilizar a API Rest. A documentação é bem completa e parte essencial para o uso. Com Xamarin, da um poder muito legal ao app com pouco esforço.

Você pode conferir o código deste post no meu GitHub, neste endereço

#Ubuntu

Modificado pela ultima vez: 13 de maio de 2020

Comentários

Escreva uma resposta ou comentário

Seu endereço de e-mail não será publicado.

Esse site utiliza o Akismet para reduzir spam. Aprenda como seus dados de comentários são processados.