|
|
|
|
|
|
|
|
|
|
|
|
|
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] |
|
] |
|
|
|
feature_ratios_indices=[ |
|
["forehead",67,69,66], |
|
["forehead",10,151,9], |
|
["forehead",297,299,296], |
|
|
|
|
|
["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:]) |
|
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:]) |
|
result_ratios.append(ratios_cordinates(points_cordinate)) |
|
cordinates.append(points_cordinate) |
|
return cordinates,result_ratios |
|
|
|
|
|
|
|
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:]) |
|
cordinates.append(points_cordinate) |
|
angle_rad =angle_between_points_and_x_axis(points_cordinate[0][:2],points_cordinate[1][:2]) |
|
|
|
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:]) |
|
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:]) |
|
cordinates.append(points_cordinate) |
|
angle_rad =angle_between_points_and_x_axis(points_cordinate[0][:2],points_cordinate[2][:2]) |
|
|
|
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 |