Usar o atributo HeadPose

Neste guia, você verá como usar o atributo HeadPose de um rosto detectado para habilitar alguns cenários importantes.

Importante

Os atributos de rosto são previstos por meio do uso de algoritmos estatísticos. Eles podem não ser precisos todas as vezes. Tenha cautela ao tomar decisões com base nos dados de atributo. Evite usar esses atributos para proteção contra falsificação. Em vez disso, recomendamos usar a detecção do Face Liveness. Para obter mais informações, consulte o Tutorial: Detectar atividades em rostos.

Girar o retângulo facial

O retângulo facial, retornado com cada rosto detectado, marca a localização e o tamanho do rosto na imagem. Por padrão, o retângulo é sempre alinhado com a imagem (os lados são vertical e horizontal); isso pode ser ineficiente para o enquadramento de rostos angulares. Em situações em que você deseja cortar rostos de maneira programática em uma imagem, é melhor poder girar o retângulo para fazer o corte.

O aplicativo de exemplo do Windows Presentation Foundation (WPF) de Detecção Facial da IA do Azure usa o atributo HeadPose para girar os retângulos faciais detectados.

Explorar o código de exemplo

Você pode girar o retângulo facial de maneira programática usando o atributo HeadPose. Se você especificar esse atributo ao detectar rostos (confira Chamar a API de detecção), poderá consultá-lo mais tarde. O método a seguir do aplicativo WPF de Detecção Facial da IA do Azure usa uma lista de objetos DetectedFace e retorna uma lista de objetos Face. Face aqui é uma classe personalizada que armazena dados faciais, incluindo as coordenadas de retângulo atualizadas. Os novos valores são calculados para parte superior, esquerda, largura e altura, e um novo campo FaceAngle especifica a rotação.

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

Exibir o retângulo atualizado

Aqui, você pode usar os objetos Face na exibição. As seguintes linhas de FaceDetectionPage.xaml mostram como o novo retângulo é renderizado com base nesses dados:

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

Próximas etapas