From 704d0a63b758dfb6692f03c3d0ae091f2cee7e74 Mon Sep 17 00:00:00 2001 From: davidpagnon Date: Tue, 22 Oct 2024 23:18:00 +0200 Subject: [PATCH] Edits to hunmin's pull request (multi-person synchro) --- Content/synchro_multi.jpg | Bin 0 -> 61805 bytes Pose2Sim/Demo_Batch/Config.toml | 3 +- Pose2Sim/Demo_Batch/Trial_1/Config.toml | 3 +- Pose2Sim/Demo_Batch/Trial_2/Config.toml | 3 +- Pose2Sim/Demo_MultiPerson/Config.toml | 7 +- Pose2Sim/Demo_SinglePerson/Config.toml | 3 +- Pose2Sim/filtering.py | 2 +- Pose2Sim/poseEstimation.py | 24 +- Pose2Sim/synchronization.py | 385 ++++++++++++++++++++++-- README.md | 17 +- 10 files changed, 392 insertions(+), 55 deletions(-) create mode 100644 Content/synchro_multi.jpg diff --git a/Content/synchro_multi.jpg b/Content/synchro_multi.jpg new file mode 100644 index 0000000000000000000000000000000000000000..54cfb012705cf892aef6b68a4a2943c9fa086928 GIT binary patch literal 61805 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 len(cap): + return None, [] + image_path = cap[frame_number] + frame = cv2.imread(image_path) + if frame is None: + return None, [] + frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) + + else: + raise ValueError("Input must be either a video capture object or a list of image file paths.") + + # Get the corresponding JSON file for bounding boxes + json_file_name = frame_to_json.get(frame_number) + bounding_boxes_list = [] + if json_file_name: + json_file_path = os.path.join(pose_dir, json_dir_name, json_file_name) + bounding_boxes_list.extend(bounding_boxes(json_file_path)) + + return frame_rgb, bounding_boxes_list + + + +def draw_bounding_boxes_and_annotations(ax, bounding_boxes_list, rects, annotations): + ''' + Draws the bounding boxes and annotations on the given axes. + + INPUTS: + - ax: The axes object to draw on. + - bounding_boxes_list: list of tuples. Each tuple contains (x_min, y_min, x_max, y_max) of a bounding box. + - rects: List to store rectangle patches representing bounding boxes. + - annotations: List to store text annotations for each bounding box. + + OUTPUTS: + - None. Modifies rects and annotations in place. + ''' + + # Clear existing rectangles and annotations + for items in [rects, annotations]: + for item in items: + item.remove() + items.clear() + + # Draw bounding boxes and annotations + for idx, (x_min, y_min, x_max, y_max) in enumerate(bounding_boxes_list): + if not np.isfinite([x_min, y_min, x_max, y_max]).all(): + continue # Skip invalid bounding boxes for solve issue(posx and posy should be finite values) + + rect = plt.Rectangle( + (x_min, y_min), x_max - x_min, y_max - y_min, + linewidth=1, edgecolor='white', facecolor=(1, 1, 1, 0.1), + linestyle='-', path_effects=[patheffects.withSimplePatchShadow()], zorder=2 + ) # add shadow + ax.add_patch(rect) + rects.append(rect) + + annotation = ax.text( + x_min, y_min - 10, f'Person {idx}', color='white', fontsize=7, fontweight='normal', + bbox=dict(facecolor='black', alpha=0.5, boxstyle='round,pad=0.3'), zorder=3 + ) + annotations.append(annotation) + + +def reset_styles(rects, annotations): + ''' + Resets the styles of the rectangles and annotations to default. + + INPUTS: + - rects: List of rectangle patches representing bounding boxes. + - annotations: List of text annotations for each bounding box. + + OUTPUTS: + - None. Modifies rects and annotations in place. + ''' + + for rect, annotation in zip(rects, annotations): + rect.set_linewidth(1) + rect.set_edgecolor('white') + rect.set_facecolor((1, 1, 1, 0.1)) + annotation.set_fontsize(7) + annotation.set_fontweight('normal') + + +def highlight_bounding_box(rect, annotation): + ''' + Highlights a rectangle and its annotation. + + INPUTS: + - rect: Rectangle patch to highlight. + - annotation: Text annotation to highlight. + + OUTPUTS: + - None. Modifies rect and annotation in place. + ''' + + rect.set_linewidth(2) + rect.set_edgecolor('yellow') + rect.set_facecolor((1, 1, 0, 0.2)) + annotation.set_fontsize(8) + annotation.set_fontweight('bold') + + +def on_hover(event, fig, rects, annotations, bounding_boxes_list): + ''' + Highlights the bounding box and annotation when the mouse hovers over a person in the plot. + + INPUTS: + - event: The hover event. + - fig: The figure object. + - rects: The rectangles representing bounding boxes. + - annotations: The annotations corresponding to each bounding box. + - bounding_boxes_list: List of tuples containing bounding box coordinates. + + OUTPUTS: + - None. This function updates the plot in place. + ''' + + if event.xdata is None or event.ydata is None: + return + + # Reset styles of all rectangles and annotations + reset_styles(rects, annotations) + + # Find and highlight the bounding box under the mouse cursor + # remove NaN bounding boxes for make sure matching with rects + bounding_boxes_list = [bbox for bbox in bounding_boxes_list if np.all(np.isfinite(bbox)) and not np.any(np.isnan(bbox))] + for idx, (x_min, y_min, x_max, y_max) in enumerate(bounding_boxes_list): + if x_min <= event.xdata <= x_max and y_min <= event.ydata <= y_max: + highlight_bounding_box(rects[idx], annotations[idx]) + break + + fig.canvas.draw_idle() + + +def on_click(event, ax, bounding_boxes_list, selected_idx_container): + ''' + Detects if a bounding box is clicked and records the index of the selected person. + + INPUTS: + - event: The click event. + - ax: The axes object of the plot. + - bounding_boxes_list: List of tuples containing bounding box coordinates. + - selected_idx_container: List with one element to store the selected person's index. + + OUTPUTS: + - None. Updates selected_idx_container[0] with the index of the selected person. + ''' + + if event.inaxes != ax or event.xdata is None or event.ydata is None: + return + + for idx, (x_min, y_min, x_max, y_max) in enumerate(bounding_boxes_list): + if x_min <= event.xdata <= x_max and y_min <= event.ydata <= y_max: + selected_idx_container[0] = idx + plt.close() + break + + +def update_play(cap, image, slider, frame_to_json, pose_dir, json_dir_name, rects, annotations, bounding_boxes_list, ax, fig): + ''' + Updates the plot when the slider value changes. + + INPUTS: + - cap: cv2.VideoCapture. The video capture object. + - image: The image object in the plot. + - slider: The slider widget controlling the frame number. + - frame_to_json: dict. Mapping from frame numbers to JSON file names. + - pose_dir: str. Path to the directory containing pose data. + - json_dir_name: str. Name of the JSON directory for the current camera. + - rects: List of rectangle patches representing bounding boxes. + - annotations: List of text annotations for each bounding box. + - bounding_boxes_list: List of tuples to store bounding boxes for the current frame. + - ax: The axes object of the plot. + - fig: The figure object containing the plot. + + OUTPUTS: + - None. Updates the plot with the new frame, bounding boxes, and annotations. + ''' + + frame_number = int(slider.val) + + frame_rgb, bounding_boxes_list_new = load_frame_and_bounding_boxes(cap, frame_number, frame_to_json, pose_dir, json_dir_name) + if frame_rgb is None: + return + + # Update frame image + image.set_data(frame_rgb) + + # Update bounding boxes + bounding_boxes_list.clear() + bounding_boxes_list.extend(bounding_boxes_list_new) + + # Draw bounding boxes and annotations + draw_bounding_boxes_and_annotations(ax, bounding_boxes_list, rects, annotations) + fig.canvas.draw_idle() + + +def get_selected_id_list(multi_person, vid_or_img_files, cam_names, cam_nb, json_files_names_range, search_around_frames, pose_dir, json_dirs_names): + ''' + Allows the user to select a person from each camera by clicking on their bounding box in the video frames. + + INPUTS: + - multi_person: bool. Indicates whether multiple people are present in the videos. + - vid_or_img_files: list of str. Paths to the video files for each camera or to the image directories for each camera. + - cam_names: list of str. Names of the cameras. + - cam_nb: int. Number of cameras. + - json_files_names_range: list of lists. Each sublist contains JSON file names for a camera. + - search_around_frames: list of tuples. Each tuple contains (start_frame, end_frame) for searching frames. + - pose_dir: str. Path to the directory containing pose data. + - json_dirs_names: list of str. Names of the JSON directories for each camera. + + OUTPUTS: + - selected_id_list: list of int or None. List of the selected person indices for each camera. + ''' + + if not multi_person: + return [None] * cam_nb + + else: + logging.info('Multi_person mode: selecting the person to synchronize on for each camera.') + selected_id_list = [] + try: # video files + video_files_dict = {cam_name: file for cam_name in cam_names for file in vid_or_img_files if cam_name in os.path.basename(file)} + except: # image directories + video_files_dict = {cam_name: files for cam_name in cam_names for files in vid_or_img_files if cam_name in os.path.basename(files[0])} + + for i, cam_name in enumerate(cam_names): + vid_or_img_files_cam = video_files_dict.get(cam_name) + if not vid_or_img_files_cam: + logging.warning(f'No video file nor image directory found for camera {cam_name}') + selected_id_list.append(None) + continue + try: + cap = cv2.VideoCapture(vid_or_img_files_cam) + if not cap.isOpened(): + raise + except: + cap = vid_or_img_files_cam + + frame_to_json = {int(re.split(r'(\d+)', name)[-2]): name for name in json_files_names_range[i]} + frame_number = search_around_frames[i][0] + + frame_rgb, bounding_boxes_list = load_frame_and_bounding_boxes(cap, frame_number, frame_to_json, pose_dir, json_dirs_names[i]) + if frame_rgb is None: + logging.warning(f'Cannot read frame {frame_number} from video {vid_or_img_files_cam}') + selected_id_list.append(None) + if isinstance(cap, cv2.VideoCapture): + cap.release() + continue + + # Initialize plot + frame_height, frame_width = frame_rgb.shape[:2] + fig_width, fig_height = frame_width / 200, frame_height / 250 + + fig, ax = plt.subplots(figsize=(fig_width, fig_height)) + ax.imshow(frame_rgb) + ax.set_title(f'{cam_name}: select the person to synchronize on', fontsize=10, color='black', pad=15) + ax.axis('off') + + rects, annotations = [], [] + draw_bounding_boxes_and_annotations(ax, bounding_boxes_list, rects, annotations) + + selected_idx_container = [None] + + # Event handling + fig.canvas.mpl_connect('motion_notify_event', lambda event: on_hover(event, fig, rects, annotations, bounding_boxes_list)) + fig.canvas.mpl_connect('button_press_event', lambda event: on_click(event, ax, bounding_boxes_list, selected_idx_container)) + + # Add slider + ax_slider = plt.axes([ax.get_position().x0, 0.05, ax.get_position().width, 0.05]) + slider = Slider(ax_slider, 'Frame ', search_around_frames[i][0], search_around_frames[i][1] - 1, valinit=frame_number, valfmt='%0.0f') + + # Customize slider + slider.label.set_fontsize(10) + slider.poly.set_edgecolor((0, 0, 0, 0.5)) + slider.poly.set_facecolor('lightblue') + slider.poly.set_linewidth(1) + + # Connect the update function to the slider + slider.on_changed(lambda val: update_play(cap, ax.images[0], slider, frame_to_json, pose_dir, json_dirs_names[i], rects, annotations, bounding_boxes_list, ax, fig)) + + # Show the plot and handle events + plt.show() + cap.release() + + if selected_idx_container[0] == None: + selected_idx_container[0] = 0 + logging.warning(f'No person selected for camera {cam_name}: defaulting to person 0') + selected_id_list.append(selected_idx_container[0]) + logging.info(f'--> Camera #{i}: selected person #{selected_idx_container[0]}') + logging.info('') + + return selected_id_list + + +def convert_json2pandas(json_files, likelihood_threshold=0.6, keypoints_ids=[], multi_person=False, selected_id=None): ''' Convert a list of JSON files to a pandas DataFrame. Only takes one person in the JSON file. @@ -84,7 +406,7 @@ def convert_json2pandas(json_files, likelihood_threshold=0.6, keypoints_ids=[]): with open(j_p) as j_f: try: json_data_all = json.load(j_f)['people'] - + # # previous approach takes person #0 # json_data = json_data_all[0] # json_data = np.array([json_data['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids]) @@ -97,17 +419,25 @@ def convert_json2pandas(json_files, likelihood_threshold=0.6, keypoints_ids=[]): # json_data = np.array([max_confidence_person['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids]) # latest approach: uses person with largest bounding box - bbox_area = [ - (keypoints[:, 0].max() - keypoints[:, 0].min()) * (keypoints[:, 1].max() - keypoints[:, 1].min()) - if 'pose_keypoints_2d' in p else 0 - for p in json_data_all - for keypoints in [np.array([p['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids])] - ] - max_area_person = json_data_all[np.argmax(bbox_area)] - json_data = np.array([max_area_person['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids]) + if not multi_person: + bbox_area = [ + (keypoints[:, 0].max() - keypoints[:, 0].min()) * (keypoints[:, 1].max() - keypoints[:, 1].min()) + if 'pose_keypoints_2d' in p else 0 + for p in json_data_all + for keypoints in [np.array([p['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids])] + ] + max_area_person = json_data_all[np.argmax(bbox_area)] + json_data = np.array([max_area_person['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids]) + + elif multi_person: + if selected_id is not None: # We can sfely assume that selected_id is always not greater than len(json_data_all) because padding with 0 was done in the previous step + selected_person = json_data_all[selected_id] + json_data = np.array([selected_person['pose_keypoints_2d'][3*i:3*i+3] for i in keypoints_ids]) + else: + json_data = [np.nan] * nb_coords * 3 - # remove points with low confidence - json_data = np.array([j if j[2]>likelihood_threshold else [np.nan, np.nan, np.nan] for j in json_data]).ravel().tolist() + # Remove points with low confidence + json_data = np.array([j if j[2]>likelihood_threshold else [np.nan, np.nan, np.nan] for j in json_data]).ravel().tolist() except: # print(f'No person found in {os.path.basename(json_dir)}, frame {i}') json_data = [np.nan] * nb_coords*3 @@ -274,10 +604,15 @@ def synchronize_cams_all(config_dict): # Determine frame rate video_dir = os.path.join(project_dir, 'videos') vid_img_extension = config_dict['pose']['vid_img_extension'] - video_files = glob.glob(os.path.join(video_dir, '*'+vid_img_extension)) + vid_or_img_files = glob.glob(os.path.join(video_dir, '*'+vid_img_extension)) + if not vid_or_img_files: # video_files is then img_dirs + image_folders = [f for f in os.listdir(video_dir) if os.path.isdir(os.path.join(video_dir, f))] + for image_folder in image_folders: + vid_or_img_files.append(glob.glob(os.path.join(video_dir, image_folder, '*'+vid_img_extension))) + if fps == 'auto': try: - cap = cv2.VideoCapture(video_files[0]) + cap = cv2.VideoCapture(vid_or_img_files[0]) cap.read() if cap.read()[0] == False: raise @@ -286,17 +621,6 @@ def synchronize_cams_all(config_dict): fps = 60 lag_range = time_range_around_maxspeed*fps # frames - - # Warning if multi_person - if multi_person: - logging.warning('\nYou set your project as a multi-person one: make sure you set `approx_time_maxspeed` and `time_range_around_maxspeed` at times where one single person is in the scene, or you may get inaccurate results.') - do_synchro = input('Do you want to continue? (y/n)') - if do_synchro.lower() not in ["y","yes"]: - logging.warning('Synchronization cancelled.') - return - else: - logging.warning('Synchronization will be attempted.\n') - # Retrieve keypoints from model try: # from skeletons.py model = eval(pose_model) @@ -363,8 +687,11 @@ def synchronize_cams_all(config_dict): if np.array([j==[] for j in json_files_names_range]).any(): raise ValueError(f'No json files found within the specified frame range ({frame_range}) at the times {approx_time_maxspeed} +/- {time_range_around_maxspeed} s.') + # Handle manual selection if multi person is True + selected_id_list = get_selected_id_list(multi_person, vid_or_img_files, cam_names, cam_nb, json_files_names_range, search_around_frames, pose_dir, json_dirs_names) + for i in range(cam_nb): - df_coords.append(convert_json2pandas(json_files_range[i], likelihood_threshold=likelihood_threshold, keypoints_ids=keypoints_ids)) + df_coords.append(convert_json2pandas(json_files_range[i], likelihood_threshold=likelihood_threshold, keypoints_ids=keypoints_ids, multi_person=multi_person, selected_id=selected_id_list[i])) df_coords[i] = drop_col(df_coords[i],3) # drop likelihood if keypoints_to_consider == 'right': kpt_indices = [i for i in range(len(keypoints_ids)) if keypoints_names[i].startswith('R') or keypoints_names[i].startswith('right')] @@ -431,4 +758,4 @@ def synchronize_cams_all(config_dict): json_offset_name = ''.join(j_split) shutil.copy(os.path.join(pose_dir, os.path.basename(j_dir), j_file), os.path.join(sync_dir, os.path.basename(j_dir), json_offset_name)) - logging.info(f'Synchronized json files saved in {sync_dir}.') + logging.info(f'Synchronized json files saved in {sync_dir}.') \ No newline at end of file diff --git a/README.md b/README.md index f735949..431c2c8 100644 --- a/README.md +++ b/README.md @@ -537,7 +537,9 @@ If you already have a calibration file, set `calibration_type` type to `convert` ### Synchronization > _**2D points can be triangulated only if they represent the same body position across all cameras: therefore, views need to be synchronized.**_\ -***N.B.:** Skip this step if your cameras are natively synchronized.* +For each camera, this computes mean vertical speed for the chosen keypoints, and finds the time offset for which their correlation is highest. + +>***N.B.:** Skip this step if your cameras are natively synchronized.* Open an Anaconda prompt or a terminal in a `Session` or `Trial` folder.\ Type `ipython`. @@ -551,21 +553,22 @@ Pose2Sim.synchronization()
-For each camera, this computes mean vertical speed for the chosen keypoints, and finds the time offset for which their correlation is highest.\ -All keypoints can be taken into account, or a subset of them. The user can also specify a time for each camera when the participant is roughly horizontally static but with a clear vertical motion (set `approx_time_maxspeed` and `time_range_around_maxspeed` accordingly). +In `multi_person` mode, a video will pop up to let the user choose on which person to synchronize.\ +All keypoints can be taken into account, or a subset of them.\ +The whole capture can be used for synchronization, or you can choose a time range when the participant is roughly horizontally static but with a clear vertical motion (set `approx_time_maxspeed` and `time_range_around_maxspeed` accordingly). + + *N.B.:* Works best when: -- only one participant is in the scene - the participant does not move towards or away from the cameras - they perform a clear vertical movement - the capture lasts at least 5 seconds long, so that there is enough data to synchronize on -- the capture lasts a few minutes maximum, so that camera are less likely to [drift with time](https://github.com/mprib/caliscope/discussions/496) +- the capture lasts a few minutes maximum, so that cameras are less likely to [drift with time](https://github.com/mprib/caliscope/discussions/496) *N.B.:* Alternatively, synchronize cameras using a flashlight, a clap, or a clear event. GoPro cameras can also be synchronized with a timecode, by GPS (outdoors), or with their app (slightly less reliable). -
### Associate persons across cameras @@ -614,7 +617,7 @@ If your triangulation is not satisfying, try and release the constraints in the ### Filtering 3D coordinates > _**Filter your 3D coordinates.**_\ -> Numerous filter types are provided, and can be tuned accordingly. +> Butterworth, Kalman, Butterworth on speed, Gaussian, LOESS, Median filters are available and can be tuned accordingly. Open an Anaconda prompt or a terminal in a `Session` or `Trial` folder.\ Type `ipython`.