-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #32 from freemocap/openpose
Openpose
- Loading branch information
Showing
7 changed files
with
413 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
skellytracker/trackers/openpose_tracker/openpose_model_info.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
from skellytracker.trackers.base_tracker.base_tracking_params import BaseTrackingParams | ||
|
||
|
||
class OpenPoseTrackingParams(BaseTrackingParams): | ||
openpose_exe_path: str | ||
output_json_path: str | ||
net_resolution: str = "-1x320" | ||
number_people_max: int = 1 | ||
write_video: bool = True | ||
openpose_output_resolution: str = "-1x-1" |
68 changes: 68 additions & 0 deletions
68
skellytracker/trackers/openpose_tracker/openpose_parser.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import json | ||
import numpy as np | ||
from pathlib import Path | ||
from tqdm import tqdm | ||
import re | ||
|
||
def extract_frame_index(filename): | ||
"""Extract the numeric part indicating the frame index from the filename.""" | ||
match = re.search(r"_(\d{12})_keypoints", filename) | ||
return int(match.group(1)) if match else None | ||
|
||
def parse_openpose_jsons(main_directory): | ||
"""Parse OpenPose JSON files from subdirectories within the main directory.""" | ||
main_directory = Path(main_directory) | ||
subdirectories = [d for d in main_directory.iterdir() if d.is_dir()] | ||
num_cams = len(subdirectories) | ||
|
||
# Check the first subdirectory to determine the number of frames | ||
sample_files = list(subdirectories[0].glob("*.json")) | ||
num_frames = len(sample_files) | ||
frame_indices = [extract_frame_index(f.name) for f in sample_files] | ||
frame_indices.sort() | ||
|
||
# Assuming standard OpenPose output | ||
body_markers = 25 | ||
hand_markers = 21 # Per hand | ||
face_markers = 70 | ||
num_markers = body_markers + 2 * hand_markers + face_markers | ||
|
||
data_array = np.full((num_cams, num_frames, num_markers, 3), np.nan) | ||
|
||
for cam_index, subdir in enumerate(subdirectories): | ||
json_files = sorted(subdir.glob("*.json"), key=lambda x: extract_frame_index(x.stem)) | ||
|
||
for file_index, json_file in tqdm(enumerate(json_files), desc = f'Processing {subdir.name} JSONS'): | ||
with open(json_file) as f: | ||
data = json.load(f) | ||
|
||
if data["people"]: | ||
keypoints = extract_keypoints(data["people"][0], body_markers, hand_markers, face_markers) | ||
data_array[cam_index, frame_indices[file_index], :, :] = keypoints | ||
|
||
return data_array | ||
|
||
def extract_keypoints(person_data, body_markers, hand_markers, face_markers): | ||
"""Extract and organize keypoints from person data.""" | ||
# Initialize a full array of NaNs for keypoints | ||
keypoints_array = np.full((body_markers + 2 * hand_markers + face_markers, 3), np.nan) | ||
|
||
# Populate the array with available data | ||
if "pose_keypoints_2d" in person_data: | ||
keypoints_array[:body_markers, :] = np.reshape(person_data["pose_keypoints_2d"], (-1, 3))[:body_markers, :] | ||
if "hand_left_keypoints_2d" in person_data and "hand_right_keypoints_2d" in person_data: | ||
keypoints_array[body_markers:body_markers + hand_markers, :] = np.reshape(person_data["hand_left_keypoints_2d"], (-1, 3))[:hand_markers, :] | ||
keypoints_array[body_markers + hand_markers:body_markers + 2*hand_markers, :] = np.reshape(person_data["hand_right_keypoints_2d"], (-1, 3))[:hand_markers, :] | ||
if "face_keypoints_2d" in person_data: | ||
keypoints_array[body_markers + 2*hand_markers:, :] = np.reshape(person_data["face_keypoints_2d"], (-1, 3))[:face_markers, :] | ||
|
||
return keypoints_array | ||
|
||
|
||
path_to_recording_folder = Path(r'D:\steen_pantsOn_gait_3_cameras') | ||
path_to_json_folder = path_to_recording_folder/'output_data'/'raw_data'/'openpose_json' | ||
path_to_save_raw_data = path_to_recording_folder/'output_data'/'raw_data'/'openpose2dData_numCams_numFrames_numTrackedPoints_pixelXY.npy' | ||
|
||
data = parse_openpose_jsons(path_to_json_folder) | ||
np.save(path_to_save_raw_data, data) | ||
f = 2 |
101 changes: 101 additions & 0 deletions
101
skellytracker/trackers/openpose_tracker/openpose_recorder.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
import json | ||
from typing import Union | ||
import numpy as np | ||
from pathlib import Path | ||
from skellytracker.trackers.base_tracker.base_recorder import BaseCumulativeRecorder | ||
import re | ||
from tqdm import tqdm | ||
|
||
|
||
class OpenPoseRecorder(BaseCumulativeRecorder): | ||
def __init__(self, json_directory_path: Union[Path, str]): | ||
super().__init__() | ||
self.json_directory_path = Path(json_directory_path) | ||
|
||
def extract_frame_index(self, filename: str) -> Union[int, None]: | ||
"""Extract the numeric part indicating the frame index from the filename.""" | ||
match = re.search(r"_(\d{12})_keypoints", filename) | ||
return int(match.group(1)) if match else None | ||
|
||
def parse_openpose_jsons(self, main_directory: Union[Path, str]) -> np.ndarray: | ||
subdirectories = [d for d in Path(main_directory).iterdir() if d.is_dir()] | ||
num_cams = len(subdirectories) | ||
|
||
# Assuming the first subdirectory to determine the number of frames | ||
sample_files = list(subdirectories[0].glob("*.json")) | ||
num_frames = len(sample_files) | ||
frame_indices = [self.extract_frame_index(f.name) for f in sample_files] | ||
frame_indices.sort() | ||
|
||
# Assuming standard OpenPose output | ||
# TODO: move these definitions to openpose model info | ||
body_markers, hand_markers, face_markers = 25, 21, 70 | ||
num_markers = body_markers + 2 * hand_markers + face_markers | ||
|
||
data_array = np.full((num_cams, num_frames, num_markers, 3), np.nan) | ||
|
||
for cam_index, subdir in enumerate(subdirectories): | ||
json_files = sorted( | ||
subdir.glob("*.json"), key=lambda x: self.extract_frame_index(x.stem) | ||
) | ||
|
||
for file_index, json_file in enumerate( | ||
tqdm(json_files, desc=f"Processing {subdir.name} JSONs") | ||
): | ||
with open(json_file) as f: | ||
data = json.load(f) | ||
|
||
if data["people"]: | ||
keypoints = self.extract_keypoints( | ||
data["people"][0], body_markers, hand_markers, face_markers | ||
) | ||
data_array[cam_index, frame_indices[file_index], :, :] = keypoints | ||
|
||
return data_array | ||
|
||
def extract_keypoints( | ||
self, person_data, body_markers, hand_markers, face_markers | ||
) -> ( | ||
np.ndarray | ||
): # TODO: type hint person_data - is this an ndarray yet or something else? | ||
# TODO: marker numbers don't need to be passed into this function, they can just be referred to as OpenPoseModelInfo.xyz | ||
"""Extract and organize keypoints from person data.""" | ||
# Initialize a full array of NaNs for keypoints | ||
keypoints_array = np.full( | ||
(body_markers + 2 * hand_markers + face_markers, 3), np.nan | ||
) | ||
|
||
# Populate the array with available data | ||
if "pose_keypoints_2d" in person_data: | ||
keypoints_array[:body_markers, :] = np.reshape( | ||
person_data["pose_keypoints_2d"], (-1, 3) | ||
)[:body_markers, :] | ||
if ( | ||
"hand_left_keypoints_2d" in person_data | ||
and "hand_right_keypoints_2d" in person_data | ||
): | ||
keypoints_array[body_markers : body_markers + hand_markers, :] = np.reshape( | ||
person_data["hand_left_keypoints_2d"], (-1, 3) | ||
)[:hand_markers, :] | ||
keypoints_array[ | ||
body_markers + hand_markers : body_markers + 2 * hand_markers, : | ||
] = np.reshape(person_data["hand_right_keypoints_2d"], (-1, 3))[ | ||
:hand_markers, : | ||
] | ||
if "face_keypoints_2d" in person_data: | ||
keypoints_array[body_markers + 2 * hand_markers :, :] = np.reshape( | ||
person_data["face_keypoints_2d"], (-1, 3) | ||
)[:face_markers, :] | ||
|
||
return keypoints_array | ||
|
||
def process_tracked_objects(self, **kwargs) -> np.ndarray: | ||
""" | ||
Convert the recorded JSON data into the structured numpy array format. | ||
""" | ||
# In this case, the recorded_objects are already in the desired format, | ||
# so we simply return them. | ||
self.recorded_objects_array = self.parse_openpose_jsons( | ||
self.json_directory_path | ||
) | ||
return self.recorded_objects_array |
Oops, something went wrong.