facial_beauty_analysis / facial_image.py
VladyslavTalakh
examples
6f90f9d
from math import dist
import cv2
import mediapipe as mp
from points import points
from ratios import Ratios
from utils import *
def convert_to_numpy_array(ratios: dict[str, float]) -> numpy.array:
arr = []
for k, v in ratios.items():
arr.append(v)
return numpy.array(arr)
class FacialImage:
def __init__(self):
self.landmarks = []
self.width = 0
self.height = 0
def get_point_coordinates(self, point_num):
point = self.landmarks[point_num]
return point.x * self.width, point.y * self.height
def get_distance_two_points(self, point_num_1, point_num_2):
first = self.get_point_coordinates(point_num_1)
second = self.get_point_coordinates(point_num_2)
return dist(first, second)
def get_ratio_between_two(self, ratio1_name, ratio2_name):
first = self.get_distance_two_points(points[ratio1_name][0], points[ratio1_name][1])
second = self.get_distance_two_points(points[ratio2_name][0], points[ratio2_name][1])
return first / second
def get_landmarks(self, image: numpy.ndarray):
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh()
# Image
height, width, _ = image.shape
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# Facial landmarks
result = face_mesh.process(rgb_image)
for facial_landmarks in result.multi_face_landmarks:
for i in range(0, 468):
pt1 = facial_landmarks.landmark[i]
x = int(pt1.x * width)
y = int(pt1.y * height)
cv2.circle(image, (x, y), 1, (255, 0, 0), -1)
self.landmarks = result.multi_face_landmarks[0].landmark
self.width = width
self.height = height
def calculate_ratios(self, image: numpy.ndarray, is_normalized=False):
self.get_landmarks(image)
ratios = {
'Under eyes/Interocular': self.get_ratio_between_two(Ratios.UNDER_EYES, Ratios.INTEROCULAR),
'Under eyes/Nose width': self.get_ratio_between_two(Ratios.UNDER_EYES, Ratios.NOSE_WIDTH),
'Mouth width/Interocular': self.get_ratio_between_two(Ratios.MOUTH_WIDTH, Ratios.INTEROCULAR),
'Upper lip-jaw/Interocular': self.get_ratio_between_two(Ratios.UPPER_LIP_TO_JAW, Ratios.INTEROCULAR),
'Upper lip-jaw/Nose width': self.get_ratio_between_two(Ratios.UPPER_LIP_TO_JAW, Ratios.NOSE_WIDTH),
'Interocular/Lip height': self.get_ratio_between_two(Ratios.INTEROCULAR, Ratios.LIPS_HEIGHT),
'Nose width/Interocular': self.get_ratio_between_two(Ratios.NOSE_WIDTH, Ratios.INTEROCULAR),
'Nose width/Upper lip height': self.get_ratio_between_two(Ratios.NOSE_WIDTH, Ratios.UPPER_LIP_HEIGHT),
'Interocular/Nose mouth height': self.get_ratio_between_two(Ratios.INTEROCULAR,
Ratios.NOSE_TO_MOUTH_HEIGHT),
'Face top-eyebrows/Eyebrows-Nose': self.get_ratio_between_two(Ratios.FACE_TOP_TO_EYEBROWS,
Ratios.EYEBROWS_TO_NOSE),
'Eyebrows-nose/Nose-jaw': self.get_ratio_between_two(Ratios.EYEBROWS_TO_NOSE, Ratios.NOSE_TO_JAW),
'Face top-eyebrows/Nose-Jaw': self.get_ratio_between_two(Ratios.FACE_TOP_TO_EYEBROWS, Ratios.NOSE_TO_JAW),
'Interocular/Nose width': self.get_ratio_between_two(Ratios.INTEROCULAR, Ratios.NOSE_WIDTH),
'Face height/Face width': self.get_ratio_between_two(Ratios.FACE_HEIGHT, Ratios.FACE_WIDTH),
'Lower eyebrow length': self.get_ratio_between_two(Ratios.LEFT_LOWER_EYEBROW_LENGTH,
Ratios.RIGHT_LOWER_EYEBROW_LENGTH),
'Lower lip length': self.get_ratio_between_two(Ratios.LEFT_LOWER_LIP_LENGTH, Ratios.RIGHT_LOWER_LIP_LENGTH),
'Upper eyebrow': self.get_ratio_between_two(Ratios.LEFT_UPPER_EYEBROW_LENGTH,
Ratios.RIGHT_UPPER_EYEBROW_LENGTH),
'Upper lip': self.get_ratio_between_two(Ratios.LEFT_UPPER_LIP_LENGTH, Ratios.RIGHT_UPPER_LIP_LENGTH),
'Nose': self.get_ratio_between_two(Ratios.LEFT_NOSE_WIDTH, Ratios.RIGHT_NOSE_WIDTH)
}
if is_normalized:
return normalization(ratios), image
return ratios, image