Skip to content

Commit 2f27952

Browse files
committed
Automatic video discovery: no need for vid_img_extension anymore
1 parent 88a072d commit 2f27952

10 files changed

Lines changed: 62 additions & 54 deletions

File tree

Pose2Sim/Demo_Batch/Config.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ exclude_from_batch = [] # List of trials to be excluded from batch analysis, ['<
3535

3636

3737
[pose]
38-
vid_img_extension = 'mp4' # any video or image extension
39-
4038
pose_model = 'Body_with_feet' #With RTMLib:
4139
# - Body_with_feet (default HALPE_26 model),
4240
# - Whole_body_wrist (COCO_133_WRIST: body + feet + 2 hand_points),

Pose2Sim/Demo_Batch/Trial_1/Config.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@
3535

3636

3737
# [pose]
38-
# vid_img_extension = 'mp4' # any video or image extension
39-
4038
# pose_model = 'Body_with_feet' #With RTMLib:
4139
# # - Body_with_feet (default HALPE_26 model),
4240
# # - Whole_body_wrist (COCO_133_WRIST: body + feet + 2 hand_points),

Pose2Sim/Demo_Batch/Trial_2/Config.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ participant_mass = [70.0, 63.5] # float (eg 70.0), or list of floats (eg [70
3434
# # e.g. ['S00_P00_Participant/S00_P00_T00_StaticTrial', 'S00_P00_Participant/S00_P00_T01_BalancingTrial']
3535

3636
# [pose]
37-
# vid_img_extension = 'mp4' # any video or image extension
38-
3937
# pose_model = 'Body_with_feet' #With RTMLib:
4038
# # - Body_with_feet (default HALPE_26 model),
4139
# # - Whole_body_wrist (COCO_133_WRIST: body + feet + 2 hand_points),

Pose2Sim/Demo_MultiPerson/Config.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,6 @@ exclude_from_batch = [] # List of trials to be excluded from batch analysis, ['<
3535

3636

3737
[pose]
38-
vid_img_extension = 'mp4' # any video or image extension
39-
4038
pose_model = 'Body_with_feet' #With RTMLib:
4139
# - Body_with_feet (default HALPE_26 model),
4240
# - Whole_body_wrist (COCO_133_WRIST: body + feet + 2 hand_points),

Pose2Sim/Demo_SinglePerson/Config.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,6 @@ exclude_from_batch = [] # List of trials to be excluded from batch analysis, ['<
3434

3535

3636
[pose]
37-
vid_img_extension = 'mp4' # any video or image extension
38-
3937
pose_model = 'Body_with_feet' #With RTMLib:
4038
# - Body_with_feet (default HALPE_26 model),
4139
# - Whole_body_wrist (COCO_133_WRIST: body + feet + 2 hand_points),

Pose2Sim/common.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
'''
1212

1313
## INIT
14+
import os
1415
import toml
1516
import json
1617
import numpy as np
@@ -159,6 +160,36 @@ def show(self):
159160

160161

161162
## FUNCTIONS
163+
def is_video_file(path):
164+
'''
165+
Check if the given path is a video file based on its extension.
166+
167+
INPUTS:
168+
- path (str): The file path to check.
169+
170+
OUTPUTS:
171+
- bool: True if the path is a video file, False otherwise.
172+
'''
173+
174+
video_extensions = {'.mp4', '.avi', '.mov', '.mkv', '.wmv', '.flv', '.webm', '.m4v', '.mpeg', '.mpg'}
175+
return os.path.isfile(path) and os.path.splitext(path)[1].lower() in video_extensions
176+
177+
178+
def is_image_file(path):
179+
'''
180+
Check if the given path is an image file based on its extension.
181+
182+
INPUTS:
183+
- path (str): The file path to check.
184+
185+
OUTPUTS:
186+
- bool: True if the path is an image file, False otherwise.
187+
'''
188+
189+
image_extensions = {'.png', '.jpg', '.jpeg', '.bmp', '.tif', '.tiff', '.webp'}
190+
return os.path.isfile(path) and os.path.splitext(path)[1].lower() in image_extensions
191+
192+
162193
def read_trc(trc_path):
163194
'''
164195
Read a TRC file and extract its contents.

Pose2Sim/filtering.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
from filterpy.common import Q_discrete_white_noise
4646

4747
from Pose2Sim.common import plotWindow
48-
from Pose2Sim.common import convert_to_c3d, read_trc
48+
from Pose2Sim.common import convert_to_c3d, read_trc, is_video_file
4949

5050
## AUTHORSHIP INFORMATION
5151
__author__ = "David Pagnon"
@@ -754,8 +754,7 @@ def filter_all(config_dict):
754754
# Get frame_rate
755755
video_dir = os.path.join(project_dir, 'videos')
756756
frame_range = config_dict.get('project', {}).get('frame_range', 'auto')
757-
vid_img_extension = config_dict.get('pose', {}).get('vid_img_extension', 'mp4')
758-
video_files = glob.glob(os.path.join(video_dir, '*'+vid_img_extension))
757+
video_files = sorted([f for f in glob.glob(os.path.join(video_dir, '*')) if is_video_file(f)])
759758
frame_rate = config_dict.get('project', {}).get('frame_rate', 'auto')
760759
if frame_rate == 'auto':
761760
try:
@@ -765,7 +764,7 @@ def filter_all(config_dict):
765764
raise
766765
frame_rate = round(cap.get(cv2.CAP_PROP_FPS))
767766
except:
768-
logging.warning(f'Cannot read video. Frame rate will be set to 60 fps.')
767+
logging.warning(f'Cannot read video. Frame rate will be set to 30 fps.')
769768
frame_rate = 30
770769

771770
# Trc paths

Pose2Sim/poseEstimation.py

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
from rtmlib.tools.object_detection.post_processings import nms
4848
from Pose2Sim.common import natural_sort_key, sort_people_sports2d, sort_people_deepsort,\
4949
colors, thickness, draw_bounding_box, draw_keypts, draw_skel, bbox_xyxy_compute, \
50-
get_screen_size, calculate_display_size
50+
get_screen_size, calculate_display_size, is_video_file, is_image_file
5151
from Pose2Sim.skeletons import *
5252

5353
np.set_printoptions(legacy='1.21') # otherwise prints np.float64(3.0) rather than 3.0
@@ -275,7 +275,7 @@ def save_to_openpose(json_file_path, keypoints, scores):
275275

276276
# Save JSON output for each frame
277277
json_output_dir = os.path.abspath(os.path.join(json_file_path, '..'))
278-
if not os.path.isdir(json_output_dir): os.makedirs(json_output_dir)
278+
os.makedirs(json_output_dir, exist_ok=True)
279279
with open(json_file_path, 'w') as json_file:
280280
json.dump(json_output, json_file)
281281

@@ -310,7 +310,7 @@ def process_video(video_path, pose_tracker, pose_model, frame_range, average_lik
310310
raise NameError(f"{video_path} is not a video. Images must be put in one subdirectory per camera.")
311311

312312
pose_dir = os.path.abspath(os.path.join(video_path, '..', '..', 'pose'))
313-
if not os.path.isdir(pose_dir): os.makedirs(pose_dir)
313+
os.makedirs(pose_dir, exist_ok=True)
314314
video_name_wo_ext = os.path.splitext(os.path.basename(video_path))[0]
315315
json_output_dir = os.path.join(pose_dir, f'{video_name_wo_ext}_json')
316316
output_video_path = os.path.join(pose_dir, f'{video_name_wo_ext}_pose.mp4')
@@ -437,13 +437,12 @@ def process_video(video_path, pose_tracker, pose_model, frame_range, average_lik
437437
cv2.destroyAllWindows()
438438

439439

440-
def process_images(image_folder_path, vid_img_extension, pose_tracker, pose_model, output_format, fps, save_video, save_images, display_detection, frame_range, tracking_mode, max_distance_px, deepsort_tracker):
440+
def process_images(image_folder_path, pose_tracker, pose_model, output_format, fps, save_video, save_images, display_detection, frame_range, tracking_mode, max_distance_px, deepsort_tracker):
441441
'''
442442
Estimate pose estimation from a folder of images
443443
444444
INPUTS:
445445
- image_folder_path: str. Path to the input image folder
446-
- vid_img_extension: str. Extension of the image files
447446
- pose_tracker: PoseTracker. Initialized pose tracker object from RTMLib
448447
- pose_model: str. The pose model to use for pose estimation (HALPE_26, COCO_133, COCO_17)
449448
- output_format: str. Output format for the pose estimation results ('openpose', 'mmpose', 'deeplabcut')
@@ -461,13 +460,14 @@ def process_images(image_folder_path, vid_img_extension, pose_tracker, pose_mode
461460
'''
462461

463462
pose_dir = os.path.abspath(os.path.join(image_folder_path, '..', '..', 'pose'))
464-
if not os.path.isdir(pose_dir): os.makedirs(pose_dir)
463+
os.makedirs(pose_dir, exist_ok=True)
465464
json_output_dir = os.path.join(pose_dir, f'{os.path.basename(image_folder_path)}_json')
466465
output_video_path = os.path.join(pose_dir, f'{os.path.basename(image_folder_path)}_pose.mp4')
467466
img_output_dir = os.path.join(pose_dir, f'{os.path.basename(image_folder_path)}_img')
468467

469-
image_files = glob.glob(os.path.join(image_folder_path, '*'+vid_img_extension))
470-
image_files = sorted(image_files, key=natural_sort_key)
468+
image_files = sorted([f for f in glob.glob(os.path.join(image_folder_path, '*')) if is_image_file(f)], key=natural_sort_key)
469+
if len(image_files) == 0:
470+
raise NameError(f'No image files found in {image_folder_path}.')
471471

472472
if save_video or display_detection:
473473
first_frame = cv2.imread(image_files[0])
@@ -615,7 +615,6 @@ def estimate_pose_all(config_dict):
615615

616616
pose_model = config_dict.get('pose', {}).get('pose_model', 'Body_with_feet')
617617
mode = config_dict.get('pose', {}).get('mode', 'balanced')
618-
vid_img_extension = config_dict.get('pose', {}).get('vid_img_extension', 'mp4')
619618

620619
output_format = config_dict.get('pose', {}).get('output_format', 'openpose')
621620
save_video = True if 'to_video' in config_dict.get('pose', {}).get('save_video', 'to_video') else False
@@ -644,7 +643,7 @@ def estimate_pose_all(config_dict):
644643
deepsort_params = {}
645644

646645
# Determine frame rate
647-
video_files = sorted(glob.glob(os.path.join(video_dir, '*'+vid_img_extension)))
646+
video_files = sorted([f for f in glob.glob(os.path.join(video_dir, '*')) if is_video_file(f)], key=natural_sort_key)
648647
frame_rate = config_dict.get('project', {}).get('frame_rate', 'auto')
649648
if frame_rate == 'auto':
650649
try:
@@ -654,10 +653,9 @@ def estimate_pose_all(config_dict):
654653
raise
655654
frame_rate = round(cap.get(cv2.CAP_PROP_FPS))
656655
except:
657-
logging.warning(f'Cannot read video. Frame rate will be set to 60 fps.')
656+
logging.warning(f'Cannot read video. Frame rate will be set to 30 fps.')
658657
frame_rate = 30
659658

660-
661659
# Select the appropriate model based on the model_type
662660
logging.info('Estimating pose...\n')
663661
pose_model_name = pose_model
@@ -722,7 +720,7 @@ def estimate_pose_all(config_dict):
722720

723721
if not len(video_files) == 0:
724722
# Process video files
725-
logging.info(f'Found {len(video_files)} video files with {vid_img_extension} extension.')
723+
logging.info(f'Found {len(video_files)} video files in {video_dir}.')
726724

727725
# In parallel
728726
if parallel_pose != 1 and len(video_files) > 1:
@@ -762,22 +760,11 @@ def estimate_pose_all(config_dict):
762760

763761
else:
764762
# Process image folders
765-
image_folders = sorted([os.path.join(video_dir,f) for f in os.listdir(video_dir) if os.path.isdir(os.path.join(video_dir, f))])
766-
empty_folders = [folder for folder in image_folders if len(glob.glob(os.path.join(folder, '*'+vid_img_extension)))==0]
767-
if len(empty_folders) != 0:
768-
raise NameError(f'No image files with {vid_img_extension} extension found in {empty_folders}.')
769-
elif len(image_folders) == 0:
770-
raise NameError(f'No image folders containing files with {vid_img_extension} extension found in {video_dir}.')
763+
image_folders = sorted([os.path.join(video_dir, f) for f in os.listdir(video_dir) if os.path.isdir(os.path.join(video_dir, f))])
764+
# Keep only folders that contain at least one image file
765+
image_folders = [folder for folder in image_folders
766+
if any(is_image_file(os.path.join(folder, f)) for f in os.listdir(folder))]
767+
if len(image_folders) == 0:
768+
raise NameError(f'No video files and no image folders with recognized image extensions found in {video_dir}.')
771769
else:
772-
logging.info(f'Found image folders with {vid_img_extension} extension.')
773-
try:
774-
pose_tracker = setup_pose_tracker(ModelClass, det_frequency, mode, False, backend, device)
775-
except:
776-
logging.error('Error: Pose estimation failed. Check in Config.toml that pose_model and mode are valid.')
777-
raise ValueError('Error: Pose estimation failed. Check in Config.toml that pose_model and mode are valid.')
778-
for image_folder in image_folders:
779-
pose_tracker.reset()
780-
image_folder_path = os.path.join(video_dir, image_folder)
781-
if tracking_mode == 'deepsort':
782-
deepsort_tracker.tracker.delete_all_tracks()
783-
process_images(image_folder_path, vid_img_extension, pose_tracker, pose_model, frame_range, average_likelihood_threshold_pose, output_format, frame_rate, save_video, save_images, display_detection, tracking_mode, max_distance_px, deepsort_tracker)
770+
logging.info(f'No video files found. Found {len(image_folders)} image folders in {video_dir}.')

Pose2Sim/synchronization.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@
5050
from matplotlib.widgets import TextBox, Button
5151
import logging
5252

53-
from Pose2Sim.common import sort_stringlist_by_last_number, bounding_boxes, interpolate_zeros_nans
53+
from Pose2Sim.common import sort_stringlist_by_last_number, bounding_boxes, interpolate_zeros_nans, \
54+
is_video_file, is_image_file
5455
from Pose2Sim.skeletons import *
5556

5657

@@ -1390,13 +1391,14 @@ def synchronize_cams_all(config_dict):
13901391

13911392
# Determine frame rate
13921393
video_dir = os.path.join(project_dir, 'videos')
1393-
vid_img_extension = config_dict.get('pose', {}).get('vid_img_extension', 'mp4')
1394-
vid_or_img_files = glob.glob(os.path.join(video_dir, '*'+vid_img_extension))
1394+
vid_or_img_files = sorted([f for f in glob.glob(os.path.join(video_dir, '*')) if is_video_file(f)])
13951395
if not vid_or_img_files: # video_files is then img_dirs
13961396
try:
13971397
image_folders = [f for f in os.listdir(video_dir) if os.path.isdir(os.path.join(video_dir, f))]
13981398
for image_folder in image_folders:
1399-
vid_or_img_files.append(glob.glob(os.path.join(video_dir, image_folder, '*'+vid_img_extension)))
1399+
img_files = sorted([f for f in glob.glob(os.path.join(video_dir, image_folder, '*')) if is_image_file(f)])
1400+
if img_files:
1401+
vid_or_img_files.append(img_files)
14001402
except:
14011403
logging.warning(f'No video files nor image directories found in {video_dir}.')
14021404

@@ -1408,7 +1410,7 @@ def synchronize_cams_all(config_dict):
14081410
raise
14091411
fps = round(cap.get(cv2.CAP_PROP_FPS))
14101412
except:
1411-
logging.warning(f'Cannot read video. Frame rate will be set to 60 fps.')
1413+
logging.warning(f'Cannot read video. Frame rate will be set to 30 fps.')
14121414
fps = 30
14131415
lag_range = time_range_around_maxspeed*fps # frames
14141416

Pose2Sim/triangulation.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757

5858
from Pose2Sim.common import retrieve_calib_params, computeP, weighted_triangulation, \
5959
reprojection, euclidean_distance, sort_people_sports2d, interpolate_zeros_nans, \
60-
sort_stringlist_by_last_number, zup2yup, convert_to_c3d
60+
sort_stringlist_by_last_number, zup2yup, convert_to_c3d, is_video_file
6161
from Pose2Sim.skeletons import *
6262

6363

@@ -172,8 +172,7 @@ def make_trc(config_dict, Q, keypoints_names, id_person=-1):
172172

173173
# Get frame_rate
174174
video_dir = os.path.join(project_dir, 'videos')
175-
vid_img_extension = config_dict.get('pose', {}).get('vid_img_extension', 'mp4')
176-
video_files = glob.glob(os.path.join(video_dir, '*'+vid_img_extension))
175+
video_files = sorted([f for f in glob.glob(os.path.join(video_dir, '*')) if is_video_file(f)])
177176
frame_rate = config_dict.get('project', {}).get('frame_rate', 'auto')
178177
if frame_rate == 'auto':
179178
try:
@@ -183,7 +182,7 @@ def make_trc(config_dict, Q, keypoints_names, id_person=-1):
183182
raise
184183
frame_rate = round(cap.get(cv2.CAP_PROP_FPS))
185184
except:
186-
logging.warning(f'Cannot read video. Frame rate will be set to 60 fps.')
185+
logging.warning(f'Cannot read video. Frame rate will be set to 30 fps.')
187186
frame_rate = 30
188187

189188
trc_f = f'{seq_name}_{Q.index[0]}-{Q.index[-1]}.trc'

0 commit comments

Comments
 (0)