juras3k's picture
Deploy backend API to HF Space
c4ba2f9
Raw
History Blame Contribute Delete
3.68 kB
import numpy as np
class FaceGeometry:
def __init__(self, landmarks, hairline_y=None):
self.lm = landmarks
self.hairline_y = hairline_y
def _p(self, idx):
return self.lm[idx][:2]
def chin(self):
return self._p(152)
def nose(self):
return self._p(1)
def left_cheek(self):
return self._p(234)
def right_cheek(self):
return self._p(454)
def left_eye(self):
return self._p(33)
def right_eye(self):
return self._p(263)
def forehead_top(self):
if self.hairline_y is not None:
mid_x = (self._p(234)[0] + self._p(454)[0]) / 2
return np.array([mid_x, self.hairline_y])
return self._p(10)
def dist(self, a, b):
return np.linalg.norm(a - b)
def face_height(self):
return self.dist(self.chin(), self.forehead_top())
def face_width(self):
return self.dist(self.left_cheek(), self.right_cheek())
def jaw_width(self):
return self.dist(self._p(172), self._p(397))
def eye_dist(self):
return self.dist(self.left_eye(), self.right_eye())
def nose_position_ratio(self):
return (self.nose()[1] - self.forehead_top()[1]) / self.face_height()
def face_ratio(self):
return self.face_height() / self.face_width()
def jaw_ratio(self):
return self.jaw_width() / self.face_width()
def symmetry_score(self):
mid = (self._p(33) + self._p(263)) / 2
left_dist = np.linalg.norm(self._p(234) - mid)
right_dist = np.linalg.norm(self._p(454) - mid)
return abs(left_dist - right_dist) / self.face_width()
def jaw_to_height(self):
return self.jaw_width() / self.face_height()
def eye_ratio(self):
return self.eye_dist() / self.face_width()
def eye_height(self):
eye_h = self.dist(self._p(159), self._p(145))
eye_w = self.dist(self._p(33), self._p(133))
return eye_h / eye_w
def lip_ratio(self):
return self.dist(self._p(61), self._p(291)) / self.face_width()
def chin_ratio(self):
return self.dist(self._p(152), self._p(175)) / self.face_height()
def forehead_ratio(self):
forehead_h = self.dist(self.forehead_top(), self._p(10))
return forehead_h / self.face_height()
def lower_face_ratio(self):
mouth = self._p(0)
return self.dist(mouth, self.chin()) / self.face_height()
def chin_prominence(self):
jaw_mid = (self._p(172) + self._p(397)) / 2
return self.dist(jaw_mid, self.chin()) / self.face_height()
def brow_line_y(self):
left_brow = self._p(55)
right_brow = self._p(285)
return (left_brow[1] + right_brow[1]) / 2
def nose_base_y(self):
return self._p(2)[1]
def upper_third(self):
top = self.forehead_top()[1]
return abs(self.brow_line_y() - top)
def middle_third(self):
return abs(self.nose_base_y() - self.brow_line_y())
def lower_third(self):
return abs(self.chin()[1] - self.nose_base_y())
def facial_thirds_ratio(self):
u = self.upper_third()
m = self.middle_third()
l = self.lower_third()
total = u + m + l
if total == 0:
return None
return {
"upper": round(u / total, 3),
"middle": round(m / total, 3),
"lower": round(l / total, 3),
}
def middle_lower_ratio(self):
m = self.middle_third()
l = self.lower_third()
return m / l if l > 0 else 1.0