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:
Na próxima tela, clique em + Add
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:
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
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&returnFaceLandmarks=false" +
"&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:
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!
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
Comentários