Source code for lunavl.sdk.estimators.face_estimators.head_pose
"""
Module contains a head pose estimator.
See `head pose`_.
"""
from enum import Enum
from typing import Dict
from FaceEngine import IHeadPoseEstimatorPtr, HeadPoseEstimation, FrontalFaceType # pylint: disable=E0611,E0401
from lunavl.sdk.errors.errors import LunaVLError
from lunavl.sdk.errors.exceptions import LunaSDKException, CoreExceptionWarp
from lunavl.sdk.estimators.base_estimation import BaseEstimation, BaseEstimator
from lunavl.sdk.faceengine.facedetector import Landmarks68, BoundingBox
from lunavl.sdk.image_utils.image import VLImage
[docs]class FrontalType(Enum):
"""
Enum for frontal types
"""
TURNED = "FrontalFace0" #: Non-frontal face
FRONTAL = "FrontalFace1" #: Good for recognition; Doesn't descrease recall and looks fine
BY_GOST = "FrontalFace2" #: GOST/ISO angles
@classmethod
def fromCoreFrontalType(cls, frontalFaceType: FrontalFaceType) -> 'FrontalType':
"""
Create frontal type by core frontal type
Args:
frontalFaceType: core frontal type
Returns:
frontal type
"""
frontalType = cls(frontalFaceType.name)
return frontalType
def __repr__(self):
return self.value
[docs]class HeadPose(BaseEstimation):
"""
Head pose. Estimate Tait–Bryan angles for head (https://en.wikipedia.org/wiki/Euler_angles#Tait–Bryan_angles).
Estimation properties:
- pitch
- roll
- yaw
"""
# pylint: disable=W0235
def __init__(self, coreHeadPose: HeadPoseEstimation):
"""
Init.
Args:
coreHeadPose: core head pose estimation.
"""
super().__init__(coreHeadPose)
@property
def yaw(self) -> float:
"""
Get the yaw angle.
Returns:
float in range(0, 1)
"""
return self._coreEstimation.yaw
@property
def pitch(self) -> float:
"""
Get the pitch angle.
Returns:
float in range(0, 1)
"""
return self._coreEstimation.pitch
@property
def roll(self) -> float:
"""
Get the pitch angle.
Returns:
float in range(0, 1)
"""
return self._coreEstimation.roll
[docs] def asDict(self) -> Dict[str, float]:
"""
Convert angles to dict.
Returns:
{"pitch": self.pitch, "roll": self.roll, "yaw": self.yaw}
"""
return {"pitch": self.pitch, "roll": self.roll, "yaw": self.yaw}
[docs] def getFrontalType(self) -> FrontalType:
"""
Get frontal type of head pose estimation.
Returns:
frontal type
"""
return FrontalType.fromCoreFrontalType(self._coreEstimation.getFrontalFaceType())
[docs]class HeadPoseEstimator(BaseEstimator):
"""
HeadPoseEstimator.
"""
# pylint: disable=W0235
def __init__(self, coreHeadPoseEstimator: IHeadPoseEstimatorPtr):
"""
Init.
Args:
coreHeadPoseEstimator: core estimator
"""
super().__init__(coreHeadPoseEstimator)
[docs] @CoreExceptionWarp(LunaVLError.EstimationAGSError)
def estimateBy68Landmarks(self, landmarks68: Landmarks68) -> HeadPose:
"""
Estimate head pose by 68 landmarks.
Args:
landmarks68: landmarks68
Returns:
estimate head pose
Raises:
LunaSDKException: if estimation is failed
"""
error, headPoseEstimation = self._coreEstimator.estimate(landmarks68.coreEstimation)
if error.isError:
raise LunaSDKException(LunaVLError.fromSDKError(error))
return HeadPose(headPoseEstimation)
# pylint: disable=W0221
[docs] def estimate(self, landmarks68: Landmarks68) -> HeadPose:
"""
Realize interface of a abstract estimator. Call estimateBy68Landmarks
"""
return self.estimateBy68Landmarks(landmarks68)
[docs] @CoreExceptionWarp(LunaVLError.EstimationHeadPoseError)
def estimateByBoundingBox(self, detection: BoundingBox, imageWithDetection: VLImage) -> HeadPose:
"""
Estimate head pose by detection.
Args:
detection: detection bounding box
imageWithDetection: image with the detection.
Returns:
estimate head pose
Raises:
LunaSDKException: if estimation is failed
"""
error, headPoseEstimation = self._coreEstimator.estimate(imageWithDetection.coreImage, detection.coreEstimation)
if error.isError:
raise LunaSDKException(LunaVLError.fromSDKError(error))
return HeadPose(headPoseEstimation)