Usare l'attributo HeadPose

In questa guida verrà illustrato come usare l'attributo HeadPose di un volto rilevato per abilitare alcuni scenari chiave.

Importante

Gli attributi relativi al viso vengono stimati tramite l'uso di algoritmi statistici. Potrebbero non essere sempre accurati. Prestare attenzione quando si effettuano decisioni basate sui dati degli attributi. Evitare di usare questi attributi per le operazioni anti-spoofing. È invece consigliabile usare il rilevamento della mimica facciale. Per altre informazioni, vedere Esercitazione: Rilevare la mimica facciale.

Ruotare il rettangolo del viso

Il rettangolo del viso, restituito con ogni viso rilevato, contrassegna la posizione e le dimensioni del viso nell'immagine. Per impostazione predefinita, il rettangolo è sempre allineato all'immagine (i relativi lati sono verticali e orizzontali). Questo comportamento può risultare inefficiente per inquadrare i visi angolati. Nei casi in cui si intende ritagliare i visi in un'immagine a livello di programmazione, è preferibile poter ruotare il rettangolo da ritagliare.

L'app di esempio Azure AI Face WPF (Windows Presentation Foundation) usa l'attributo HeadPose per ruotare i rettangoli del viso rilevati.

Esplorare il codice di esempio

Per ruotare il rettangolo del viso a livello di programmazione, è possibile usare l'attributo HeadPose. Se si specifica questo attributo durante il rilevamento dei visi (vedere Chiamare l'API di rilevamento), sarà possibile eseguirne una query in un secondo momento. Il metodo seguente dell'app Azure AI Face WPF accetta un elenco di oggetti FaceDetectionResult e restituisce un elenco di oggetti Face. In questo caso, Face è una classe personalizzata che archivia i dati del viso, incluse le coordinate aggiornate del rettangolo. Vengono calcolati nuovi valori per top, left, width e height, mentre un nuovo campo FaceAngle specifica la rotazione.

/// <summary>
/// Calculate the rendering face rectangle
/// </summary>
/// <param name="faces">Detected face from service</param>
/// <param name="maxSize">Image rendering size</param>
/// <param name="imageInfo">Image width and height</param>
/// <returns>Face structure for rendering</returns>
public static IEnumerable<Face> CalculateFaceRectangleForRendering(IList<FaceDetectionResult> faces, int maxSize, Tuple<int, int> imageInfo)
{
    var imageWidth = imageInfo.Item1;
    var imageHeight = imageInfo.Item2;
    var ratio = (float)imageWidth / imageHeight;
    int uiWidth = 0;
    int uiHeight = 0;
    if (ratio > 1.0)
    {
        uiWidth = maxSize;
        uiHeight = (int)(maxSize / ratio);
    }
    else
    {
        uiHeight = maxSize;
        uiWidth = (int)(ratio * uiHeight);
    }

    var uiXOffset = (maxSize - uiWidth) / 2;
    var uiYOffset = (maxSize - uiHeight) / 2;
    var scale = (float)uiWidth / imageWidth;

    foreach (var face in faces)
    {
        var left = (int)(face.FaceRectangle.Left * scale + uiXOffset);
        var top = (int)(face.FaceRectangle.Top * scale + uiYOffset);

        // Angle of face rectangles, default value is 0 (not rotated).
        double faceAngle = 0;

        // If head pose attributes have been obtained, re-calculate the left & top (X & Y) positions.
        if (face.FaceAttributes?.HeadPose != null)
        {
            // Head pose's roll value acts directly as the face angle.
            faceAngle = face.FaceAttributes.HeadPose.Roll;
            var angleToPi = Math.Abs((faceAngle / 180) * Math.PI);

            // _____       | / \ |
            // |____|  =>  |/   /|
            //             | \ / |
            // Re-calculate the face rectangle's left & top (X & Y) positions.
            var newLeft = face.FaceRectangle.Left +
                face.FaceRectangle.Width / 2 -
                (face.FaceRectangle.Width * Math.Sin(angleToPi) + face.FaceRectangle.Height * Math.Cos(angleToPi)) / 2;

            var newTop = face.FaceRectangle.Top +
                face.FaceRectangle.Height / 2 -
                (face.FaceRectangle.Height * Math.Sin(angleToPi) + face.FaceRectangle.Width * Math.Cos(angleToPi)) / 2;

            left = (int)(newLeft * scale + uiXOffset);
            top = (int)(newTop * scale + uiYOffset);
        }

        yield return new Face()
        {
            FaceId = face.FaceId?.ToString(),
            Left = left,
            Top = top,
            OriginalLeft = (int)(face.FaceRectangle.Left * scale + uiXOffset),
            OriginalTop = (int)(face.FaceRectangle.Top * scale + uiYOffset),
            Height = (int)(face.FaceRectangle.Height * scale),
            Width = (int)(face.FaceRectangle.Width * scale),
            FaceAngle = faceAngle,
        };
    }
}

Visualizzare il rettangolo aggiornato

Da qui, è possibile usare gli oggetti Face restituiti nella visualizzazione. Le righe seguenti del file FaceDetectionPage.xaml mostra il rendering del nuovo rettangolo a partire da questi dati:

 <DataTemplate>
    <Rectangle Width="{Binding Width}" Height="{Binding Height}" Stroke="#FF26B8F4" StrokeThickness="1">
        <Rectangle.LayoutTransform>
            <RotateTransform Angle="{Binding FaceAngle}"/>
        </Rectangle.LayoutTransform>
    </Rectangle>
</DataTemplate>

Passaggi successivi

  • Per un esempio di utilizzo dei rettangoli del viso ruotati, vedere l'app Azure AI Face WPF su GitHub.