Everything works properly

This commit is contained in:
davidpagnon 2023-08-20 21:55:13 +02:00
parent b08bba12a0
commit 7e861db257
89 changed files with 219 additions and 290 deletions

BIN
Content/Calib_int.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 600 KiB

View File

@ -5,7 +5,7 @@
# Configure your project parameters here # Configure your project parameters here
[project] [project]
project_dir = 'D:\softs\github_david\pose2sim\Pose2Sim\Demo' # BETWEEN SINGLE QUOTES! # If empty, project dir is current dir project_dir = '' # BETWEEN SINGLE QUOTES! # If empty, project dir is current dir
frame_range = [] #For example [10,300], or [] for all frames frame_range = [] #For example [10,300], or [] for all frames
frame_rate = 60 #Hz frame_rate = 60 #Hz
@ -26,7 +26,7 @@ pose_model = 'BODY_25B' #CUSTOM, BODY_25B, BODY_25, BODY_135, BLAZEPOSE, HALPE_2
[calibration] [calibration]
calibration_type = 'calculate' # 'convert' or 'calculate' calibration_type = 'convert' # 'convert' or 'calculate'
[calibration.convert] [calibration.convert]
convert_from = 'qualisys' # 'qualisys', 'optitrack', or 'vicon' convert_from = 'qualisys' # 'qualisys', 'optitrack', or 'vicon'
@ -41,10 +41,9 @@ calibration_type = 'calculate' # 'convert' or 'calculate'
intrinsics_board_type = 'checkerboard' # 'checkerboard' ('charucoboard' not supported yet) intrinsics_board_type = 'checkerboard' # 'checkerboard' ('charucoboard' not supported yet)
overwrite_intrinsics = false # overwrite (or not) if they have already been calculated? overwrite_intrinsics = false # overwrite (or not) if they have already been calculated?
show_detection_intrinsics = true # true or false (lowercase) show_detection_intrinsics = true # true or false (lowercase)
intrinsics_extension = 'jpg' # any video or image extension intrinsics_extension = 'jpg' # any video or image extension
extract_every_N_sec = 1 # if video, extract frames every N seconds (can be <1 )
extract_every_N_sec = 1 # if video, extract frames every N seconds (can be <1 )
intrinsics_corners_nb = [4,7] intrinsics_corners_nb = [4,7]
intrinsics_square_size = 60 # mm intrinsics_square_size = 60 # mm
intrinsics_marker_size = 40 # mm # only checked if charucoboard intrinsics_marker_size = 40 # mm # only checked if charucoboard
@ -56,7 +55,6 @@ calibration_type = 'calculate' # 'convert' or 'calculate'
# 'scene' involves manually clicking any point of know coordinates on scene. Usually more accurate if points are spread out # 'scene' involves manually clicking any point of know coordinates on scene. Usually more accurate if points are spread out
calculate_extrinsics = true # true or false (lowercase) calculate_extrinsics = true # true or false (lowercase)
show_reprojection_error = true # true or false (lowercase) show_reprojection_error = true # true or false (lowercase)
extrinsics_extension = 'png' # any video or image extension extrinsics_extension = 'png' # any video or image extension
# if extrinsics_board_type = 'checkerboard' or 'charucoboard' # if extrinsics_board_type = 'checkerboard' or 'charucoboard'
@ -87,7 +85,8 @@ likelihood_threshold = 0.3
min_cameras_for_triangulation = 2 min_cameras_for_triangulation = 2
interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none
# 'none' if you don't want to interpolate missing points # 'none' if you don't want to interpolate missing points
show_interp_indices = false # true or false (lowercase). For each keypoint, return the frames that need to be interpolated interp_if_gap_smaller_than = 10 # do not interpolate bigger gaps
show_interp_indices = true # true or false (lowercase). For each keypoint, return the frames that need to be interpolated
[filtering] [filtering]

View File

@ -1,5 +1,5 @@
############################################################################### ###############################################################################
## POSE2SIM PROJECT PARAMETERS ## ## PROJECT PARAMETERS ##
############################################################################### ###############################################################################
# Configure your project parameters here # Configure your project parameters here
@ -9,45 +9,78 @@ project_dir = '' # BETWEEN SINGLE QUOTES! # If empty, project dir is current dir
frame_range = [0,10] #For example [10,300], or [] for all frames frame_range = [0,10] #For example [10,300], or [] for all frames
frame_rate = 60 #Hz frame_rate = 60 #Hz
rawImg_folder_name = 'raw-2d' rawImg_folder_name = 'raw'
calib_folder_name = 'calibration' calib_folder_name = 'calibration'
pose_folder_name = 'pose' pose_folder_name = 'pose'
pose_json_folder_extension = 'json' pose_json_folder_extension = 'json'
pose_img_folder_extension = 'img' pose_img_folder_extension = 'img'
poseTracked_folder_name = 'pose-2d-tracked' poseAssociated_folder_name = 'pose-associated'
pose3d_folder_name = 'triangulation' pose3d_folder_name = 'pose-3d'
opensim_folder_name = 'opensim' opensim_folder_name = 'opensim'
[pose] [pose]
pose_model = 'BODY_25B' #CUSTOM, BODY_25B, BODY_25, BODY_135, BLAZEPOSE, pose_model = 'BODY_25B' #CUSTOM, BODY_25B, BODY_25, BODY_135, BLAZEPOSE, HALPE_26, HALPE_68, HALPE_136, COCO_133, COCO, MPII are available,
# HALPE_26, HALPE_68, HALPE_136, COCO_133, COCO, MPII are available,
# from DeepLabCut, OpenPose, MediaPipe BlazePose, and AlphaPose # from DeepLabCut, OpenPose, MediaPipe BlazePose, and AlphaPose
# See Pose2Sim\skeleton.py for their skeleton hierarchy # See Pose2Sim\skeleton.py for their skeleton hierarchy
[calibration] [calibration]
type = 'qca' # 'qca', 'checkerboard', 'arucoboard', or 'charucoboard' calibration_type = 'convert' # 'convert' or 'calculate'
[calibration.qca]
binning_factor = 1 # Usually 1, except when filming in 540p where it usually is 2
[calibration.checkerboard] [calibration.convert]
corners_nb = [7,12] # [H,W] rather than [w,h] convert_from = 'qualisys' # 'qualisys', 'optitrack', or 'vicon'
square_size = 80 # mm # [h,w] if square is actually a rectangle [calibration.convert.qualisys]
frame_for_origin = -1 # starting from zero. -1 if board is at origin on last frame binning_factor = 1 # Usually 1, except when filming in 540p where it usually is 2
# /!\ Beware that corners must be detected on all view at frame_for_origin, or else
# extrinsic parameters will be wrong. Set show_corner_detection to true to check it.
show_corner_detection = false # true or false (lowercase)
from_vid_or_img = 'img' # 'vid' or 'img'
vid_snapshot_every_N_frames = 20
vid_extension = 'mp4'
img_extension = 'jpg' # 'png', 'jpg', etc
[2d-tracking]
[calibration.calculate]
calculate_method = 'board' # 'board' or 'points'
[calibration.calculate.board.intrinsics] # camera properties, only needs to be done once
intrinsics_board_type = 'checkerboard' # 'checkerboard' ('charucoboard' not supported yet)
overwrite_intrinsics = false # overwrite (or not) if they have already been calculated?
show_detection_intrinsics = true # true or false (lowercase)
intrinsics_extension = 'jpg' # any video or image extension
extract_every_N_sec = 1 # if video, extract frames every N seconds (can be <1 )
intrinsics_corners_nb = [4,7]
intrinsics_square_size = 60 # mm
intrinsics_marker_size = 40 # mm # only checked if charucoboard
intrinsics_aruco_dict = 'DICT_6X6_250' # only checked if charucoboard # see https://docs.opencv.org/3.4/dc/df7/dictionary_8hpp.html
[calibration.calculate.board.extrinsics] # camera placement, needs to be done every time
extrinsics_board_type = 'scene' # 'checkerboard', 'scene' ('charucoboard' not supported yet)
# 'board' should be large enough to be detected when laid on the floor.
# 'scene' involves manually clicking any point of know coordinates on scene. Usually more accurate if points are spread out
calculate_extrinsics = true # true or false (lowercase)
show_reprojection_error = true # true or false (lowercase)
extrinsics_extension = 'png' # any video or image extension
# if extrinsics_board_type = 'checkerboard' or 'charucoboard'
extrinsics_corners_nb = [4,7] # [H,W] rather than [w,h]
extrinsics_square_size = 60 # mm # [h,w] if square is actually a rectangle
extrinsics_marker_size = 40 # mm # only checked if 'charucoboard' (not supported yet)
extrinsics_aruco_dict = 'DICT_6X6_250' # only checked if 'charucoboard' # see https://docs.opencv.org/3.4/dc/df7/dictionary_8hpp.html
# if extrinsics_board_type = 'scene'
# list of 3D coordinates to be manually labelled on images. Can also be a 2 dimensional plane. # in m
object_coords_3d = [[-2.0, 0.3, 0.0], [-2.0 , 0.0, 0.0], [-2.0, 0.0, 0.05], [-2.0, -0.3 , 0.0], [0.0, 0.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.05], [0.0, -0.3, 0.0]] # in meters -> Not in mm! <-
[calibration.calculate.points]
calibration_points = 'wand' # 'wand' or 'keypoints'
# Not supported yet.
[personAssociation]
tracked_keypoint = 'Neck' # If the neck is not detected by the pose_model, check skeleton.py tracked_keypoint = 'Neck' # If the neck is not detected by the pose_model, check skeleton.py
# and choose a stable point for tracking the person of interest (e.g., 'right_shoulder' with BLAZEPOSE) # and choose a stable point for tracking the person of interest (e.g., 'right_shoulder' with BLAZEPOSE)
error_threshold_tracking = 20 # px reproj_error_threshold_association = 20 # px
[3d-triangulation]
error_threshold_triangulation = 15 # px [triangulation]
reproj_error_threshold_triangulation = 15 # px
likelihood_threshold = 0.3 likelihood_threshold = 0.3
min_cameras_for_triangulation = 2 min_cameras_for_triangulation = 2
interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none
@ -55,23 +88,26 @@ interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none
interp_if_gap_smaller_than = 10 # do not interpolate bigger gaps interp_if_gap_smaller_than = 10 # do not interpolate bigger gaps
show_interp_indices = true # true or false (lowercase). For each keypoint, return the frames that need to be interpolated show_interp_indices = true # true or false (lowercase). For each keypoint, return the frames that need to be interpolated
[3d-filtering]
type = 'butterworth' # butterworth, butterworth_on_speed, gaussian, LOESS, median
display_figures = false # true or false (lowercase)
[3d-filtering.butterworth] [filtering]
type = 'low' type = 'butterworth' # butterworth, kalman, gaussian, LOESS, median, butterworth_on_speed
display_figures = true # true or false (lowercase)
[filtering.butterworth]
order = 4 order = 4
cut_off_frequency = 6 # Hz cut_off_frequency = 6 # Hz
[3d-filtering.butterworth_on_speed] [filtering.kalman]
type = 'low' # How much more do you trust triangulation results (measurements), than previous data (process assuming constant acceleration)?
trust_ratio = 100 # = measurement_trust/process_trust ~= process_noise/measurement_noise
smooth = true # should be true, unless you need real-time filtering
[filtering.butterworth_on_speed]
order = 4 order = 4
cut_off_frequency = 10 # Hz cut_off_frequency = 10 # Hz
[3d-filtering.gaussian] [filtering.gaussian]
sigma_kernel = 2 #px sigma_kernel = 2 #px
[3d-filtering.LOESS] [filtering.LOESS]
nb_values_used = 5 # = fraction of data used * nb frames nb_values_used = 30 # = fraction of data used * nb frames
[3d-filtering.median] [filtering.median]
kernel_size = 9 kernel_size = 9
[opensim] [opensim]

View File

@ -1,39 +0,0 @@
[cam_01]
name = "cam_01"
size = [ 1088.0, 1920.0]
matrix = [ [ 1681.244873046875, 0.0, 532.97369384375], [ 0.0, 1681.075439453125, 948.137390140625], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000721609375, 0.002187234375, 9.5e-06, 1.078125e-05]
rotation = [ [1.70179346], [1.04839803], [-0.40602443]]
translation = [ [0.31962238], [0.93995713], [2.97508412]]
fisheye = false
[cam_02]
name = "cam_02"
size = [ 1088.0, 1920.0]
matrix = [ [ 1673.729614265625, 0.0, 534.494567875], [ 0.0, 1673.79724121875, 963.225891109375], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000747609375, 0.00213728125, 1.51875e-05, 4.546875e-06]
rotation = [ [1.35902244], [1.60141928], [-1.18177902]]
translation = [ [-0.12599186], [0.74502948], [3.17221429]]
fisheye = false
[cam_03]
name = "cam_03"
size = [ 1088.0, 1920.0]
matrix = [ [ 1681.598388671875, 0.0, 513.20837403125], [ 0.0, 1681.509887703125, 955.005126953125], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000729765625, 0.00215034375, -8.46875e-06, -8.078125e-06]
rotation = [ [0.81816165], [-2.22184308], [1.4608978]]
translation = [ [-0.76301979], [0.34503189], [4.43845847]]
fisheye = false
[cam_04]
name = "cam_04"
size = [ 1088.0, 1920.0]
matrix = [ [ 1675.234985359375, 0.0, 540.106201171875], [ 0.0, 1675.204223640625, 964.0302734375], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000744265625, 0.002104171875, 4.328125e-06, 3.109375e-06]
rotation = [ [1.4245729], [-1.39512301], [0.45721172]]
translation = [ [0.48659282], [0.02675454], [4.33496911]]
fisheye = false
[metadata]
adjusted = false
error = 0.0

View File

@ -1,39 +0,0 @@
[cam_1]
name = "cam_01"
size = [ 1088.0, 1920.0]
matrix = [ [ 1687.6396622414502, 0.0, 543.5], [ 0.0, 1686.6625452424132, 959.5], [ 0.0, 0.0, 1.0]]
distortions = [ -0.05054882348909584, 0.1576374662929963, 0.002210439026715273, -0.002164250840100675]
rotation = [ 0, 0, 0]
translation = [ 0, 0, 0]
fisheye = false
[cam_2]
name = "cam_02"
size = [ 1088.0, 1920.0]
matrix = [ [ 1687.859605173682, 0.0, 543.5], [ 0.0, 1685.4371774565182, 959.5], [ 0.0, 0.0, 1.0]]
distortions = [ -0.03518095956993663, 0.037170387967130306, 0.0017983248726869015, -0.0018747264134721386]
rotation = [ 0, 0, 0]
translation = [ 0, 0, 0]
fisheye = false
[cam_3]
name = "cam_03"
size = [ 1088.0, 1920.0]
matrix = [ [ 1680.286039024573, 0.0, 543.5], [ 0.0, 1681.1761700950424, 959.5], [ 0.0, 0.0, 1.0]]
distortions = [ -0.030304789365317657, 0.04613237843981006, 0.004618104732402956, -0.001684974310757026]
rotation = [ 0, 0, 0]
translation = [ 0, 0, 0]
fisheye = false
[cam_4]
name = "cam_04"
size = [ 1088.0, 1920.0]
matrix = [ [ 1689.483288223434, 0.0, 543.5], [ 0.0, 1688.5630322142706, 959.5], [ 0.0, 0.0, 1.0]]
distortions = [ -0.04369424846208241, 0.12212413289800295, 0.0017367557051414114, -0.0018985222378279064]
rotation = [ 0, 0, 0]
translation = [ 0, 0, 0]
fisheye = false
[metadata]
adjusted = false
error = 0.0

View File

@ -1,39 +0,0 @@
[cam_01]
name = "cam_01"
size = [ 1088.0, 1920.0]
matrix = [ [ 1681.244873046875, 0.0, 532.97369384375], [ 0.0, 1681.075439453125, 948.137390140625], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000721609375, 0.002187234375, 9.5e-06, 1.078125e-05]
rotation = [ 1.6882754799999993, 1.0483220499999997, -0.41955852000000016]
translation = [ 0.3211048899999996, 0.9563320600000009, 2.8907130499999996]
fisheye = false
[cam_02]
name = "cam_02"
size = [ 1088.0, 1920.0]
matrix = [ [ 1673.729614265625, 0.0, 534.494567875], [ 0.0, 1673.79724121875, 963.225891109375], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000747609375, 0.00213728125, 1.51875e-05, 4.546875e-06]
rotation = [ 1.34975875, 1.5963809099999993, -1.1983285799999999]
translation = [ -0.11152829000000017, 0.7766184800000001, 3.0675519599999994]
fisheye = false
[cam_03]
name = "cam_03"
size = [ 1088.0, 1920.0]
matrix = [ [ 1681.598388671875, 0.0, 513.20837403125], [ 0.0, 1681.509887703125, 955.005126953125], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000729765625, 0.00215034375, -8.46875e-06, -8.078125e-06]
rotation = [ 0.8109654899999995, -2.1972129299999996, 1.3760277799999996]
translation = [ -0.7934803899999996, 0.32283594000000126, 4.353514870000001]
fisheye = false
[cam_04]
name = "cam_04"
size = [ 1088.0, 1920.0]
matrix = [ [ 1675.234985359375, 0.0, 540.106201171875], [ 0.0, 1675.204223640625, 964.0302734375], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000744265625, 0.002104171875, 4.328125e-06, 3.109375e-06]
rotation = [ 1.4045571699999995, -1.3887412699999993, 0.42535743000000026]
translation = [ 0.5030217200000007, 0.04894934000000083, 4.406564460000002]
fisheye = false
[metadata]
adjusted = false
error = 0.0

View File

@ -1,39 +0,0 @@
[cam_1]
name = "cam01"
size = [ 1088.0, 1920.0]
matrix = [ [ 1681.244873046875, 0.0, 532.97369384375], [ 0.0, 1681.075439453125, 948.137390140625], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000721609375, 0.002187234375, 9.5e-06, 1.078125e-05]
rotation = [ 1.6882754799999993, 1.0483220499999997, -0.41955852000000016]
translation = [ 0.3211048899999996, 0.9563320600000009, 2.8907130499999996]
fisheye = false
[cam_2]
name = "cam02"
size = [ 1088.0, 1920.0]
matrix = [ [ 1673.729614265625, 0.0, 534.494567875], [ 0.0, 1673.79724121875, 963.225891109375], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000747609375, 0.00213728125, 1.51875e-05, 4.546875e-06]
rotation = [ 1.34975875, 1.5963809099999993, -1.1983285799999999]
translation = [ -0.11152829000000017, 0.7766184800000001, 3.0675519599999994]
fisheye = false
[cam_3]
name = "cam03"
size = [ 1088.0, 1920.0]
matrix = [ [ 1681.598388671875, 0.0, 513.20837403125], [ 0.0, 1681.509887703125, 955.005126953125], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000729765625, 0.00215034375, -8.46875e-06, -8.078125e-06]
rotation = [ 0.8109654899999995, -2.1972129299999996, 1.3760277799999996]
translation = [ -0.7934803899999996, 0.32283594000000126, 4.353514870000001]
fisheye = false
[cam_4]
name = "cam04"
size = [ 1088.0, 1920.0]
matrix = [ [ 1675.234985359375, 0.0, 540.106201171875], [ 0.0, 1675.204223640625, 964.0302734375], [ 0.0, 0.0, 1.0]]
distortions = [ -0.000744265625, 0.002104171875, 4.328125e-06, 3.109375e-06]
rotation = [ 1.4045571699999995, -1.3887412699999993, 0.42535743000000026]
translation = [ 0.5030217200000007, 0.04894934000000083, 4.406564460000002]
fisheye = false
[metadata]
adjusted = false
error = 0.0

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

View File

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View File

Before

Width:  |  Height:  |  Size: 173 KiB

After

Width:  |  Height:  |  Size: 173 KiB

View File

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 255 KiB

View File

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 240 KiB

View File

Before

Width:  |  Height:  |  Size: 225 KiB

After

Width:  |  Height:  |  Size: 225 KiB

View File

Before

Width:  |  Height:  |  Size: 205 KiB

After

Width:  |  Height:  |  Size: 205 KiB

View File

Before

Width:  |  Height:  |  Size: 216 KiB

After

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

View File

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 232 KiB

View File

Before

Width:  |  Height:  |  Size: 204 KiB

After

Width:  |  Height:  |  Size: 204 KiB

View File

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

Before

Width:  |  Height:  |  Size: 256 KiB

After

Width:  |  Height:  |  Size: 256 KiB

View File

Before

Width:  |  Height:  |  Size: 248 KiB

After

Width:  |  Height:  |  Size: 248 KiB

View File

Before

Width:  |  Height:  |  Size: 236 KiB

After

Width:  |  Height:  |  Size: 236 KiB

View File

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 244 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

View File

Before

Width:  |  Height:  |  Size: 182 KiB

After

Width:  |  Height:  |  Size: 182 KiB

View File

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 232 KiB

View File

Before

Width:  |  Height:  |  Size: 251 KiB

After

Width:  |  Height:  |  Size: 251 KiB

View File

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 199 KiB

View File

Before

Width:  |  Height:  |  Size: 180 KiB

After

Width:  |  Height:  |  Size: 180 KiB

View File

Before

Width:  |  Height:  |  Size: 262 KiB

After

Width:  |  Height:  |  Size: 262 KiB

View File

Before

Width:  |  Height:  |  Size: 238 KiB

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 225 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 228 KiB

View File

Before

Width:  |  Height:  |  Size: 240 KiB

After

Width:  |  Height:  |  Size: 240 KiB

View File

Before

Width:  |  Height:  |  Size: 199 KiB

After

Width:  |  Height:  |  Size: 199 KiB

View File

Before

Width:  |  Height:  |  Size: 255 KiB

After

Width:  |  Height:  |  Size: 255 KiB

View File

Before

Width:  |  Height:  |  Size: 253 KiB

After

Width:  |  Height:  |  Size: 253 KiB

View File

Before

Width:  |  Height:  |  Size: 226 KiB

After

Width:  |  Height:  |  Size: 226 KiB

View File

Before

Width:  |  Height:  |  Size: 235 KiB

After

Width:  |  Height:  |  Size: 235 KiB

View File

Before

Width:  |  Height:  |  Size: 265 KiB

After

Width:  |  Height:  |  Size: 265 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 203 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 190 KiB

View File

@ -1,5 +1,5 @@
############################################################################### ###############################################################################
## POSE2SIM PROJECT PARAMETERS ## ## PROJECT PARAMETERS ##
############################################################################### ###############################################################################
# Configure your project parameters here # Configure your project parameters here
@ -9,45 +9,78 @@ project_dir = '' # BETWEEN SINGLE QUOTES! # If empty, project dir is current dir
frame_range = [] #For example [10,300], or [] for all frames frame_range = [] #For example [10,300], or [] for all frames
frame_rate = 60 #Hz frame_rate = 60 #Hz
rawImg_folder_name = 'raw-2d' rawImg_folder_name = 'raw'
calib_folder_name = 'calibration' calib_folder_name = 'calibration'
pose_folder_name = 'pose' pose_folder_name = 'pose'
pose_json_folder_extension = 'json' pose_json_folder_extension = 'json'
pose_img_folder_extension = 'img' pose_img_folder_extension = 'img'
poseTracked_folder_name = 'pose-2d-tracked' poseAssociated_folder_name = 'pose-associated'
pose3d_folder_name = 'triangulation' pose3d_folder_name = 'pose-3d'
opensim_folder_name = 'opensim' opensim_folder_name = 'opensim'
[pose] [pose]
pose_model = 'BODY_25B' #CUSTOM, BODY_25B, BODY_25, BODY_135, BLAZEPOSE, pose_model = 'BODY_25B' #CUSTOM, BODY_25B, BODY_25, BODY_135, BLAZEPOSE, HALPE_26, HALPE_68, HALPE_136, COCO_133, COCO, MPII are available,
# HALPE_26, HALPE_68, HALPE_136, COCO_133, COCO, MPII are available,
# from DeepLabCut, OpenPose, MediaPipe BlazePose, and AlphaPose # from DeepLabCut, OpenPose, MediaPipe BlazePose, and AlphaPose
# See Pose2Sim\skeleton.py for their skeleton hierarchy # See Pose2Sim\skeleton.py for their skeleton hierarchy
[calibration] [calibration]
type = 'qca' # 'qca', 'checkerboard', 'arucoboard', or 'charucoboard' calibration_type = 'convert' # 'convert' or 'calculate'
[calibration.qca]
binning_factor = 1 # Usually 1, except when filming in 540p where it usually is 2
[calibration.checkerboard] [calibration.convert]
corners_nb = [7,12] # [H,W] rather than [w,h] convert_from = 'qualisys' # 'qualisys', 'optitrack', or 'vicon'
square_size = 80 # mm # [h,w] if square is actually a rectangle [calibration.convert.qualisys]
frame_for_origin = -1 # starting from zero. -1 if board is at origin on last frame binning_factor = 1 # Usually 1, except when filming in 540p where it usually is 2
# /!\ Beware that corners must be detected on all view at frame_for_origin, or else
# extrinsic parameters will be wrong. Set show_corner_detection to true to check it.
show_corner_detection = false # true or false (lowercase)
from_vid_or_img = 'img' # 'vid' or 'img'
vid_snapshot_every_N_frames = 20
vid_extension = 'mp4'
img_extension = 'jpg' # 'png', 'jpg', etc
[2d-tracking]
[calibration.calculate]
calculate_method = 'board' # 'board' or 'points'
[calibration.calculate.board.intrinsics] # camera properties, only needs to be done once
intrinsics_board_type = 'checkerboard' # 'checkerboard' ('charucoboard' not supported yet)
overwrite_intrinsics = false # overwrite (or not) if they have already been calculated?
show_detection_intrinsics = true # true or false (lowercase)
intrinsics_extension = 'jpg' # any video or image extension
extract_every_N_sec = 1 # if video, extract frames every N seconds (can be <1 )
intrinsics_corners_nb = [4,7]
intrinsics_square_size = 60 # mm
intrinsics_marker_size = 40 # mm # only checked if charucoboard
intrinsics_aruco_dict = 'DICT_6X6_250' # only checked if charucoboard # see https://docs.opencv.org/3.4/dc/df7/dictionary_8hpp.html
[calibration.calculate.board.extrinsics] # camera placement, needs to be done every time
extrinsics_board_type = 'scene' # 'checkerboard', 'scene' ('charucoboard' not supported yet)
# 'board' should be large enough to be detected when laid on the floor.
# 'scene' involves manually clicking any point of know coordinates on scene. Usually more accurate if points are spread out
calculate_extrinsics = true # true or false (lowercase)
show_reprojection_error = true # true or false (lowercase)
extrinsics_extension = 'png' # any video or image extension
# if extrinsics_board_type = 'checkerboard' or 'charucoboard'
extrinsics_corners_nb = [4,7] # [H,W] rather than [w,h]
extrinsics_square_size = 60 # mm # [h,w] if square is actually a rectangle
extrinsics_marker_size = 40 # mm # only checked if 'charucoboard' (not supported yet)
extrinsics_aruco_dict = 'DICT_6X6_250' # only checked if 'charucoboard' # see https://docs.opencv.org/3.4/dc/df7/dictionary_8hpp.html
# if extrinsics_board_type = 'scene'
# list of 3D coordinates to be manually labelled on images. Can also be a 2 dimensional plane. # in m
object_coords_3d = [[-2.0, 0.3, 0.0], [-2.0 , 0.0, 0.0], [-2.0, 0.0, 0.05], [-2.0, -0.3 , 0.0], [0.0, 0.3, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.05], [0.0, -0.3, 0.0]] # in meters -> Not in mm! <-
[calibration.calculate.points]
calibration_points = 'wand' # 'wand' or 'keypoints'
# Not supported yet.
[personAssociation]
tracked_keypoint = 'Neck' # If the neck is not detected by the pose_model, check skeleton.py tracked_keypoint = 'Neck' # If the neck is not detected by the pose_model, check skeleton.py
# and choose a stable point for tracking the person of interest (e.g., 'right_shoulder' with BLAZEPOSE) # and choose a stable point for tracking the person of interest (e.g., 'right_shoulder' with BLAZEPOSE)
error_threshold_tracking = 20 # px reproj_error_threshold_association = 20 # px
[3d-triangulation]
error_threshold_triangulation = 15 # px [triangulation]
reproj_error_threshold_triangulation = 15 # px
likelihood_threshold = 0.3 likelihood_threshold = 0.3
min_cameras_for_triangulation = 2 min_cameras_for_triangulation = 2
interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none
@ -55,23 +88,26 @@ interpolation = 'cubic' #linear, slinear, quadratic, cubic, or none
interp_if_gap_smaller_than = 10 # do not interpolate bigger gaps interp_if_gap_smaller_than = 10 # do not interpolate bigger gaps
show_interp_indices = true # true or false (lowercase). For each keypoint, return the frames that need to be interpolated show_interp_indices = true # true or false (lowercase). For each keypoint, return the frames that need to be interpolated
[3d-filtering]
type = 'butterworth' # butterworth, butterworth_on_speed, gaussian, LOESS, median [filtering]
type = 'butterworth' # butterworth, kalman, gaussian, LOESS, median, butterworth_on_speed
display_figures = true # true or false (lowercase) display_figures = true # true or false (lowercase)
[3d-filtering.butterworth] [filtering.butterworth]
type = 'low'
order = 4 order = 4
cut_off_frequency = 6 # Hz cut_off_frequency = 6 # Hz
[3d-filtering.butterworth_on_speed] [filtering.kalman]
type = 'low' # How much more do you trust triangulation results (measurements), than previous data (process assuming constant acceleration)?
trust_ratio = 100 # = measurement_trust/process_trust ~= process_noise/measurement_noise
smooth = true # should be true, unless you need real-time filtering
[filtering.butterworth_on_speed]
order = 4 order = 4
cut_off_frequency = 10 # Hz cut_off_frequency = 10 # Hz
[3d-filtering.gaussian] [filtering.gaussian]
sigma_kernel = 2 #px sigma_kernel = 2 #px
[3d-filtering.LOESS] [filtering.LOESS]
nb_values_used = 5 # = fraction of data used * nb frames nb_values_used = 30 # = fraction of data used * nb frames
[3d-filtering.median] [filtering.median]
kernel_size = 9 kernel_size = 9
[opensim] [opensim]

View File

@ -136,7 +136,7 @@ def read_qca(qca_path, binning_factor):
# Camera name # Camera name
for i, tag in enumerate(root.findall('cameras/camera')): for i, tag in enumerate(root.findall('cameras/camera')):
ret += [float(tag.attrib.get('avg-residual'))/1000] ret += [float(tag.attrib.get('avg-residual'))]
C += [tag.attrib.get('serial')] C += [tag.attrib.get('serial')]
if tag.attrib.get('model') in ('Miqus Video', 'Miqus Video UnderWater', 'none'): if tag.attrib.get('model') in ('Miqus Video', 'Miqus Video UnderWater', 'none'):
vid_id += [i] vid_id += [i]
@ -423,15 +423,13 @@ def calibrate_intrinsics(calib_dir, intrinsics_config_dict):
logging.exception(f'The folder {os.path.join(calib_dir, "intrinsics", cam)} does not exist or does not contain any files with extension .{intrinsics_extension}.') logging.exception(f'The folder {os.path.join(calib_dir, "intrinsics", cam)} does not exist or does not contain any files with extension .{intrinsics_extension}.')
raise ValueError(f'The folder {os.path.join(calib_dir, "intrinsics", cam)} does not exist or does not contain any files with extension .{intrinsics_extension}.') raise ValueError(f'The folder {os.path.join(calib_dir, "intrinsics", cam)} does not exist or does not contain any files with extension .{intrinsics_extension}.')
img_vid_files = sorted(img_vid_files, key=lambda c: [int(n) for n in re.findall(r'\d+', c)]) #sorting paths with numbers img_vid_files = sorted(img_vid_files, key=lambda c: [int(n) for n in re.findall(r'\d+', c)]) #sorting paths with numbers
# extract frames from video if video # extract frames from video if video
try: try:
# check if file is a video rather than an image
cap = cv2.VideoCapture(img_vid_files[0]) cap = cv2.VideoCapture(img_vid_files[0])
cap.read() cap.read()
if cap.read()[0] == False: if cap.read()[0] == False:
logging.exception('No video in the folder or wrong extension.') raise
raise ValueError('No video in the folder or wrong extension.')
# extract frames from video
extract_frames(img_vid_files[0], extract_every_N_sec, overwrite_extraction) extract_frames(img_vid_files[0], extract_every_N_sec, overwrite_extraction)
img_vid_files = glob.glob(os.path.join(calib_dir, 'intrinsics', cam, f'*.png')) img_vid_files = glob.glob(os.path.join(calib_dir, 'intrinsics', cam, f'*.png'))
img_vid_files = sorted(img_vid_files, key=lambda c: [int(n) for n in re.findall(r'\d+', c)]) img_vid_files = sorted(img_vid_files, key=lambda c: [int(n) for n in re.findall(r'\d+', c)])
@ -442,16 +440,18 @@ def calibrate_intrinsics(calib_dir, intrinsics_config_dict):
for img_path in img_vid_files: for img_path in img_vid_files:
if show_detection_intrinsics == True: if show_detection_intrinsics == True:
imgp_confirmed, objp_confirmed = findCorners(img_path, intrinsics_corners_nb, objp=objp, show=show_detection_intrinsics) imgp_confirmed, objp_confirmed = findCorners(img_path, intrinsics_corners_nb, objp=objp, show=show_detection_intrinsics)
print(len(imgp_confirmed), len(objp_confirmed))
if isinstance(imgp_confirmed, np.ndarray): if isinstance(imgp_confirmed, np.ndarray):
imgpoints.append(imgp_confirmed) imgpoints.append(imgp_confirmed)
objpoints.append(objp_confirmed) objpoints.append(objp_confirmed)
else: else:
imgp_confirmed = findCorners(img_path, intrinsics_corners_nb, objp=objp, show=show_detection_intrinsics) imgp_confirmed = findCorners(img_path, intrinsics_corners_nb, objp=objp, show=show_detection_intrinsics)
if isinstance(imgp_confirmed, np.ndarray): if isinstance(imgp_confirmed, np.ndarray):
imgpoints.append(imgp_confirmed) imgpoints.append(imgp_confirmed)
objpoints.append(objp) objpoints.append(objp)
if len(imgpoints) < 10: if len(imgpoints) < 10:
logging.info(f'Corners were detected only on {len(imgpoints)} images for camera {cam}. Calibration of intrinsic parameters may not be accurate with less than 10 good images of the board.') logging.info(f'Corners were detected only on {len(imgpoints)} images for camera {cam}. Calibration of intrinsic parameters may not be accurate with fewer than 10 good images of the board.')
# calculate intrinsics # calculate intrinsics
img = cv2.imread(str(img_path)) img = cv2.imread(str(img_path))
@ -524,11 +524,12 @@ def calibrate_extrinsics(calib_dir, extrinsics_config_dict, C, S, K, D):
logging.exception('No points clicked (or fewer than 6). Press \'C\' when the image is displayed, and then click on the image points corresponding to the \'object_coords_3d\' you measured and wrote down in the Config.toml file.') logging.exception('No points clicked (or fewer than 6). Press \'C\' when the image is displayed, and then click on the image points corresponding to the \'object_coords_3d\' you measured and wrote down in the Config.toml file.')
raise ValueError('No points clicked (or fewer than 6). Press \'C\' when the image is displayed, and then click on the image points corresponding to the \'object_coords_3d\' you measured and wrote down in the Config.toml file.') raise ValueError('No points clicked (or fewer than 6). Press \'C\' when the image is displayed, and then click on the image points corresponding to the \'object_coords_3d\' you measured and wrote down in the Config.toml file.')
if len(objp) < 10: if len(objp) < 10:
logging.info(f'Only {len(objp)} reference points for camera {cam}. Calibration of extrinsic parameters may not be accurate with less than 10 reference points, as spread out as possible.') logging.info(f'Only {len(objp)} reference points for camera {cam}. Calibration of extrinsic parameters may not be accurate with fewer than 10 reference points, as spread out as possible.')
# Calculate extrinsics # Calculate extrinsics
mtx, dist = np.array(K[i]), np.array(D[i]) mtx, dist = np.array(K[i]), np.array(D[i])
_, r, t = cv2.solvePnP(objp, imgp, mtx, dist) _, r, t = cv2.solvePnP(objp, imgp, mtx, dist)
r, t = r.flatten(), t.flatten()
# Projection of object points to image plane # Projection of object points to image plane
Kh_cam = np.block([mtx, np.zeros(3).reshape(3,1)]) Kh_cam = np.block([mtx, np.zeros(3).reshape(3,1)])
@ -545,9 +546,16 @@ def calibrate_extrinsics(calib_dir, extrinsics_config_dict, C, S, K, D):
cv2.circle(img, (int(o[0]), int(o[1])), 8, (0,0,255), -1) cv2.circle(img, (int(o[0]), int(o[1])), 8, (0,0,255), -1)
for i in imgp: for i in imgp:
cv2.drawMarker(img, (int(i[0][0]), int(i[0][1])), (0,255,0), cv2.MARKER_CROSS, 15, 2) cv2.drawMarker(img, (int(i[0][0]), int(i[0][1])), (0,255,0), cv2.MARKER_CROSS, 15, 2)
cv2.putText(img, 'Verify calibration results, then close window.', (20, 20), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA)
cv2.putText(img, 'Verify calibration results, then close window.', (20, 20), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA)
cv2.drawMarker(img, (20,40), (0,255,0), cv2.MARKER_CROSS, 15, 2)
cv2.putText(img, ' Clicked points', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA)
cv2.putText(img, ' Clicked points', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA)
cv2.circle(img, (20,60), 8, (0,0,255), -1)
cv2.putText(img, ' Reprojected object points', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA)
cv2.putText(img, ' Reprojected object points', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA)
im_pil = Image.fromarray(img) im_pil = Image.fromarray(img)
print(img_vid_files[0]) im_pil.show(title = os.path.basename(img_vid_files[0]))
im_pil.show(title = img_vid_files[0])
# Calculate reprojection error # Calculate reprojection error
imgp_to_objreproj_dist = [euclidean_distance(proj_obj[n], imgp[n]) for n in range(len(proj_obj))] imgp_to_objreproj_dist = [euclidean_distance(proj_obj[n], imgp[n]) for n in range(len(proj_obj))]
@ -574,7 +582,7 @@ def findCorners(img_path, corner_nb, objp=[], show=True):
INPUTS: INPUTS:
- img_path: path to image (or video) - img_path: path to image (or video)
- corner_nb: [H, W] internal corners in checkerboard: list of two integers [9,6] - corner_nb: [H, W] internal corners in checkerboard: list of two integers [4,7]
- optionnal: show: choose whether to show corner detections - optionnal: show: choose whether to show corner detections
- optionnal: objp: array [3d corner coordinates] - optionnal: objp: array [3d corner coordinates]
@ -678,7 +686,7 @@ def imgp_objp_visualizer_clicker(img, imgp=[], objp=[], img_path=''):
objp_confirmed = objp objp_confirmed = objp
else: else:
imgp_confirmed = np.array([imgp.astype('float32') for imgp in imgp_confirmed]) imgp_confirmed = np.array([imgp.astype('float32') for imgp in imgp_confirmed])
objp_confirmed = np.array(objp_confirmed) objp_confirmed = objp_confirmed
# OpenCV needs at leas 4 correspondance points to calibrate # OpenCV needs at leas 4 correspondance points to calibrate
if len(imgp_confirmed) < 6: if len(imgp_confirmed) < 6:
objp_confirmed = [] objp_confirmed = []
@ -696,6 +704,9 @@ def imgp_objp_visualizer_clicker(img, imgp=[], objp=[], img_path=''):
objp_confirmed = [] objp_confirmed = []
if event.key == 'c': if event.key == 'c':
# TODO: RIGHT NOW, IF 'C' IS PRESSED ANOTHER TIME, OBJP_CONFIRMED AND IMGP_CONFIRMED ARE RESET TO []
if 'objp_confirmed' in globals():
del objp_confirmed
# If 'c', allows retrieving imgp_confirmed by clicking them on the image # If 'c', allows retrieving imgp_confirmed by clicking them on the image
scat = ax.scatter([],[],s=100,marker='+',color='g') scat = ax.scatter([],[],s=100,marker='+',color='g')
plt.connect('button_press_event', on_click) plt.connect('button_press_event', on_click)
@ -731,7 +742,7 @@ def imgp_objp_visualizer_clicker(img, imgp=[], objp=[], img_path=''):
fig_3d.canvas.draw() fig_3d.canvas.draw()
elif count == len(objp)-1: elif count == len(objp)-1:
# if all objp have been clicked or indicated as not visible, close all # if all objp have been clicked or indicated as not visible, close all
imgp_confirmed = np.array(imgp) imgp_confirmed = np.array(imgp, np.float32)
plt.close('all') plt.close('all')
for var_to_delete in ['events', 'count', 'scat', 'fig_3d', 'ax_3d', 'objp_confirmed_notok']: for var_to_delete in ['events', 'count', 'scat', 'fig_3d', 'ax_3d', 'objp_confirmed_notok']:
if var_to_delete in globals(): if var_to_delete in globals():
@ -780,8 +791,8 @@ def imgp_objp_visualizer_clicker(img, imgp=[], objp=[], img_path=''):
fig_3d.canvas.draw() fig_3d.canvas.draw()
elif count == len(objp)-1: elif count == len(objp)-1:
# retrieve objp_confirmed # retrieve objp_confirmed
objp_confirmed = np.array([[objp[count].tolist()] if 'objp_confirmed' not in globals() else objp_confirmed+[objp[count]]][0]) objp_confirmed = np.array([[objp[count]] if 'objp_confirmed' not in globals() else objp_confirmed+[objp[count]]][0])
imgp_confirmed = np.array(imgp_confirmed) imgp_confirmed = np.array(imgp_confirmed, np.float32)
# close all, delete all # close all, delete all
plt.close('all') plt.close('all')
for var_to_delete in ['events', 'count', 'scat', 'scat_3d', 'fig_3d', 'ax_3d', 'objp_confirmed_notok']: for var_to_delete in ['events', 'count', 'scat', 'scat_3d', 'fig_3d', 'ax_3d', 'objp_confirmed_notok']:
@ -792,6 +803,8 @@ def imgp_objp_visualizer_clicker(img, imgp=[], objp=[], img_path=''):
objp_confirmed = [[objp[count]] if 'objp_confirmed' not in globals() else objp_confirmed+[objp[count]]][0] objp_confirmed = [[objp[count]] if 'objp_confirmed' not in globals() else objp_confirmed+[objp[count]]][0]
ax_3d.scatter(*objp[count], marker='o', color='g') ax_3d.scatter(*objp[count], marker='o', color='g')
fig_3d.canvas.draw() fig_3d.canvas.draw()
print(objp_confirmed)
# Right click: # Right click:
# If last event was left click, remove last point and if objp given, from objp_confirmed # If last event was left click, remove last point and if objp given, from objp_confirmed
@ -858,20 +871,20 @@ def imgp_objp_visualizer_clicker(img, imgp=[], objp=[], img_path=''):
ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius]) ax.set_zlim3d([z_middle - plot_radius, z_middle + plot_radius])
# Write instructions # Write instructions
cv2.putText(img, 'Type "Y" to accept point detection.', (20, 20), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, 'Type "Y" to accept point detection.', (20, 20), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, 'Type "Y" to accept point detection.', (20, 20), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, 'Type "Y" to accept point detection.', (20, 20), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
cv2.putText(img, 'If points are wrongfully (or not) detected:', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, 'If points are wrongfully (or not) detected:', (20, 43), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, 'If points are wrongfully (or not) detected:', (20, 40), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, 'If points are wrongfully (or not) detected:', (20, 43), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
cv2.putText(img, '- type "N" to dismiss this image,', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, '- type "N" to dismiss this image,', (20, 66), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, '- type "N" to dismiss this image,', (20, 60), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, '- type "N" to dismiss this image,', (20, 66), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
cv2.putText(img, '- type "C" to click points by hand (beware of their order).', (20, 80), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, '- type "C" to click points by hand (beware of their order).', (20, 89), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, '- type "C" to click points by hand (beware of their order).', (20, 80), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, '- type "C" to click points by hand (beware of their order).', (20, 89), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
cv2.putText(img, ' left click to add a point, right click to remove it, "H" to indicate it is not visible. ', (20, 100), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, ' left click to add a point, right click to remove it, "H" to indicate it is not visible. ', (20, 112), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, ' left click to add a point, right click to remove it, "H" to indicate it is not visible. ', (20, 100), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, ' left click to add a point, right click to remove it, "H" to indicate it is not visible. ', (20, 112), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
cv2.putText(img, ' Confirm with "Y", cancel with "N".', (20, 120), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, ' Confirm with "Y", cancel with "N".', (20, 135), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, ' Confirm with "Y", cancel with "N".', (20, 120), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, ' Confirm with "Y", cancel with "N".', (20, 135), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
cv2.putText(img, 'Use mouse wheel to zoom in and out and to pan', (20, 140), cv2.FONT_HERSHEY_SIMPLEX, .5, (255,255,255), 2, lineType = cv2.LINE_AA) cv2.putText(img, 'Use mouse wheel to zoom in and out and to pan', (20, 158), cv2.FONT_HERSHEY_SIMPLEX, .7, (255,255,255), 3, lineType = cv2.LINE_AA)
cv2.putText(img, 'Use mouse wheel to zoom in and out and to pan', (20, 140), cv2.FONT_HERSHEY_SIMPLEX, .5, (0,0,0), 1, lineType = cv2.LINE_AA) cv2.putText(img, 'Use mouse wheel to zoom in and out and to pan', (20, 158), cv2.FONT_HERSHEY_SIMPLEX, .7, (0,0,0), 2, lineType = cv2.LINE_AA)
# Put image in a matplotlib figure for more controls # Put image in a matplotlib figure for more controls
plt.rcParams['toolbar'] = 'None' plt.rcParams['toolbar'] = 'None'
@ -997,15 +1010,14 @@ def recap_calibrate(ret, calib_path, calib_full_type):
if cam != 'metadata': if cam != 'metadata':
f_px = calib[cam]['matrix'][0][0] f_px = calib[cam]['matrix'][0][0]
Dm = euclidean_distance(calib[cam]['translation'], [0,0,0]) Dm = euclidean_distance(calib[cam]['translation'], [0,0,0])
print(ret[c])
if calib_full_type=='convert_qualisys' or calib_full_type=='convert_vicon': if calib_full_type=='convert_qualisys' or calib_full_type=='convert_vicon':
ret_m.append( np.around(ret[c]*1000, decimals=3) ) ret_m.append( np.around(ret[c], decimals=3) )
ret_px.append( np.around(ret[c] / Dm * f_px, decimals=3) ) ret_px.append( np.around(ret[c] / (Dm*1000) * f_px, decimals=3) )
elif calib_full_type=='calculate_board': elif calib_full_type=='calculate_board':
ret_px.append( np.around(ret[c], decimals=3) ) ret_px.append( np.around(ret[c], decimals=3) )
ret_m.append( np.around(ret[c]*Dm / f_px, decimals=3) ) ret_m.append( np.around(ret[c]*Dm*1000 / f_px, decimals=3) )
logging.info(f'\n--> Residual (RMS) calibration errors for each camera are respectively {ret_px} px, \nwhich corresponds to {ret_m} m.\n') logging.info(f'\n--> Residual (RMS) calibration errors for each camera are respectively {ret_px} px, \nwhich corresponds to {ret_m} mm.\n')
logging.info(f'Calibration file is stored at {calib_path}.') logging.info(f'Calibration file is stored at {calib_path}.')

View File

@ -150,8 +150,8 @@ def kalman_filter_1d(config, col):
- col_filtered: Filtered pandas dataframe column - col_filtered: Filtered pandas dataframe column
''' '''
trustratio = int(config.get('3d-filtering').get('kalman').get('trust_ratio')) trustratio = int(config.get('filtering').get('kalman').get('trust_ratio'))
smooth = int(config.get('3d-filtering').get('kalman').get('smooth')) smooth = int(config.get('filtering').get('kalman').get('smooth'))
framerate = config.get('project').get('frame_rate') framerate = config.get('project').get('frame_rate')
measurement_noise = 20 measurement_noise = 20
process_noise = measurement_noise * trustratio process_noise = measurement_noise * trustratio
@ -187,9 +187,9 @@ def butterworth_filter_1d(config, col):
- col_filtered: Filtered pandas dataframe column - col_filtered: Filtered pandas dataframe column
''' '''
type = 'low' #config.get('3d-filtering').get('butterworth').get('type') type = 'low' #config.get('filtering').get('butterworth').get('type')
order = int(config.get('3d-filtering').get('butterworth').get('order')) order = int(config.get('filtering').get('butterworth').get('order'))
cutoff = int(config.get('3d-filtering').get('butterworth').get('cut_off_frequency')) cutoff = int(config.get('filtering').get('butterworth').get('cut_off_frequency'))
framerate = config.get('project').get('frame_rate') framerate = config.get('project').get('frame_rate')
b, a = signal.butter(order/2, cutoff/(framerate/2), type, analog = False) b, a = signal.butter(order/2, cutoff/(framerate/2), type, analog = False)
@ -223,9 +223,9 @@ def butterworth_on_speed_filter_1d(config, col):
- col_filtered: Filtered pandas dataframe column - col_filtered: Filtered pandas dataframe column
''' '''
type = 'low' # config.get('3d-filtering').get('butterworth_on_speed').get('type') type = 'low' # config.get('filtering').get('butterworth_on_speed').get('type')
order = int(config.get('3d-filtering').get('butterworth_on_speed').get('order')) order = int(config.get('filtering').get('butterworth_on_speed').get('order'))
cutoff = int(config.get('3d-filtering').get('butterworth_on_speed').get('cut_off_frequency')) cutoff = int(config.get('filtering').get('butterworth_on_speed').get('cut_off_frequency'))
framerate = config.get('project').get('frame_rate') framerate = config.get('project').get('frame_rate')
b, a = signal.butter(order/2, cutoff/(framerate/2), type, analog = False) b, a = signal.butter(order/2, cutoff/(framerate/2), type, analog = False)
@ -264,7 +264,7 @@ def gaussian_filter_1d(config, col):
- col_filtered: Filtered pandas dataframe column - col_filtered: Filtered pandas dataframe column
''' '''
gaussian_filter_sigma_kernel = int(config.get('3d-filtering').get('gaussian').get('sigma_kernel')) gaussian_filter_sigma_kernel = int(config.get('filtering').get('gaussian').get('sigma_kernel'))
col_filtered = gaussian_filter1d(col, gaussian_filter_sigma_kernel) col_filtered = gaussian_filter1d(col, gaussian_filter_sigma_kernel)
@ -284,7 +284,7 @@ def loess_filter_1d(config, col):
- col_filtered: Filtered pandas dataframe column - col_filtered: Filtered pandas dataframe column
''' '''
kernel = config.get('3d-filtering').get('LOESS').get('nb_values_used') kernel = config.get('filtering').get('LOESS').get('nb_values_used')
col_filtered = col.copy() col_filtered = col.copy()
mask = np.isnan(col_filtered) mask = np.isnan(col_filtered)
@ -313,7 +313,7 @@ def median_filter_1d(config, col):
- col_filtered: Filtered pandas dataframe column - col_filtered: Filtered pandas dataframe column
''' '''
median_filter_kernel_size = config.get('3d-filtering').get('median').get('kernel_size') median_filter_kernel_size = config.get('filtering').get('median').get('kernel_size')
col_filtered = signal.medfilt(col, kernel_size=median_filter_kernel_size) col_filtered = signal.medfilt(col, kernel_size=median_filter_kernel_size)
@ -402,19 +402,19 @@ def recap_filter3d(config, trc_path):
''' '''
# Read Config # Read Config
filter_type = config.get('3d-filtering').get('type') filter_type = config.get('filtering').get('type')
kalman_filter_trustratio = int(config.get('3d-filtering').get('kalman').get('trust_ratio')) kalman_filter_trustratio = int(config.get('filtering').get('kalman').get('trust_ratio'))
kalman_filter_smooth = int(config.get('3d-filtering').get('kalman').get('smooth')) kalman_filter_smooth = int(config.get('filtering').get('kalman').get('smooth'))
kalman_filter_smooth_str = 'smoother' if kalman_filter_smooth else 'filter' kalman_filter_smooth_str = 'smoother' if kalman_filter_smooth else 'filter'
butterworth_filter_type = 'low' # config.get('3d-filtering').get('butterworth').get('type') butterworth_filter_type = 'low' # config.get('filtering').get('butterworth').get('type')
butterworth_filter_order = int(config.get('3d-filtering').get('butterworth').get('order')) butterworth_filter_order = int(config.get('filtering').get('butterworth').get('order'))
butterworth_filter_cutoff = int(config.get('3d-filtering').get('butterworth').get('cut_off_frequency')) butterworth_filter_cutoff = int(config.get('filtering').get('butterworth').get('cut_off_frequency'))
butter_speed_filter_type = 'low' # config.get('3d-filtering').get('butterworth_on_speed').get('type') butter_speed_filter_type = 'low' # config.get('filtering').get('butterworth_on_speed').get('type')
butter_speed_filter_order = int(config.get('3d-filtering').get('butterworth_on_speed').get('order')) butter_speed_filter_order = int(config.get('filtering').get('butterworth_on_speed').get('order'))
butter_speed_filter_cutoff = int(config.get('3d-filtering').get('butterworth_on_speed').get('cut_off_frequency')) butter_speed_filter_cutoff = int(config.get('filtering').get('butterworth_on_speed').get('cut_off_frequency'))
gaussian_filter_sigma_kernel = int(config.get('3d-filtering').get('gaussian').get('sigma_kernel')) gaussian_filter_sigma_kernel = int(config.get('filtering').get('gaussian').get('sigma_kernel'))
loess_filter_nb_values = config.get('3d-filtering').get('LOESS').get('nb_values_used') loess_filter_nb_values = config.get('filtering').get('LOESS').get('nb_values_used')
median_filter_kernel_size = config.get('3d-filtering').get('median').get('kernel_size') median_filter_kernel_size = config.get('filtering').get('median').get('kernel_size')
# Recap # Recap
filter_mapping_recap = { filter_mapping_recap = {

View File

@ -192,7 +192,7 @@ def recap_tracking(config, error, nb_cams_excluded):
# Read config # Read config
project_dir = config.get('project').get('project_dir') project_dir = config.get('project').get('project_dir')
if project_dir == '': project_dir = os.getcwd() if project_dir == '': project_dir = os.getcwd()
poseTracked_folder_name = config.get('project').get('poseTracked_folder_name') poseTracked_folder_name = config.get('project').get('poseAssociated_folder_name')
calib_folder_name = config.get('project').get('calib_folder_name') calib_folder_name = config.get('project').get('calib_folder_name')
tracked_keypoint = config.get('personAssociation').get('tracked_keypoint') tracked_keypoint = config.get('personAssociation').get('tracked_keypoint')
error_threshold_tracking = config.get('personAssociation').get('error_threshold_tracking') error_threshold_tracking = config.get('personAssociation').get('error_threshold_tracking')

View File

@ -413,7 +413,7 @@ def triangulate_all(config):
interp_gap_smaller_than = config.get('triangulation').get('interp_if_gap_smaller_than') interp_gap_smaller_than = config.get('triangulation').get('interp_if_gap_smaller_than')
show_interp_indices = config.get('triangulation').get('show_interp_indices') show_interp_indices = config.get('triangulation').get('show_interp_indices')
pose_dir = os.path.join(project_dir, pose_folder_name) pose_dir = os.path.join(project_dir, pose_folder_name)
poseTracked_folder_name = config.get('project').get('poseTracked_folder_name') poseTracked_folder_name = config.get('project').get('poseAssociated_folder_name')
calib_dir = os.path.join(project_dir, calib_folder_name) calib_dir = os.path.join(project_dir, calib_folder_name)
calib_file = glob.glob(os.path.join(calib_dir, '*.toml'))[0] calib_file = glob.glob(os.path.join(calib_dir, '*.toml'))[0]
poseTracked_dir = os.path.join(project_dir, poseTracked_folder_name) poseTracked_dir = os.path.join(project_dir, poseTracked_folder_name)
@ -495,6 +495,7 @@ def triangulate_all(config):
non_interp_frames = [[f'{seq[0]}:{seq[-1]+1}' for seq in seq_kpt if len(seq)>interp_gap_smaller_than] for seq_kpt in sequences] non_interp_frames = [[f'{seq[0]}:{seq[-1]+1}' for seq in seq_kpt if len(seq)>interp_gap_smaller_than] for seq_kpt in sequences]
else: else:
interp_frames = None interp_frames = None
non_interp_frames = []
# Interpolate missing values # Interpolate missing values
if interpolation_kind != 'none': if interpolation_kind != 'none':

View File

@ -98,7 +98,7 @@ You should obtain a plot of all the 3D coordinates trajectories. You can check t
Results are stored as .trc files in the `Demo/pose-3d` directory. Results are stored as .trc files in the `Demo/pose-3d` directory.
*N.B.:* Default parameters have been provided in `Demo\Users\Config.toml` but can be edited.\ *N.B.:* Default parameters have been provided in `Demo\Users\Config.toml` but can be edited.\
**Try calibration tool by changing `calibration_type` to `calculate` instead of `convert` (more info [there](#calculate-from-scratch)).** *N.B.:* *Try calibration tool by changing `calibration_type` to `calculate` instead of `convert` (more info [there](#calculate-from-scratch)).*
<br/> <br/>
## Demonstration Part-2: Obtain 3D joint angles with OpenSim ## Demonstration Part-2: Obtain 3D joint angles with OpenSim
@ -256,6 +256,7 @@ If you already have a calibration file, set `calibration_type` type to `convert`
- **With a board:** - **With a board:**
> *N.B.:* Try the calibration tool on the Demo by changing `calibration_type` to `calculate` instead of `convert` in `Config.toml`.\ > *N.B.:* Try the calibration tool on the Demo by changing `calibration_type` to `calculate` instead of `convert` in `Config.toml`.\
For the sake of practicality, there are voluntarily few images for intrinsics, and few clicked points for extrinsics. *You should use more of them.* In spite of this, your reprojection error should be under 1-2 cm, which [does not hinder the quality of kinematic results in practice](https://www.mdpi.com/1424-8220/21/19/6530/htm).
- **Calculate intrinsic parameters:** - **Calculate intrinsic parameters:**