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 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. Non usare questi attributi per lo spoofing. È invece consigliabile usare il rilevamento di Liveness viso. Per altre informazioni, vedere Esercitazione: Rilevare la vivacità nei visi.

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 quando si rilevano visi (vedere Chiamare l'API di rilevamento), sarà possibile eseguirne una query in un secondo momento. Il metodo seguente dell'app WPF Viso di Intelligenza artificiale di Azure accetta un elenco di oggetti DetectedFace 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<DetectedFace> 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 funzionante di rettangoli visi ruotati, vedere l'app WPF Viso di Azure in GitHub.
  • In alternativa, vedere l'app dell'esempio HeadPose di Viso, che tiene traccia dell'attributo HeadPose in tempo reale per rilevare i movimenti della testa.