Skip to content

Commit 7a95e70

Browse files
authored
feat(pose_estimation): support multiprocessing videos_to_poses (#130)
* feat(pose_estimation): support multiprocessing videos_to_poses * review: use tqdm process_map
1 parent 1845ea4 commit 7a95e70

2 files changed

Lines changed: 39 additions & 14 deletions

File tree

src/python/pose_format/bin/directory.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
from typing import List
55
import logging
66
from tqdm import tqdm
7+
from tqdm.contrib.concurrent import process_map
8+
import psutil
9+
import os
10+
from functools import partial
711

812
# Note: untested other than .mp4. Support for .webm may have issues: https://github.com/sign-language-processing/pose/pull/126
913
SUPPORTED_VIDEO_FORMATS = [".mp4", ".mov", ".avi", ".mkv", ".flv", ".wmv", ".webm"]
@@ -79,6 +83,22 @@ def get_corresponding_pose_path(video_path: Path, keep_video_suffixes: bool = Fa
7983
return video_path.with_suffix(".pose")
8084

8185

86+
def process_video(keep_video_suffixes: bool, pose_format: str, additional_config: dict, vid_path: Path) -> bool:
87+
print(f'Estimating {vid_path} on CPU {psutil.Process().cpu_num()}')
88+
89+
try:
90+
pose_path = get_corresponding_pose_path(video_path=vid_path, keep_video_suffixes=keep_video_suffixes)
91+
if pose_path.is_file():
92+
print(f"Skipping {vid_path}, corresponding .pose file already created.")
93+
else:
94+
pose_video(vid_path, pose_path, pose_format, additional_config, progress=False)
95+
return True
96+
97+
except ValueError as e:
98+
print(f"ValueError on {vid_path}")
99+
logging.exception(e)
100+
101+
82102
def main():
83103
parser = argparse.ArgumentParser()
84104
parser.add_argument(
@@ -114,6 +134,13 @@ def main():
114134
default=SUPPORTED_VIDEO_FORMATS,
115135
help="Video extensions to search for. Defaults to searching for all supported.",
116136
)
137+
parser.add_argument(
138+
"--num-workers",
139+
type=int,
140+
default=1,
141+
help="Number of multiprocessing workers.",
142+
required=False
143+
)
117144
parser.add_argument(
118145
"--additional-config",
119146
type=str,
@@ -144,15 +171,14 @@ def main():
144171

145172
pose_with_no_errors_count = 0
146173

147-
for vid_path in tqdm(videos_with_missing_pose_files):
148-
try:
149-
pose_path = get_corresponding_pose_path(video_path=vid_path, keep_video_suffixes=args.keep_video_suffixes)
150-
if pose_path.is_file():
151-
print(f"Skipping {vid_path}, corresponding .pose file already created.")
152-
continue
153-
pose_video(vid_path, pose_path, args.format, additional_config)
174+
if args.num_workers == 1:
175+
print('Process sequentially ...')
176+
else:
177+
print(f'Multiprocessing with {args.num_workers} workers on {len(os.sched_getaffinity(0))} available CPUs ...')
178+
179+
func = partial(process_video, args.keep_video_suffixes, args.format, additional_config)
180+
for success in process_map(func, videos_with_missing_pose_files, max_workers=args.num_workers):
181+
if success:
154182
pose_with_no_errors_count += 1
155-
except ValueError as e:
156-
print(f"ValueError on {vid_path}")
157-
logging.exception(e)
183+
158184
print(f"Successfully created pose files for {pose_with_no_errors_count}/{len(videos_with_missing_pose_files)} video files")

src/python/pose_format/bin/pose_estimation.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def load_video_frames(cap: cv2.VideoCapture):
1515
cap.release()
1616

1717

18-
def pose_video(input_path: str, output_path: str, format: str, additional_config: dict):
18+
def pose_video(input_path: str, output_path: str, format: str, additional_config: dict = {'model_complexity': 1}, progress: bool = True):
1919
# Load video frames
2020
print('Loading video ...')
2121
cap = cv2.VideoCapture(input_path)
@@ -27,13 +27,12 @@ def pose_video(input_path: str, output_path: str, format: str, additional_config
2727
# Perform pose estimation
2828
print('Estimating pose ...')
2929
if format == 'mediapipe':
30-
additional_holistic_config = {'model_complexity': 1} | additional_config
3130
pose = load_holistic(frames,
3231
fps=fps,
3332
width=width,
3433
height=height,
35-
progress=True,
36-
additional_holistic_config=additional_holistic_config)
34+
progress=progress,
35+
additional_holistic_config=additional_config)
3736
else:
3837
raise NotImplementedError('Pose format not supported')
3938

0 commit comments

Comments
 (0)