8383from Sports2D .Utilities .common import *
8484from Pose2Sim .common import *
8585from Pose2Sim .skeletons import *
86+ from Pose2Sim .calibration import toml_write
8687from Pose2Sim .triangulation import indices_of_first_last_non_nan_chunks
8788from Pose2Sim .personAssociation import *
8889from Pose2Sim .filtering import *
@@ -1476,8 +1477,12 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
14761477 save_calib = config_dict .get ('px_to_meters_conversion' ).get ('save_calib' )
14771478 # Calibration from file
14781479 calib_file = config_dict .get ('px_to_meters_conversion' ).get ('calib_file' )
1479- if calib_file == '' : calib_file = None
1480- else : calib_file = Path (calib_file ).resolve ()
1480+ if calib_file == '' :
1481+ calib_file = None
1482+ else :
1483+ calib_file = video_dir / calib_file
1484+ if not calib_file .is_file ():
1485+ raise FileNotFoundError (f'Error: Could not find calibration file { calib_file } . Check that the file exists.' )
14811486 # Calibration from person height
14821487 floor_angle = config_dict .get ('px_to_meters_conversion' ).get ('floor_angle' ) # 'auto' or float
14831488 floor_angle = np .radians (float (floor_angle )) if floor_angle != 'auto' else floor_angle
@@ -2107,16 +2112,47 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
21072112 trc_data_m = []
21082113 if to_meters and save_pose :
21092114 logging .info ('\n Converting pose to meters:' )
2115+
2116+ # Compute height in px of the first person
2117+ height_px = compute_height (trc_data [0 ].iloc [:,1 :], new_keypoints_names ,
2118+ fastest_frames_to_remove_percent = fastest_frames_to_remove_percent , close_to_zero_speed = close_to_zero_speed_px , large_hip_knee_angles = large_hip_knee_angles , trimmed_extrema_percent = trimmed_extrema_percent )
2119+
2120+ if calib_file or save_calib :
2121+ dist_to_cam = 10.0 # arbitrary distance between the camera and the person (m)
2122+ R90z = np .array ([[0.0 , - 1.0 , 0.0 ],
2123+ [1.0 , 0.0 , 0.0 ],
2124+ [0.0 , 0.0 , 1.0 ]])
2125+ R270x = np .array ([[1.0 , 0.0 , 0.0 ],
2126+ [0.0 , 0.0 , 1.0 ],
2127+ [0.0 , - 1.0 , 0.0 ]])
2128+
2129+ # Compute px to meter parameters from calibration file
21102130 if calib_file :
2111- logging .info (f'Using calibration file to convert coordinates in meters: { calib_file } .' )
21122131 calib_params_dict = retrieve_calib_params (calib_file )
2113- # TODO
21142132
2115- else :
2116- # Compute calibration parameters
2117- height_px = compute_height (trc_data [0 ].iloc [:,1 :], new_keypoints_names ,
2118- fastest_frames_to_remove_percent = fastest_frames_to_remove_percent , close_to_zero_speed = close_to_zero_speed_px , large_hip_knee_angles = large_hip_knee_angles , trimmed_extrema_percent = trimmed_extrema_percent )
2133+ f = calib_params_dict ['K' ][0 ][0 ][0 ]
2134+ first_person_height = height_px / f * dist_to_cam
21192135
2136+ R_cam = cv2 .Rodrigues (calib_params_dict ['R' ][0 ])[0 ]
2137+ T_cam = np .array (calib_params_dict ['T' ][0 ])
2138+ R_world , T_world = world_to_camera_persp (R_cam , T_cam )
2139+ Rfloory = R90z .T @ R_world @ R270x .T
2140+ T_world = R90z .T @ T_world
2141+ floor_angle_estim = np .arctan2 (Rfloory [0 ,2 ], Rfloory [0 ,0 ])
2142+
2143+ cu = calib_params_dict ['K' ][0 ][0 ][2 ]
2144+ cv = calib_params_dict ['K' ][0 ][1 ][2 ]
2145+ cx = 0.0
2146+ cy = cv + T_world [2 ]* f / dist_to_cam
2147+ xy_origin_estim = [cx , cy ]
2148+
2149+ logging .info (f'Using calibration file to convert coordinates in meters: { calib_file } .\n '
2150+ f'Floor angle: { np .degrees (floor_angle_estim ):.2f} °, '
2151+ f'xy_origin: [{ cx :.2f} , { cy :.2f} ] px.' )
2152+
2153+
2154+ # Compute px to meter parameters from scene
2155+ else :
21202156 toe_speed_below = 1 # m/s (below which the foot is considered to be stationary)
21212157 px_per_m = height_px / first_person_height
21222158 toe_speed_below_px_frame = toe_speed_below * px_per_m / fps
@@ -2142,6 +2178,37 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
21422178 logging .info (f'Using height of person #0 ({ first_person_height } m) to convert coordinates in meters.\n '
21432179 f'Floor angle: { np .degrees (floor_angle_estim ) if not floor_angle == "auto" else f"auto (estimation: { round (np .degrees (floor_angle_estim ),2 )} °)" } , '
21442180 f'xy_origin: { xy_origin if not xy_origin == "auto" else f"auto (estimation: { [round (c ) for c in xy_origin_estim ]} )" } px.' )
2181+
2182+ # Save calibration file
2183+ if save_calib :
2184+ calib_file_path = output_dir / f'{ video_file_stem } _Sports2D_calib.toml'
2185+
2186+ # name, size, distortions
2187+ N = [video_file_stem ]
2188+ S = [[cam_width , cam_height ]]
2189+ D = [[0.0 , 0.0 , 0.0 , 0.0 ]]
2190+
2191+ # Intrinsics
2192+ f = height_px / first_person_height * dist_to_cam
2193+ cu = cam_width / 2
2194+ cv = cam_height / 2
2195+ K = np .array ([[[f , 0.0 , cu ], [0.0 , f , cv ], [0.0 , 0.0 , 1.0 ]]])
2196+
2197+ # Extrinsics
2198+ Rfloory = np .array ([[np .cos (floor_angle_estim ), 0.0 , np .sin (floor_angle_estim )],
2199+ [0.0 , 1.0 , 0.0 ],
2200+ [- np .sin (floor_angle_estim ), 0.0 , np .cos (floor_angle_estim )]])
2201+ R_world = R90z @ Rfloory @ R270x
2202+ T_world = R90z @ np .array ([- (cx - cu )/ f * dist_to_cam , - dist_to_cam , (cy - cv )/ f * dist_to_cam ])
2203+
2204+ R_cam , T_cam = world_to_camera_persp (R_world , T_world )
2205+ Tvec_cam = T_cam .reshape (1 ,3 ).tolist ()
2206+ Rvec_cam = cv2 .Rodrigues (R_cam )[0 ].reshape (1 ,3 ).tolist ()
2207+
2208+ # Write calibration file
2209+ toml_write (calib_file_path , N , S , D , K , Rvec_cam , Tvec_cam )
2210+ logging .info (f'Calibration saved to { calib_file_path } .' )
2211+
21452212
21462213 # Coordinates in m
21472214 new_visible_side = []
@@ -2206,48 +2273,6 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir):
22062273 new_visible_side += [visible_side_i ]
22072274 else :
22082275 new_visible_side = visible_side .copy ()
2209-
2210-
2211-
2212-
2213-
2214-
2215- # # plt.plot(trc_data_m.iloc[:,0], trc_data_m.iloc[:,1])
2216- # # plt.ylim([0,2])
2217- # # plt.show()
2218-
2219-
2220-
2221- # z = 3.0 # distance between the camera and the person. Required in the calibration file but simplified in the equations
2222- # f = height_px / first_person_height * z
2223-
2224-
2225- # # Name
2226- # N = [video_file]
2227-
2228- # # Size
2229- # S = [[cam_width, cam_height]]
2230-
2231- # # Distortions
2232- # D = [[0.0, 0.0, 0.0, 0.0]]
2233-
2234- # # Camera matrix
2235- # K = [[[f, 0.0, cx], [0.0, f, cy], [0.0, 0.0, 1.0]]] # f and Z do not matter in 2D
2236-
2237- # # Rot, Trans
2238- # R =
2239- # T =
2240-
2241- # # Save calibration file
2242-
2243- # # Convert to meters
2244- # trc_data =
2245-
2246-
2247-
2248-
2249-
2250-
22512276
22522277
22532278 #%% ==================================================
0 commit comments