Tutorial: Criar uma aplicação do Windows Presentation Framework (WPF) para exibir dados faciais numa imagemTutorial: Create a Windows Presentation Framework (WPF) app to display face data in an image

Neste tutorial, você aprenderá a usar o serviço Azure Face, através do cliente .NET SDK, para detetar rostos numa imagem e, em seguida, apresentar esses dados na UI.In this tutorial, you'll learn how to use the Azure Face service, through the .NET client SDK, to detect faces in an image and then present that data in the UI. Você vai criar uma aplicação WPF que deteta rostos, desenha uma moldura em torno de cada face, e apresenta uma descrição do rosto na barra de estado.You'll create a WPF application that detects faces, draws a frame around each face, and displays a description of the face in the status bar.

Este tutorial mostrar-lhe como:This tutorial shows you how to:

  • Criar uma aplicação WPFCreate a WPF application
  • Instale a biblioteca do cliente FaceInstall the Face client library
  • Utilizar a biblioteca de cliente para detetar rostos numa imagemUse the client library to detect faces in an image
  • Desenhar uma moldura em torno de cada rosto detetadoDraw a frame around each detected face
  • Mostrar uma descrição do rosto realçado na barra de estadoDisplay a description of the highlighted face on the status bar

Captura de ecrã que mostra os rostos detetados, enquadrados com retângulos

O código de amostra completo está disponível no repositório de amostras do CSharp cognitivo no GitHub.The complete sample code is available in the Cognitive Face CSharp sample repository on GitHub.

Se não tiver uma subscrição do Azure, crie uma conta gratuita antes de começar.If you don't have an Azure subscription, create a free account before you begin.

Pré-requisitosPrerequisites

  • Subscrição Azure - Crie uma gratuitamenteAzure subscription - Create one for free
  • Assim que tiver a subscrição do Azure, Azure para obter a sua chave e ponto final.Once you have your Azure subscription, create a Face resource in the Azure portal to get your key and endpoint. Depois de implementar, clique em Ir para o recurso.After it deploys, click Go to resource.
    • Necessitará da chave e ponto final do recurso que criar para ligar a sua aplicação à API face.You will need the key and endpoint from the resource you create to connect your application to the Face API. Colará a chave e o ponto final no código abaixo mais tarde no arranque rápido.You'll paste your key and endpoint into the code below later in the quickstart.
    • Pode utilizar o nível de preços gratuitos F0 para experimentar o serviço e fazer upgrade mais tarde para um nível pago para produção.You can use the free pricing tier (F0) to try the service, and upgrade later to a paid tier for production.
  • Crie variáveis ambientais para a chave e cadeia de ponto final de serviço, nomeada FACE_SUBSCRIPTION_KEY FACE_ENDPOINT e, respectivamente.Create environment variables for the key and service endpoint string, named FACE_SUBSCRIPTION_KEY and FACE_ENDPOINT, respectively.

Criar o projeto do Visual StudioCreate the Visual Studio project

Siga estes passos para criar um novo projeto de aplicação WPF.Follow these steps to create a new WPF application project.

  1. No Visual Studio, abra o diálogo do Novo Projeto.In Visual Studio, open the New Project dialog. Expandir Instalado, depois Visual C., em seguida, selecione A App WPF (.NET Framework).Expand Installed, then Visual C#, then select WPF App (.NET Framework).
  2. Dê à aplicação o nome FaceTutorial e, em seguida, clique em OK.Name the application FaceTutorial, then click OK.
  3. Obtenha os pacotes NuGet necessários.Get the required NuGet packages. Clique com o botão direito no seu projeto no Solution Explorer e selecione Gerir pacotes NuGet; em seguida, encontrar e instalar o seguinte pacote:Right-click on your project in the Solution Explorer and select Manage NuGet Packages; then, find and install the following package:

Adicionar o código inicialAdd the initial code

Nesta secção, irá adicionar o quadro básico da app sem as suas funcionalidades específicas do rosto.In this section, you will add the basic framework of the app without its face-specific features.

Criar a UICreate the UI

Abra MainWindow.xaml e substitua o conteúdo pelo seguinte — código, este código cria a janela UI.Open MainWindow.xaml and replace the contents with the following code—this code creates the UI window. Os FacePhoto_MouseMove BrowseButton_Click e métodos são manipuladores de eventos que definirá mais tarde.The FacePhoto_MouseMove and BrowseButton_Click methods are event handlers that you will define later on.

<Window x:Class="FaceTutorial.MainWindow"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         Title="MainWindow" Height="700" Width="960">
    <Grid x:Name="BackPanel">
        <Image x:Name="FacePhoto" Stretch="Uniform" Margin="0,0,0,50" MouseMove="FacePhoto_MouseMove" />
        <DockPanel DockPanel.Dock="Bottom">
            <Button x:Name="BrowseButton" Width="72" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Left"
                     Content="Browse..."
                     Click="BrowseButton_Click" />
            <StatusBar VerticalAlignment="Bottom">
                <StatusBarItem>
                    <TextBlock Name="faceDescriptionStatusBar" />
                </StatusBarItem>
            </StatusBar>
        </DockPanel>
    </Grid>
</Window>

Criar a classe principalCreate the main class

Abra MainWindow.xaml.cs e adicione os espaços de nome da biblioteca do cliente, juntamente com outros espaços de nome necessários.Open MainWindow.xaml.cs and add the client library namespaces, along with other necessary namespaces.

using Microsoft.Azure.CognitiveServices.Vision.Face;
using Microsoft.Azure.CognitiveServices.Vision.Face.Models;

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

Em seguida, insira o seguinte código na classe MainWindow.Next, insert the following code in the MainWindow class. Este código cria um exemplo faceClient utilizando a chave de subscrição e o ponto final.This code creates a FaceClient instance using the subscription key and endpoint.

// Add your Face subscription key to your environment variables.
private const string subscriptionKey = Environment.GetEnvironmentVariable("FACE_SUBSCRIPTION_KEY");
// Add your Face endpoint to your environment variables.
private const string faceEndpoint = Environment.GetEnvironmentVariable("FACE_ENDPOINT");

private readonly IFaceClient faceClient = new FaceClient(
    new ApiKeyServiceClientCredentials(subscriptionKey),
    new System.Net.Http.DelegatingHandler[] { });

// The list of detected faces.
private IList<DetectedFace> faceList;
// The list of descriptions for the detected faces.
private string[] faceDescriptions;
// The resize factor for the displayed image.
private double resizeFactor;

private const string defaultStatusBarText =
    "Place the mouse pointer over a face to see the face description.";

Em seguida, adicione o construtor MainWindow.Next add the MainWindow constructor. Verifica a sua cadeia de URL de ponto final e associa-a ao objeto do cliente.It checks your endpoint URL string and then associates it with the client object.

public MainWindow()
{
    InitializeComponent();

    if (Uri.IsWellFormedUriString(faceEndpoint, UriKind.Absolute))
    {
        faceClient.Endpoint = faceEndpoint;
    }
    else
    {
        MessageBox.Show(faceEndpoint,
            "Invalid URI", MessageBoxButton.OK, MessageBoxImage.Error);
        Environment.Exit(0);
    }
}

Finalmente, adicione os métodos de BrowseButton_Click e FacePhoto_MouseMove à classe.Finally, add the BrowseButton_Click and FacePhoto_MouseMove methods to the class. Estes métodos correspondem aos manipuladores de eventos declarados em MainWindow.xaml.These methods correspond to the event handlers declared in MainWindow.xaml. O método BrowseButton_Click cria um OpenFileDialog, que permite ao utilizador selecionar uma imagem .jpg.The BrowseButton_Click method creates an OpenFileDialog, which allows the user to select a .jpg image. Em seguida, exibe a imagem na janela principal.It then displays the image in the main window. Irá inserir o código restante para BrowseButton_Click e FacePhoto_MouseMove em etapas posteriores.You will insert the remaining code for BrowseButton_Click and FacePhoto_MouseMove in later steps. Note também a faceList referência de uma lista de — objetos DetectedFace.Also note the faceList reference—a list of DetectedFace objects. Esta referência é onde a sua aplicação irá armazenar e ligar para os dados faciais reais.This reference is where your app will store and call the actual face data.

// Displays the image and calls UploadAndDetectFaces.
private async void BrowseButton_Click(object sender, RoutedEventArgs e)
{
    // Get the image file to scan from the user.
    var openDlg = new Microsoft.Win32.OpenFileDialog();

    openDlg.Filter = "JPEG Image(*.jpg)|*.jpg";
    bool? result = openDlg.ShowDialog(this);

    // Return if canceled.
    if (!(bool)result)
    {
        return;
    }

    // Display the image file.
    string filePath = openDlg.FileName;

    Uri fileUri = new Uri(filePath);
    BitmapImage bitmapSource = new BitmapImage();

    bitmapSource.BeginInit();
    bitmapSource.CacheOption = BitmapCacheOption.None;
    bitmapSource.UriSource = fileUri;
    bitmapSource.EndInit();

    FacePhoto.Source = bitmapSource;
// Displays the face description when the mouse is over a face rectangle.
private void FacePhoto_MouseMove(object sender, MouseEventArgs e)
{

Experimente a aplicaçãoTry the app

Prima Iniciar no menu para testar a sua aplicação.Press Start on the menu to test your app. Quando a janela da aplicação abrir, clique em Navegar no canto inferior esquerdo.When the app window opens, click Browse in the lower left corner. Deve aparecer um diálogo 'File Open'.A File Open dialog should appear. Selecione uma imagem do seu sistema de ficheiros e verifique se aparece na janela.Select an image from your filesystem and verify that it displays in the window. Em seguida, feche a app e avance para o próximo passo.Then, close the app and advance to the next step.

Captura de ecrã que mostra uma imagem não modificada de rostos

Carregar imagem e detetar rostosUpload image and detect faces

A sua aplicação irá detetar rostos chamando o método FaceClient.Face.DetectWithStreamAsync, que envolve a API detete REST para o upload de uma imagem local.Your app will detect faces by calling the FaceClient.Face.DetectWithStreamAsync method, which wraps the Detect REST API for uploading a local image.

Insira o seguinte método na classe MainWindow, abaixo do método FacePhoto_MouseMove.Insert the following method in the MainWindow class, below the FacePhoto_MouseMove method. Este método define uma lista de atributos faciais para recuperar e lê o ficheiro de imagem submetido num Stream.This method defines a list of face attributes to retrieve and reads the submitted image file into a Stream. Em seguida, transmite ambos estes objetos para a chamada do método DetectWithStreamAsync.Then it passes both of these objects to the DetectWithStreamAsync method call.

// Uploads the image file and calls DetectWithStreamAsync.
private async Task<IList<DetectedFace>> UploadAndDetectFaces(string imageFilePath)
{
    // The list of Face attributes to return.
    IList<FaceAttributeType> faceAttributes =
        new FaceAttributeType[]
        {
            FaceAttributeType.Gender, FaceAttributeType.Age,
            FaceAttributeType.Smile, FaceAttributeType.Emotion,
            FaceAttributeType.Glasses, FaceAttributeType.Hair
        };

    // Call the Face API.
    try
    {
        using (Stream imageFileStream = File.OpenRead(imageFilePath))
        {
            // The second argument specifies to return the faceId, while
            // the third argument specifies not to return face landmarks.
            IList<DetectedFace> faceList =
                await faceClient.Face.DetectWithStreamAsync(
                    imageFileStream, true, false, faceAttributes);
            return faceList;
        }
    }
    // Catch and display Face API errors.
    catch (APIErrorException f)
    {
        MessageBox.Show(f.Message);
        return new List<DetectedFace>();
    }
    // Catch and display all other errors.
    catch (Exception e)
    {
        MessageBox.Show(e.Message, "Error");
        return new List<DetectedFace>();
    }
}

Desenhe retângulos em torno de rostosDraw rectangles around faces

Em seguida, irá adicionar o código para desenhar um retângulo em torno de cada face detetada na imagem.Next, you will add the code to draw a rectangle around each detected face in the image. Na classe MainWindow, insira o seguinte código no fim do método BrowseButton_Click, após a FacePhoto.Source = bitmapSource linha.In the MainWindow class, insert the following code at the end of the BrowseButton_Click method, after the FacePhoto.Source = bitmapSource line. Este código preenche uma lista de rostos detetados da chamada para UploadAndDetectFaces.This code populates a list of detected faces from the call to UploadAndDetectFaces. Em seguida, desenha um retângulo em torno de cada face e exibe a imagem modificada na janela principal.Then it draws a rectangle around each face and displays the modified image in the main window.

// Detect any faces in the image.
Title = "Detecting...";
faceList = await UploadAndDetectFaces(filePath);
Title = String.Format(
    "Detection Finished. {0} face(s) detected", faceList.Count);

if (faceList.Count > 0)
{
    // Prepare to draw rectangles around the faces.
    DrawingVisual visual = new DrawingVisual();
    DrawingContext drawingContext = visual.RenderOpen();
    drawingContext.DrawImage(bitmapSource,
        new Rect(0, 0, bitmapSource.Width, bitmapSource.Height));
    double dpi = bitmapSource.DpiX;
    // Some images don't contain dpi info.
    resizeFactor = (dpi == 0) ? 1 : 96 / dpi;
    faceDescriptions = new String[faceList.Count];

    for (int i = 0; i < faceList.Count; ++i)
    {
        DetectedFace face = faceList[i];

        // Draw a rectangle on the face.
        drawingContext.DrawRectangle(
            Brushes.Transparent,
            new Pen(Brushes.Red, 2),
            new Rect(
                face.FaceRectangle.Left * resizeFactor,
                face.FaceRectangle.Top * resizeFactor,
                face.FaceRectangle.Width * resizeFactor,
                face.FaceRectangle.Height * resizeFactor
                )
        );

        // Store the face description.
        faceDescriptions[i] = FaceDescription(face);
    }

    drawingContext.Close();

    // Display the image with the rectangle around the face.
    RenderTargetBitmap faceWithRectBitmap = new RenderTargetBitmap(
        (int)(bitmapSource.PixelWidth * resizeFactor),
        (int)(bitmapSource.PixelHeight * resizeFactor),
        96,
        96,
        PixelFormats.Pbgra32);

    faceWithRectBitmap.Render(visual);
    FacePhoto.Source = faceWithRectBitmap;

    // Set the status bar text.
    faceDescriptionStatusBar.Text = defaultStatusBarText;
}

Descreva os rostosDescribe the faces

Adicione o seguinte método à classe MainWindow, abaixo do método UploadAndDetectFaces.Add the following method to the MainWindow class, below the UploadAndDetectFaces method. Este método converte os atributos faciais recuperados numa cadeia que descreve o rosto.This method converts the retrieved face attributes into a string describing the face.

// Creates a string out of the attributes describing the face.
private string FaceDescription(DetectedFace face)
{
    StringBuilder sb = new StringBuilder();

    sb.Append("Face: ");

    // Add the gender, age, and smile.
    sb.Append(face.FaceAttributes.Gender);
    sb.Append(", ");
    sb.Append(face.FaceAttributes.Age);
    sb.Append(", ");
    sb.Append(String.Format("smile {0:F1}%, ", face.FaceAttributes.Smile * 100));

    // Add the emotions. Display all emotions over 10%.
    sb.Append("Emotion: ");
    Emotion emotionScores = face.FaceAttributes.Emotion;
    if (emotionScores.Anger >= 0.1f) sb.Append(
        String.Format("anger {0:F1}%, ", emotionScores.Anger * 100));
    if (emotionScores.Contempt >= 0.1f) sb.Append(
        String.Format("contempt {0:F1}%, ", emotionScores.Contempt * 100));
    if (emotionScores.Disgust >= 0.1f) sb.Append(
        String.Format("disgust {0:F1}%, ", emotionScores.Disgust * 100));
    if (emotionScores.Fear >= 0.1f) sb.Append(
        String.Format("fear {0:F1}%, ", emotionScores.Fear * 100));
    if (emotionScores.Happiness >= 0.1f) sb.Append(
        String.Format("happiness {0:F1}%, ", emotionScores.Happiness * 100));
    if (emotionScores.Neutral >= 0.1f) sb.Append(
        String.Format("neutral {0:F1}%, ", emotionScores.Neutral * 100));
    if (emotionScores.Sadness >= 0.1f) sb.Append(
        String.Format("sadness {0:F1}%, ", emotionScores.Sadness * 100));
    if (emotionScores.Surprise >= 0.1f) sb.Append(
        String.Format("surprise {0:F1}%, ", emotionScores.Surprise * 100));

    // Add glasses.
    sb.Append(face.FaceAttributes.Glasses);
    sb.Append(", ");

    // Add hair.
    sb.Append("Hair: ");

    // Display baldness confidence if over 1%.
    if (face.FaceAttributes.Hair.Bald >= 0.01f)
        sb.Append(String.Format("bald {0:F1}% ", face.FaceAttributes.Hair.Bald * 100));

    // Display all hair color attributes over 10%.
    IList<HairColor> hairColors = face.FaceAttributes.Hair.HairColor;
    foreach (HairColor hairColor in hairColors)
    {
        if (hairColor.Confidence >= 0.1f)
        {
            sb.Append(hairColor.Color.ToString());
            sb.Append(String.Format(" {0:F1}% ", hairColor.Confidence * 100));
        }
    }

    // Return the built string.
    return sb.ToString();
}

Apresentar a descrição de rostosDisplay the face description

Adicione o seguinte código ao método FacePhoto_MouseMove.Add the following code to the FacePhoto_MouseMove method. Este manipulador de eventos exibe a cadeia de descrição facial faceDescriptionStatusBar quando o cursor paira sobre um retângulo facial detetado.This event handler displays the face description string in faceDescriptionStatusBar when the cursor hovers over a detected face rectangle.

// If the REST call has not completed, return.
if (faceList == null)
    return;

// Find the mouse position relative to the image.
Point mouseXY = e.GetPosition(FacePhoto);

ImageSource imageSource = FacePhoto.Source;
BitmapSource bitmapSource = (BitmapSource)imageSource;

// Scale adjustment between the actual size and displayed size.
var scale = FacePhoto.ActualWidth / (bitmapSource.PixelWidth / resizeFactor);

// Check if this mouse position is over a face rectangle.
bool mouseOverFace = false;

for (int i = 0; i < faceList.Count; ++i)
{
    FaceRectangle fr = faceList[i].FaceRectangle;
    double left = fr.Left * scale;
    double top = fr.Top * scale;
    double width = fr.Width * scale;
    double height = fr.Height * scale;

    // Display the face description if the mouse is over this face rectangle.
    if (mouseXY.X >= left && mouseXY.X <= left + width &&
        mouseXY.Y >= top && mouseXY.Y <= top + height)
    {
        faceDescriptionStatusBar.Text = faceDescriptions[i];
        mouseOverFace = true;
        break;
    }
}

// String to display when the mouse is not over a face rectangle.
if (!mouseOverFace) faceDescriptionStatusBar.Text = defaultStatusBarText;

Executar a aplicaçãoRun the app

Execute a aplicação e procure uma imagem que tenha um rosto.Run the application and browse for an image containing a face. Aguarde alguns segundos para permitir que o serviço Face responda.Wait a few seconds to allow the Face service to respond. Devia ver um retângulo vermelho em cada um dos rostos da imagem.You should see a red rectangle on each of the faces in the image. Se mover o rato sobre um retângulo facial, a descrição desse rosto deve aparecer na barra de estado.If you move the mouse over a face rectangle, the description of that face should appear in the status bar.

Captura de ecrã que mostra os rostos detetados, enquadrados com retângulos

Passos seguintesNext steps

Neste tutorial, aprendeu o processo básico de utilização do serviço Face .NET SDK e criou uma aplicação para detetar e emoldurar rostos numa imagem.In this tutorial, you learned the basic process for using the Face service .NET SDK and created an application to detect and frame faces in an image. Em seguida, saiba mais sobre os detalhes da deteção facial.Next, learn more about the details of face detection.