#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]) print(distance_a) distance_b = calculate_distance(cordinates[-2],cordinates[-1]) print(distance_b) 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