Gunakan atribut HeadPose

Dalam panduan ini, Anda akan melihat cara menggunakan atribut HeadPose dari wajah yang terdeteksi untuk mengaktifkan beberapa skenario utama.

Penting

Atribut wajah diprediksi melalui penggunaan algoritma statistik. Atribut tersebut mungkin tidak selalu akurat. Hati-hati saat membuat keputusan berdasarkan data atribut. Harap jangan menggunakan atribut ini untuk anti-spoofing. Sebagai gantinya, sebaiknya gunakan deteksi Face Liveness. Untuk informasi selengkapnya, silakan merujuk ke Tutorial: Mendeteksi keaktivan di wajah.

Memutar persegi wajah

Persegi wajah, dikembalikan dengan setiap wajah yang terdeteksi, menandai lokasi dan ukuran wajah dalam gambar. Secara default, persegi selalu sejajar dengan gambar (sisinya vertikal dan horizontal); ini bisa tidak efisien untuk membingkai wajah bersudut. Dalam situasi di mana Anda ingin secara terprogram memotong wajah dalam gambar, sebaiknya putar persegi untuk memotong.

Aplikasi sampel Azure AI Face WPF (Windows Presentation Foundation) menggunakan atribut HeadPose untuk memutar persegi wajah yang terdeteksi.

Menjelajahi kode sampel

Anda dapat memutar persegi wajah secara terprogram dengan menggunakan atribut HeadPose. Jika Anda menentukan atribut ini saat mendeteksi wajah (lihat Memanggil API pendeteksi), Anda akan dapat menanyakannya nanti. Metode berikut dari aplikasi Azure AI Face WPF mengambil daftar objek DetectedFace dan mengembalikan daftar objek Face . Wajah di sini adalah kelas kustom yang menyimpan data wajah, termasuk koordinat persegi yang diperbarui. Nilai baru dihitung untuk atas, kiri, lebar, dan tinggi, dan bidang baru FaceAngle menentukan rotasi.

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

Menampilkan persegi yang diperbarui

Dari sini, Anda dapat menggunakan objek Wajah yang dikembalikan di layar. Baris berikut dari FaceDetectionPage.xaml memperlihatkan bagaimana persegi baru dirender dari data ini:

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

Langkah berikutnya