Akjava's picture
update
ff3c171
#2024-12-04 add forehead_chin_points_pair,estimate_rotatios
#formart is first,second,middle
#2024-12-05 deg to rad
#2024-12-06 get_feature_ratios_cordinate
#2024-12-08 create_detail_labels
#2024-12-14 ratio support 4point
horizontal_points_pair = [
[
"inner-eye",133,362,6
],
[
"outer-eye",33,263,168
],
[
"mouth",61,291,13
],
[
"eyeblow",105,334,9
],[
"nose",98,327,2
],[
"contour",143,372,6
],
[
"chin",32,262,200
], [
"cheek",123,352,5
], [
"cheek2",192,416,0
], [
"nose1",129,358,1
], [
"nose2",47,277,195
], [
"cheek3",206,426,2
], [
"cheek4",101,330,5
], [
"cheek5",153,380,6
]
]
def angle_between_points_and_x_axis(A, B):
"""
2点A, Bを結ぶ線分とx軸の正方向との角度を計算する
Args:
A: A点の座標 (x, y) のタプルまたはNumPy配列
B: B点の座標 (x, y) のタプルまたはNumPy配列
Returns:
角度(ラジアン)
"""
x = B[0] - A[0]
y = B[1] - A[1]
return np.arctan2(y, x)
vertical_points_pair=[
["forehead-chin",8,1,199]
]
#formart is first,second,third
feature_ratios_indices=[
["forehead",67,69,66],
["forehead",10,151,9],
["forehead",297,299,296],
#["forehead-chin",8,1,199],
#["middle-chin",168,199,2],
["middle",168,195,2],
["right",153,101,206],
["right2",133,47,129],
["left",380,330,426],
["left2",362,277,358],
["right-contour",143,123,192],
["left-contour",372,352,416],
["nose",4,1,2],
]
feature_angles_indices =[
["forehead1",9,6],
["forehead2",69,299],
["eyes1",133,362],
["eyes2",133,33],
["eyes3",362,263],
["nose1",6,2],
["nose1",98,327],
["nose1",2,1],
["nose1",1,6],
["lip",61,291],
["lip",0,17],
["jaw",152,199],
["jaw",194,418],
["cheek",118,214],
["cheek",347,434],
["contour",389,397],
["contour",127,172],
]
def get_feature_angles_cordinate(face_landmarks,angles=feature_angles_indices):
points = [get_normalized_cordinate(face_landmarks,i) for i in range(468)]
return get_feature_angles_cordinate_points(points,angles)
def get_feature_angles_cordinate_points(points,angles=feature_angles_indices):
cordinates=[]
result_angles = []
for indices in angles:
points_cordinate = get_points_by_indices(points,indices[1:])#first one is label
angle_rad =angle_between_points_and_x_axis(points_cordinate[0][:2],points_cordinate[1][:2])
result_angles.append(angle_rad)
cordinates.append(points_cordinate)
return cordinates,result_angles
def get_feature_ratios_cordinate(face_landmarks,ratios=feature_ratios_indices):
points = [get_normalized_cordinate(face_landmarks,i) for i in range(468)]
return get_feature_angles_cordinate_points(points,ratios)
def ratios_cordinates(cordinates):
distance_a = calculate_distance(cordinates[0],cordinates[1])
distance_b = calculate_distance(cordinates[-2],cordinates[-1])
if distance_a == 0 or distance_b == 0:
return 0
else:
return distance_a/distance_b
def get_feature_ratios_cordinate_points(points,ratios=feature_ratios_indices):
cordinates=[]
result_ratios = []
for indices in ratios:
points_cordinate = get_points_by_indices(points,indices[1:])#first one is label
result_ratios.append(ratios_cordinates(points_cordinate))
cordinates.append(points_cordinate)
return cordinates,result_ratios
#vertical-format
forehead_chin_points_pair=[
[
"forehead-chin",8,1,199
]
]
horizontal_contour_points_pair=[
[
"contour",143,6,372
]
]
import math
def calculate_distance(xy, xy2):
return math.sqrt((xy2[0] - xy[0])**2 + (xy2[1] - xy[1])**2)
def create_detail_labels(values,radian=False,pair_data=horizontal_points_pair):
assert len(values) == len(pair_data)
lines = []
for i,value in enumerate(values):
if radian:
value=math.degrees(value)
lines.append(f"{pair_data[i][0]} = {value:.2f}")
return "\n".join(lines)
import numpy as np
from mp_utils import get_normalized_cordinate
def estimate_horizontal(face_landmarks,pair_data = horizontal_points_pair):
points = [get_normalized_cordinate(face_landmarks,i) for i in range(468)]
return estimate_horizontal_points(points,pair_data)
def get_points_by_indices(face_landmark_points,indices):
points = [face_landmark_points[index] for index in indices]
return points
def normalized_to_pixel(cordinates,width,height):
pixel_point = [[pt[0]*width,pt[1]*height] for pt in cordinates]
return pixel_point
def estimate_horizontal_points(face_landmark_points,pair_data = horizontal_points_pair):
z_angles=[]
y_ratios = []
cordinates = []
for compare_point in pair_data:
points_cordinate = get_points_by_indices(face_landmark_points,compare_point[1:])#first one is label
cordinates.append(points_cordinate)
angle_rad =angle_between_points_and_x_axis(points_cordinate[0][:2],points_cordinate[1][:2])
#angle_deg = np.degrees(angle_rad)
z_angles.append(angle_rad)
right_distance = calculate_distance(points_cordinate[0],points_cordinate[2])
left_distance = calculate_distance(points_cordinate[1],points_cordinate[2])
y_ratios.append(left_distance/(right_distance+left_distance))
return z_angles,y_ratios,cordinates,pair_data
def estimate_vertical(face_landmarks,pair_data = vertical_points_pair):
points = [get_normalized_cordinate(face_landmarks,i) for i in range(468)]
return estimate_vertical_points(points,pair_data)
def estimate_rotations_v2(face_landmarker_result):
points = get_normalized_landmarks(face_landmarker_result.face_landmarks,True)
values1_text=estimate_rotations_point(points)
result3,ratios = get_feature_ratios_cordinate_points(points)
key_cordinates,angles = get_feature_angles_cordinate_points(points)
angles_str=[str(angle) for angle in angles]
ratios_str=[str(ratio) for ratio in ratios]
return f"{values1_text},{','.join(angles_str)},{','.join(ratios_str)}"
from mp_utils import get_normalized_landmarks
def estimate_rotations(face_landmarker_result):
points = get_normalized_landmarks(face_landmarker_result.face_landmarks,True)
return estimate_rotations_point(points)
def estimate_rotations_point(points):
z_angles,y_ratios,h_cordinates,_ =estimate_horizontal_points(points)
z_angle = np.mean(z_angles)
y_ratio = np.mean(y_ratios)
_,x_ratios,h_cordinates,_ =estimate_vertical_points(points)
x_ratio = np.mean(x_ratios)
x_angle,_,_,_ =estimate_vertical_points(points,forehead_chin_points_pair)
x_angle=np.mean(x_angle)
length_ratio = estimate_ratio(points)
result = f"{x_ratio:.6f},{y_ratio:.6f},{z_angle:.6f},{x_angle:.6f},{length_ratio:.6f}"
return result
def estimate_ratio(face_landmark_points,a_line=forehead_chin_points_pair,b_line=horizontal_contour_points_pair):
points_cordinate_a = get_points_by_indices(face_landmark_points,a_line[0][1:])#for campatible
points_cordinate_b = get_points_by_indices(face_landmark_points,b_line[0][1:])
distance_a = calculate_distance(points_cordinate_a[0],points_cordinate_a[2])
distance_b = calculate_distance(points_cordinate_b[0],points_cordinate_b[2])
if distance_a == 0 or distance_b == 0:
return 0
else:
return distance_a/distance_b
def estimate_vertical_points(face_landmarks,pair_data = vertical_points_pair):
angles = []
ratios = []
cordinates = []
for compare_point in pair_data:
points_cordinate = get_points_by_indices(face_landmarks,compare_point[1:])#first one is label
cordinates.append(points_cordinate)
angle_rad =angle_between_points_and_x_axis(points_cordinate[0][:2],points_cordinate[2][:2])
#angle_deg = np.degrees(angle_rad)
angles.append(angle_rad)
up_distance = calculate_distance(points_cordinate[0],points_cordinate[1])
down_distance = calculate_distance(points_cordinate[1],points_cordinate[2])
ratios.append(down_distance/(down_distance+up_distance))
return angles,ratios,cordinates,pair_data
def mean_std_label(values,radian=False):
mean_value = np.mean(values)
std_value = np.std(values)
if radian:
mean_value = math.degrees(mean_value)
std_value = math.degrees(std_value)
value_text = f"mean:{mean_value:.3f} std:{std_value:.3f}"
return value_text