Skip to content

Commit 1c0db22

Browse files
committed
Create and load a calibration file
1 parent abc026b commit 1c0db22

File tree

3 files changed

+80
-53
lines changed

3 files changed

+80
-53
lines changed

Sports2D/Demo/Config_demo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,15 +103,17 @@ max_distance = 100 # in px or None # If a person is detected further than max_d
103103
# Pixel to meters conversion
104104
to_meters = true
105105
make_c3d = true
106-
save_calib = false
106+
save_calib = true
107107

108108
# If conversion from first_person_height
109109
floor_angle = 'auto' # 'auto' or a value in degrees, eg 2.3. If 'auto', estimated from the line formed by the toes when they are on the ground (where speed = 0)
110110
xy_origin = ['auto'] # ['auto'] or [px_x,px_y]. N.B.: px_y points downwards. If ['auto'], direction estimated from the start to the end of the line formed by the toes when they are on the ground
111111

112112
# If conversion from a calibration file
113113
calib_file = '' # Calibration in the Pose2Sim format. 'calib_demo.toml', or '' if not available
114-
114+
# subject_distance
115+
# focal_distance
116+
# recalculate_extrinsics
115117

116118
[angles]
117119
display_angle_values_on = ['body', 'list'] # 'body', 'list', ['body', 'list'], 'none'. Display angle values on the body, as a list in the upper left of the image, both, or do not display them.

Sports2D/Sports2D.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@
197197
'calib_file': '',
198198
'floor_angle': 'auto',
199199
'xy_origin': ['auto'],
200-
'save_calib': False
200+
'save_calib': True
201201
},
202202
'angles': {'display_angle_values_on': ['body', 'list'],
203203
'fontSize': 0.3,

Sports2D/process.py

Lines changed: 75 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
from Sports2D.Utilities.common import *
8484
from Pose2Sim.common import *
8585
from Pose2Sim.skeletons import *
86+
from Pose2Sim.calibration import toml_write
8687
from Pose2Sim.triangulation import indices_of_first_last_non_nan_chunks
8788
from Pose2Sim.personAssociation import *
8889
from 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('\nConverting 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

Comments
 (0)