Verwenden des HeadPose-Attributs

In dieser Anleitung erfahren Sie, wie Sie das HeadPose-Attribut eines erkannten Gesichts verwenden können, um einige wichtige Szenarien umzusetzen.

Wichtig

Gesichtsattribute werden mithilfe statistischer Algorithmen vorhergesagt. Sie sind möglicherweise nicht immer genau. Treffen Sie Entscheidungen auf Grundlage von Attributdaten mit Umsicht. Verzichten Sie darauf, diese Attribute für Spoofingbekämpfung zu verwenden. Wir empfehlen stattdessen die Face Liveness-Erkennung. Weitere Informationen finden Sie unter Tutorial: Erkennen von Face Liveness.

Drehen des Gesichtsrechtecks

Das Gesichtsrechteck, das bei jedem erkannten Gesicht zurückgegeben wird, markiert die Position und Größe des Gesichts im Bild. Standardmäßig ist das Rechteck immer mit dem Bild ausgerichtet (seine Seiten sind vertikal und horizontal). Dies kann für das Umrahmen von abgewinkelten bzw. geneigten Gesichtern ineffizient sein. In Situationen, in denen Sie programmgesteuert Gesichter in einem Bild zuschneiden möchten, ist es besser, das Rechteck für den Zuschnitt drehen zu können.

Die Beispiel-App für die Azure KI-Gesichtserkennung für WPF (Windows Presentation Foundation) verwendet das HeadPose-Attribut, um die Rechtecke der erkannten Gesichter zu drehen.

Untersuchen des Beispielcodes

Sie können das Gesichtsrechteck programmgesteuert drehen, indem Sie das HeadPose-Attribut verwenden. Wenn Sie dieses Attribut bei der Gesichtserkennung angeben (siehe Aufrufen der Erkennungs-API), können Sie es später abfragen. Die folgende Methode aus der App Azure KI-Gesichtserkennung für WPF nimmt eine Liste von DetectedFace-Objekten und gibt eine Liste von Objekten für die Gesichtserkennung zurück: Face ist hier eine benutzerdefinierte Klasse, die Gesichtsdaten speichert, einschließlich der aktualisierten Rechteckkoordinaten. Neue Werte werden für top (oben), left (links), width (Breite) und height (Höhe) berechnet, und ein neues Feld FaceAngle gibt die Drehung an.

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

Anzeigen des aktualisierten Rechtecks

Von hier aus können Sie die zurückgegebenen Face-Objekte in Ihrer Anzeige verwenden. Die folgenden Zeilen aus FaceDetectionPage.xaml zeigen, wie das neue Rechteck aus diesen Daten gerendert wird:

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

Nächste Schritte