Share via


Utiliser l’attribut HeadPose

Dans ce guide, vous allez voir comment utiliser l’attribut HeadPose d’un visage détecté pour certains scénarios clés.

Important

Les attributs de visage sont prévus via l’utilisation d’algorithmes statistiques. Ils peuvent ne pas toujours être exacts. Soyez prudent lorsque vous prenez des décisions basées sur les données d’attribut. Veuillez-vous abstenir d’utiliser ces attributs pour la lutte contre l’usurpation d’identité numérique. À la place, nous recommandons d’utiliser la détection d’activité faciale. Pour plus d’informations, consultez Tutoriel : Détecter l’activité faciale.

Faire pivoter le rectangle de visage

Le rectangle de visage, retourné avec chaque visage détecté, marque l’emplacement et la taille du visage dans l’image. Par défaut, ce rectangle est toujours aligné avec l’image (ses côtés sont verticaux et horizontaux). Cela peut s’avérer inefficace pour encadrer des visages qui n’apparaissent pas en entier. Dans les situations où vous souhaitez découper programmatiquement des visages dans une image, il est préférable d’être en mesure de faire pivoter le rectangle à rogner.

L’exemple d’application WPF (Windows Presentation Foundation) Azure AI Visage utilise l’attribut HeadPose pour faire pivoter ses rectangles de visages détectés.

Explorer l’exemple de code

Vous pouvez faire pivoter programmatiquement le rectangle de visage à l’aide de l’attribut HeadPose. Si vous spécifiez cet attribut lors de la détection des visages (voir Appeler l’API de détection), vous serez en mesure de l’interroger plus tard. La méthode suivante à partir de l’application WPF Azure AI Visage accepte une liste d’objets DetectedFace et retourne une liste d’objets Face. Ici, Face est une classe personnalisée qui stocke les données de visage, notamment les coordonnées actualisées du rectangle. De nouvelles valeurs sont calculées pour top, left, width et height, et un nouveau champ FaceAngle spécifie la rotation.

/// <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,
        };
    }
}

Afficher le rectangle actualisé

À ce stade, vous pouvez utiliser les objets Face retournés dans votre affichage. Les lignes suivantes de FaceDetectionPage.xaml montrent comment le nouveau rectangle est rendu à partir de ces données :

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

Étapes suivantes

  • Consultez l’application WPF Azure AI Visage sur GitHub pour obtenir un exemple opérationnel de rotation de rectangles de visages.
  • Vous pouvez aussi consulter l’application Exemple HeadPose du service Visage, qui permet de suivre en temps réel l’attribut HeadPose pour détecter les mouvements de tête.