From 08de0e06e138dbee9e1a75378af262fad5a2395d Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Tue, 3 Sep 2024 23:19:10 +0900 Subject: [PATCH 01/12] Adjust fontSize dynamically --- Sports2D/Demo/Config_demo.toml | 2 +- Sports2D/Utilities/common.py | 20 ++++++++++++++++++++ Sports2D/process.py | 5 ++++- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/Sports2D/Demo/Config_demo.toml b/Sports2D/Demo/Config_demo.toml index 95f06fc..0d087a7 100644 --- a/Sports2D/Demo/Config_demo.toml +++ b/Sports2D/Demo/Config_demo.toml @@ -52,7 +52,7 @@ keypoint_number_threshold = 0.3 # Person will be ignored if the number of good k [angles] display_angle_values_on = ['body','list'] # 'body', 'list', ['body', 'list'], []. Display angle values on the body, as a list in the upper left of the image, both, or do not display them. -fontSize = 0.3 +fontSize = 'auto' # 'auto' or your preference # Select joint angles among # ['Right ankle', 'Left ankle', 'Right knee', 'Left knee', 'Right hip', 'Left hip', 'Right shoulder', 'Left shoulder', 'Right elbow', 'Left elbow', 'Right wrist', 'Left wrist'] diff --git a/Sports2D/Utilities/common.py b/Sports2D/Utilities/common.py index 48fdbd3..af74f57 100644 --- a/Sports2D/Utilities/common.py +++ b/Sports2D/Utilities/common.py @@ -257,3 +257,23 @@ def euclidean_distance(q1, q2): euc_dist = np.sqrt(np.sum( [d**2 for d in dist])) return euc_dist + + +def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5): + ''' + Dynamically adjust font size according to both the area and the aspect ratio + ''' + + # Current demo video resolution (assuming it is the optimal resolution for the base font size=0.3) + base_width = 1768 + base_height = 994 + base_resolution = base_width * base_height + resolution = width * height + + # Consider the area of the video + area_scale_factor = resolution / base_resolution + adjusted_font_size = base_font_size * area_scale_factor + if resolution < base_resolution: + adjusted_font_size = base_font_size * area_scale_factor * scale_factor + + return max(min(adjusted_font_size, max_font_size), min_font_size) diff --git a/Sports2D/process.py b/Sports2D/process.py index 636d301..e9e8549 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -1043,7 +1043,6 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): angle_names = [angle_name.lower() for angle_name in angle_names] display_angle_values_on = config_dict.get('angles').get('display_angle_values_on') fontSize = config_dict.get('angles').get('fontSize') - thickness = 1 if fontSize < 0.8 else 2 flip_left_right = config_dict.get('angles').get('flip_left_right') # Post-processing settings @@ -1108,6 +1107,10 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): cv2.namedWindow(f'{video_file} Sports2D', cv2.WINDOW_NORMAL + cv2.WINDOW_KEEPRATIO) cv2.setWindowProperty(f'{video_file} Sports2D', cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_FULLSCREEN) + # Set up front size and thickness + if fontSize == 'auto' or fontSize == 'Auto': + fontSize = dynamic_fontSize(cam_width, cam_height) + thickness = 1 if fontSize < 0.8 else 2 # Set up pose tracker tracking_rtmlib = True if (tracking_mode == 'rtmlib' and tracking) else False From db4d29d3186bae53f9e9032784d8565a030b4733 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Tue, 3 Sep 2024 23:33:34 +0900 Subject: [PATCH 02/12] adding comments and changing scale factors --- Sports2D/Utilities/common.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Sports2D/Utilities/common.py b/Sports2D/Utilities/common.py index af74f57..d6b950e 100644 --- a/Sports2D/Utilities/common.py +++ b/Sports2D/Utilities/common.py @@ -259,7 +259,7 @@ def euclidean_distance(q1, q2): return euc_dist -def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5): +def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.7): ''' Dynamically adjust font size according to both the area and the aspect ratio ''' @@ -268,12 +268,17 @@ def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_f base_width = 1768 base_height = 994 base_resolution = base_width * base_height + + # input video resolution resolution = width * height # Consider the area of the video area_scale_factor = resolution / base_resolution adjusted_font_size = base_font_size * area_scale_factor + + # If font size is too small, it is hard to read if resolution < base_resolution: adjusted_font_size = base_font_size * area_scale_factor * scale_factor + # I believe that the font size should be at least 0.2 and maximum range is 1 (through several tests) return max(min(adjusted_font_size, max_font_size), min_font_size) From c9303147f914132e11a7c3267e21362d9a995ed0 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Tue, 3 Sep 2024 23:45:15 +0900 Subject: [PATCH 03/12] scale factor = 1.5 --- Sports2D/Utilities/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sports2D/Utilities/common.py b/Sports2D/Utilities/common.py index d6b950e..f903f2a 100644 --- a/Sports2D/Utilities/common.py +++ b/Sports2D/Utilities/common.py @@ -259,7 +259,7 @@ def euclidean_distance(q1, q2): return euc_dist -def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.7): +def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5): ''' Dynamically adjust font size according to both the area and the aspect ratio ''' From 78ea750cc84ce67548fd2cc4b74f665b1109f113 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Thu, 5 Sep 2024 15:28:58 +0900 Subject: [PATCH 04/12] thickness of Font,Skel,Keypts --- Sports2D/Utilities/common.py | 8 +++++++- Sports2D/process.py | 23 +++++++++++------------ 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/Sports2D/Utilities/common.py b/Sports2D/Utilities/common.py index f903f2a..f151040 100644 --- a/Sports2D/Utilities/common.py +++ b/Sports2D/Utilities/common.py @@ -259,7 +259,7 @@ def euclidean_distance(q1, q2): return euc_dist -def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5): +def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5, base_thickness=1): ''' Dynamically adjust font size according to both the area and the aspect ratio ''' @@ -282,3 +282,9 @@ def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_f # I believe that the font size should be at least 0.2 and maximum range is 1 (through several tests) return max(min(adjusted_font_size, max_font_size), min_font_size) + +def dynamic_thickness(font_size, base_thickness=1, thickness_scale=1/0.3, min_thickness=1): + ''' + Dynamically adjust the thickness of the lines according to the font size + ''' + return int(max(font_size * thickness_scale * base_thickness, min_thickness)) diff --git a/Sports2D/process.py b/Sports2D/process.py index e9e8549..5b7ec0f 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -112,7 +112,6 @@ (125, 0, 0), (0, 125, 0), (0, 0, 125), (125, 125, 0), (125, 0, 125), (0, 125, 125), (255, 125, 125), (125, 255, 125), (125, 125, 255), (255, 255, 125), (255, 125, 255), (125, 255, 255), (125, 125, 125), (255, 0, 125), (255, 125, 0), (0, 125, 255), (0, 255, 125), (125, 0, 255), (125, 255, 0), (0, 255, 0)] -thickness = 1 ## AUTHORSHIP INFORMATION @@ -480,7 +479,7 @@ def sort_people_rtmlib(pose_tracker, keypoints, scores): return sorted_keypoints, sorted_scores -def draw_dotted_line(img, start, direction, length, color=(0, 255, 0), gap=7, dot_length=3, thickness=thickness): +def draw_dotted_line(img, start, direction, length, color=(0, 255, 0), gap=7, dot_length=3, thickness=1): ''' Draw a dotted line with on a cv2 image @@ -540,7 +539,7 @@ def draw_bounding_box(img, X, Y, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], return img -def draw_skel(img, X, Y, model, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)]): +def draw_skel(img, X, Y, model, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], thickness=1): ''' Draws keypoints and skeleton for each person. Skeletons have a different color for each person. @@ -576,7 +575,7 @@ def draw_skel(img, X, Y, model, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)]): return img -def draw_keypts(img, X, Y, scores, cmap_str='RdYlGn'): +def draw_keypts(img, X, Y, scores, cmap_str='RdYlGn', thickness=1): ''' Draws keypoints and skeleton for each person. Keypoints' colors depend on their score. @@ -654,11 +653,11 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ # Draw angle if 'body' in display_angle_values_on: if len(ang_coords) == 2: # segment angle - app_point, vec = draw_segment_angle(img, ang_coords, flip) + app_point, vec = draw_segment_angle(img, ang_coords, flip, thickness=thickness) write_angle_on_body(img, ang, app_point, vec, np.array([1,0]), dist=20, color=(255,255,255), fontSize=fontSize, thickness=thickness) else: # joint angle - app_point, vec1, vec2 = draw_joint_angle(img, ang_coords, flip, right_angle) + app_point, vec1, vec2 = draw_joint_angle(img, ang_coords, flip, right_angle, thickness=thickness) write_angle_on_body(img, ang, app_point, vec1, vec2, dist=40, color=(0,255,0), fontSize=fontSize, thickness=thickness) # Write angle as a list on image with progress bar @@ -671,7 +670,7 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ return img -def draw_segment_angle(img, ang_coords, flip): +def draw_segment_angle(img, ang_coords, flip, thickness=1): ''' Draw a segment angle on the image. @@ -702,7 +701,7 @@ def draw_segment_angle(img, ang_coords, flip): return app_point, unit_segment_direction -def draw_joint_angle(img, ang_coords, flip, right_angle): +def draw_joint_angle(img, ang_coords, flip, right_angle, thickness=1): ''' Draw a joint angle on the image. @@ -1108,9 +1107,9 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): cv2.setWindowProperty(f'{video_file} Sports2D', cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_FULLSCREEN) # Set up front size and thickness - if fontSize == 'auto' or fontSize == 'Auto': + if fontSize.lower() == 'auto': fontSize = dynamic_fontSize(cam_width, cam_height) - thickness = 1 if fontSize < 0.8 else 2 + thickness = dynamic_thickness(fontSize) # Set up pose tracker tracking_rtmlib = True if (tracking_mode == 'rtmlib' and tracking) else False @@ -1202,8 +1201,8 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): if show_realtime_results or save_vid or save_img: img = frame.copy() img = draw_bounding_box(img, valid_X, valid_Y, colors=colors, fontSize=fontSize, thickness=thickness) - img = draw_keypts(img, valid_X, valid_Y, scores, cmap_str='RdYlGn') - img = draw_skel(img, valid_X, valid_Y, model, colors=colors) + img = draw_keypts(img, valid_X, valid_Y, scores, cmap_str='RdYlGn', thickness=thickness) + img = draw_skel(img, valid_X, valid_Y, model, colors=colors, thickness=thickness) img = draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ids, keypoints_names, angle_names, display_angle_values_on=display_angle_values_on, colors=colors, fontSize=fontSize, thickness=thickness) if show_realtime_results: From 5ded86c3655e9b5bd6656a892457c56d198a8cad Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Thu, 5 Sep 2024 15:31:01 +0900 Subject: [PATCH 05/12] remove unintended --- Sports2D/Utilities/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sports2D/Utilities/common.py b/Sports2D/Utilities/common.py index f151040..6d2d57f 100644 --- a/Sports2D/Utilities/common.py +++ b/Sports2D/Utilities/common.py @@ -259,7 +259,7 @@ def euclidean_distance(q1, q2): return euc_dist -def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5, base_thickness=1): +def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5): ''' Dynamically adjust font size according to both the area and the aspect ratio ''' From 50790419d30bd4d6eb912a72b46348634a122451 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Thu, 5 Sep 2024 15:42:51 +0900 Subject: [PATCH 06/12] Checking for fontSize is str --- Sports2D/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sports2D/process.py b/Sports2D/process.py index 5b7ec0f..88e1c1f 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -1107,7 +1107,7 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): cv2.setWindowProperty(f'{video_file} Sports2D', cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_FULLSCREEN) # Set up front size and thickness - if fontSize.lower() == 'auto': + if isinstance(fontSize, str) and fontSize.lower() == 'auto': fontSize = dynamic_fontSize(cam_width, cam_height) thickness = dynamic_thickness(fontSize) From 4d60edd27accf41b08b4ab625c8b40dc6f38b5e0 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Thu, 5 Sep 2024 16:25:23 +0900 Subject: [PATCH 07/12] comment for isinstance --- Sports2D/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sports2D/process.py b/Sports2D/process.py index 88e1c1f..ebb5539 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -1107,7 +1107,7 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): cv2.setWindowProperty(f'{video_file} Sports2D', cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_FULLSCREEN) # Set up front size and thickness - if isinstance(fontSize, str) and fontSize.lower() == 'auto': + if isinstance(fontSize, str) and fontSize.lower() == 'auto': # I add isinstance to avoid errors when running pytest (I guess, when the function runs twice). fontSize = dynamic_fontSize(cam_width, cam_height) thickness = dynamic_thickness(fontSize) From 5c065c9467e4376bf202a85637df9983ffc74413 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Mon, 9 Sep 2024 08:22:59 +0900 Subject: [PATCH 08/12] Modified based on feedback --- Sports2D/Utilities/common.py | 33 +------------------ Sports2D/process.py | 61 ++++++++++++++++++++++++------------ 2 files changed, 42 insertions(+), 52 deletions(-) diff --git a/Sports2D/Utilities/common.py b/Sports2D/Utilities/common.py index 6d2d57f..a9e5b62 100644 --- a/Sports2D/Utilities/common.py +++ b/Sports2D/Utilities/common.py @@ -256,35 +256,4 @@ def euclidean_distance(q1, q2): euc_dist = np.sqrt(np.sum( [d**2 for d in dist])) - return euc_dist - - -def dynamic_fontSize(width, height, base_font_size=0.3, min_font_size=0.2, max_font_size=1, scale_factor=1.5): - ''' - Dynamically adjust font size according to both the area and the aspect ratio - ''' - - # Current demo video resolution (assuming it is the optimal resolution for the base font size=0.3) - base_width = 1768 - base_height = 994 - base_resolution = base_width * base_height - - # input video resolution - resolution = width * height - - # Consider the area of the video - area_scale_factor = resolution / base_resolution - adjusted_font_size = base_font_size * area_scale_factor - - # If font size is too small, it is hard to read - if resolution < base_resolution: - adjusted_font_size = base_font_size * area_scale_factor * scale_factor - - # I believe that the font size should be at least 0.2 and maximum range is 1 (through several tests) - return max(min(adjusted_font_size, max_font_size), min_font_size) - -def dynamic_thickness(font_size, base_thickness=1, thickness_scale=1/0.3, min_thickness=1): - ''' - Dynamically adjust the thickness of the lines according to the font size - ''' - return int(max(font_size * thickness_scale * base_thickness, min_thickness)) + return euc_dist \ No newline at end of file diff --git a/Sports2D/process.py b/Sports2D/process.py index ebb5539..2bf7a34 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -132,7 +132,7 @@ def setup_webcam(webcam_id, save_vid, vid_output_path, input_size): INPUTS: - webcam_id: int. The ID of the webcam to capture from - - input_size: tuple. The size of the input frame (width, height) + - input_size: tuple. The size of the input frame (width, height)\ OUTPUTS: - cap: cv2.VideoCapture. The webcam capture object @@ -478,6 +478,27 @@ def sort_people_rtmlib(pose_tracker, keypoints, scores): return sorted_keypoints, sorted_scores +def dynamic_fontSize(width, height, base_fontSize=0.3, base_dimension=1768): + ''' + Dynamically adjust font size according to the max dimension (width or height). + ''' + # Max dimension + max_dimension = max(width, height) + + # Calculate scale + scale = max_dimension / base_dimension + + # Adjust font size with a fixed scale factor of 1.2 for better readability + adjusted_fontSize = base_fontSize * scale * 1.2 + + # Ensure font size is within the allowed range but, not used parameters for boundaries + return max(min(adjusted_fontSize, 1), 0.2) + +def dynamic_thickness(fontSize, scale_factor=5): + ''' + Dynamically adjust the thickness of the lines according to the font size. + ''' + return max(int(fontSize * scale_factor), 1) # Minimum thickness is 1. def draw_dotted_line(img, start, direction, length, color=(0, 255, 0), gap=7, dot_length=3, thickness=1): ''' @@ -500,7 +521,7 @@ def draw_dotted_line(img, start, direction, length, color=(0, 255, 0), gap=7, do for i in range(0, length, gap): line_start = start + direction * i line_end = line_start + direction * dot_length - cv2.line(img, tuple(line_start.astype(int)), tuple(line_end.astype(int)), color, thickness) + cv2.line(img, tuple(line_start.astype(int)), tuple(line_end.astype(int)), color, thickness+1 if thickness<2 else thickness) def draw_bounding_box(img, X, Y, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], fontSize=0.3, thickness=1): @@ -568,7 +589,7 @@ def draw_skel(img, X, Y, model, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], c = next(color_cycle) if not np.isnan(x).all(): [cv2.line(img, - (int(x[n[0]]), int(y[n[0]])), (int(x[n[1]]), int(y[n[1]])), c, thickness) + (int(x[n[0]]), int(y[n[0]])), (int(x[n[1]]), int(y[n[1]])), c, thickness+1 if thickness<2 else thickness) for n in node_pairs if not (np.isnan(x[n[0]]) or np.isnan(y[n[0]]) or np.isnan(x[n[1]]) or np.isnan(y[n[1]]))] @@ -627,17 +648,17 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ - img: image with angles ''' - color_cycle = it.cycle(colors) + color_cycle = it.cycle(colors) for person_id, (X,Y,angles, X_flipped) in enumerate(zip(valid_X, valid_Y, valid_angles, valid_X_flipped)): c = next(color_cycle) if not np.isnan(X).all(): # person label if 'list' in display_angle_values_on: person_label_position = (int(10 + fontSize*150/0.3*person_id), int(fontSize*50)) - cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (255,255,255), thickness+1, cv2.LINE_AA) - cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, c, thickness, cv2.LINE_AA) + cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (255,255,255), thickness*3, cv2.LINE_AA) # The outline of the font is twice of the thickness of font (if thickness of the font is 3, the outlone will be 6. Is this reasonable?). + cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, c, thickness, cv2.LINE_AA) - # angle lines, names and values + # angle lines, names and values ang_label_line = 1 for k, ang in enumerate(angles): if not np.isnan(ang): @@ -647,11 +668,11 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ ang_coords = np.array([[X[keypoints_ids[keypoints_names.index(kpt)]], Y[keypoints_ids[keypoints_names.index(kpt)]]] for kpt in ang_params[0] if kpt in keypoints_names]) X_flipped_coords = [X_flipped[keypoints_ids[keypoints_names.index(kpt)]] for kpt in ang_params[0] if kpt in keypoints_names] flip = -1 if any(x_flipped < 0 for x_flipped in X_flipped_coords) else 1 - flip = 1 if ang_name in ['pelvis', 'trunk', 'shoulders'] else flip + flip = 1 if ang_name in ['pelvis', 'trunk', 'shoulders'] else flip right_angle = True if ang_params[2]==90 else False # Draw angle - if 'body' in display_angle_values_on: + if 'body' in display_angle_values_on: if len(ang_coords) == 2: # segment angle app_point, vec = draw_segment_angle(img, ang_coords, flip, thickness=thickness) write_angle_on_body(img, ang, app_point, vec, np.array([1,0]), dist=20, color=(255,255,255), fontSize=fontSize, thickness=thickness) @@ -661,8 +682,8 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ write_angle_on_body(img, ang, app_point, vec1, vec2, dist=40, color=(0,255,0), fontSize=fontSize, thickness=thickness) # Write angle as a list on image with progress bar - if 'list' in display_angle_values_on: - if len(ang_coords) == 2: # segment angle + if 'list' in display_angle_values_on: + if len(ang_coords) == 2: # segment angle ang_label_line = write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_line, color = (255,255,255), fontSize=fontSize, thickness=thickness) else: ang_label_line = write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_line, color = (0,255,0), fontSize=fontSize, thickness=thickness) @@ -693,10 +714,10 @@ def draw_segment_angle(img, ang_coords, flip, thickness=1): if (segment_direction==0).all(): return app_point, np.array([0,0]) unit_segment_direction = segment_direction/np.linalg.norm(segment_direction) - cv2.line(img, app_point, np.int32(app_point+unit_segment_direction*20), (255,255,255), thickness) + cv2.line(img, app_point, np.int32(app_point+unit_segment_direction*20), (255,255,255), thickness+1 if thickness<2 else thickness) # horizontal line - cv2.line(img, app_point, (np.int32(app_point[0])+flip*20, np.int32(app_point[1])), (255,255,255), thickness) + cv2.line(img, app_point, (np.int32(app_point[0])+flip*20, np.int32(app_point[1])), (255,255,255), thickness+1 if thickness<2 else thickness) return app_point, unit_segment_direction @@ -732,7 +753,7 @@ def draw_joint_angle(img, ang_coords, flip, right_angle, thickness=1): # segment line unit_segment_direction = segment_direction/np.linalg.norm(segment_direction) - cv2.line(img, app_point, np.int32(app_point+unit_segment_direction*40), (0,255,0), thickness) + cv2.line(img, app_point, np.int32(app_point+unit_segment_direction*40), (0,255,0), thickness+1 if thickness<2 else thickness) # parent segment dotted line unit_parentsegment_direction = parentsegment_direction/np.linalg.norm(parentsegment_direction) @@ -744,7 +765,7 @@ def draw_joint_angle(img, ang_coords, flip, right_angle, thickness=1): if abs(end_angle - start_angle) > 180: if end_angle > start_angle: start_angle += 360 else: end_angle += 360 - cv2.ellipse(img, app_point, (20, 20), 0, start_angle, end_angle, (0, 255, 0), thickness) + cv2.ellipse(img, app_point, (20, 20), 0, start_angle, end_angle, (0, 255, 0), thickness+1 if thickness<2 else thickness) return app_point, unit_segment_direction, unit_parentsegment_direction @@ -771,7 +792,7 @@ def write_angle_on_body(img, ang, app_point, vec1, vec2, dist=40, color=(255,255 return unit_vec_sum = vec_sum/np.linalg.norm(vec_sum) text_position = np.int32(app_point + unit_vec_sum*dist) - cv2.putText(img, f'{ang:.1f}', text_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, (0,0,0), thickness+1, cv2.LINE_AA) + cv2.putText(img, f'{ang:.1f}', text_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, (0,0,0), thickness*3, cv2.LINE_AA) cv2.putText(img, f'{ang:.1f}', text_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, color, thickness, cv2.LINE_AA) @@ -796,9 +817,9 @@ def write_angle_as_list(img, ang, ang_name, person_label_position, ang_label_lin # angle names and values ang_label_position = (person_label_position[0], person_label_position[1]+int((ang_label_line)*40*fontSize)) ang_value_position = (ang_label_position[0]+int(250*fontSize), ang_label_position[1]) - cv2.putText(img, f'{ang_name}:', ang_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, (0, 0, 0), thickness+1, cv2.LINE_AA) + cv2.putText(img, f'{ang_name}:', ang_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, (0, 0, 0), thickness*3, cv2.LINE_AA) cv2.putText(img, f'{ang_name}:', ang_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, color, thickness, cv2.LINE_AA) - cv2.putText(img, f'{ang:.1f}', ang_value_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, (0, 0, 0), thickness+1, cv2.LINE_AA) + cv2.putText(img, f'{ang:.1f}', ang_value_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, (0, 0, 0), thickness*3, cv2.LINE_AA) cv2.putText(img, f'{ang:.1f}', ang_value_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize, color, thickness, cv2.LINE_AA) # progress bar @@ -1107,7 +1128,7 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): cv2.setWindowProperty(f'{video_file} Sports2D', cv2.WND_PROP_ASPECT_RATIO, cv2.WINDOW_FULLSCREEN) # Set up front size and thickness - if isinstance(fontSize, str) and fontSize.lower() == 'auto': # I add isinstance to avoid errors when running pytest (I guess, when the function runs twice). + if isinstance(fontSize, str) and fontSize.lower() == 'auto': # I add isinstance to avoid errors when running with user's preferences (fontSize is a float) fontSize = dynamic_fontSize(cam_width, cam_height) thickness = dynamic_thickness(fontSize) @@ -1146,7 +1167,7 @@ def process_fun(config_dict, video_file, time_range, frame_rate, result_dir): all_frames_angles.append([]) continue else: - cv2.putText(frame, f"Press 'q' to quit", (cam_width-int(400*fontSize), cam_height-20), cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (255,255,255), thickness+1, cv2.LINE_AA) + cv2.putText(frame, f"Press 'q' to quit", (cam_width-int(400*fontSize), cam_height-20), cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (255,255,255), thickness*3, cv2.LINE_AA) cv2.putText(frame, f"Press 'q' to quit", (cam_width-int(400*fontSize), cam_height-20), cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (0,0,255), thickness, cv2.LINE_AA) # Detect poses From 8fc0927c6e515ef7eb05fe4de61f7054e56bc6a8 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Mon, 9 Sep 2024 08:29:34 +0900 Subject: [PATCH 09/12] fix typo and comment --- Sports2D/process.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sports2D/process.py b/Sports2D/process.py index 2bf7a34..92e52f2 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -132,7 +132,7 @@ def setup_webcam(webcam_id, save_vid, vid_output_path, input_size): INPUTS: - webcam_id: int. The ID of the webcam to capture from - - input_size: tuple. The size of the input frame (width, height)\ + - input_size: tuple. The size of the input frame (width, height) OUTPUTS: - cap: cv2.VideoCapture. The webcam capture object @@ -521,7 +521,7 @@ def draw_dotted_line(img, start, direction, length, color=(0, 255, 0), gap=7, do for i in range(0, length, gap): line_start = start + direction * i line_end = line_start + direction * dot_length - cv2.line(img, tuple(line_start.astype(int)), tuple(line_end.astype(int)), color, thickness+1 if thickness<2 else thickness) + cv2.line(img, tuple(line_start.astype(int)), tuple(line_end.astype(int)), color, thickness+1 if thickness<2 else thickness) # +1 to make sure the line is more visible when the thickness is too thin (only for lines not for characters) def draw_bounding_box(img, X, Y, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], fontSize=0.3, thickness=1): @@ -655,7 +655,7 @@ def draw_angles(img, valid_X, valid_Y, valid_angles, valid_X_flipped, keypoints_ # person label if 'list' in display_angle_values_on: person_label_position = (int(10 + fontSize*150/0.3*person_id), int(fontSize*50)) - cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (255,255,255), thickness*3, cv2.LINE_AA) # The outline of the font is twice of the thickness of font (if thickness of the font is 3, the outlone will be 6. Is this reasonable?). + cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, (255,255,255), thickness*3, cv2.LINE_AA) # The outline of the font is three times of the thickness of font(It seems better to see the font) cv2.putText(img, f'person {person_id}', person_label_position, cv2.FONT_HERSHEY_SIMPLEX, fontSize+0.2, c, thickness, cv2.LINE_AA) # angle lines, names and values From 86139b9338c8d5a4bc0db811a391d8dfe5de34ef Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Mon, 9 Sep 2024 08:38:27 +0900 Subject: [PATCH 10/12] Thickness of bbox --- Sports2D/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sports2D/process.py b/Sports2D/process.py index 92e52f2..63cf959 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -552,7 +552,7 @@ def draw_bounding_box(img, X, Y, colors=[(255, 0, 0), (0, 255, 0), (0, 0, 255)], if y_max > img.shape[0]: y_max = img.shape[0] # Draw rectangles - cv2.rectangle(img, (x_min-25, y_min-25), (x_max+25, y_max+25), color, thickness) + cv2.rectangle(img, (x_min-25, y_min-25), (x_max+25, y_max+25), color, thickness+1 if thickness<2 else thickness) # Write person ID cv2.putText(img, str(i), (x_min-30, y_min-30), cv2.FONT_HERSHEY_SIMPLEX, fontSize+1, color, 2, cv2.LINE_AA) From 776a098e28e9ecf15ef8bcbbd0e603f9bea3f358 Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Mon, 9 Sep 2024 08:58:39 +0900 Subject: [PATCH 11/12] simplify --- Sports2D/process.py | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Sports2D/process.py b/Sports2D/process.py index 63cf959..e560434 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -482,12 +482,9 @@ def dynamic_fontSize(width, height, base_fontSize=0.3, base_dimension=1768): ''' Dynamically adjust font size according to the max dimension (width or height). ''' - # Max dimension - max_dimension = max(width, height) - # Calculate scale - scale = max_dimension / base_dimension - + scale = max(width, height) / base_dimension + # Adjust font size with a fixed scale factor of 1.2 for better readability adjusted_fontSize = base_fontSize * scale * 1.2 From 20ab59046eece5650aa227223faaf7a49b4f742e Mon Sep 17 00:00:00 2001 From: Kim HunMin Date: Mon, 9 Sep 2024 09:01:51 +0900 Subject: [PATCH 12/12] remove unnecessary --- Sports2D/process.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sports2D/process.py b/Sports2D/process.py index e560434..0e4abca 100644 --- a/Sports2D/process.py +++ b/Sports2D/process.py @@ -495,7 +495,7 @@ def dynamic_thickness(fontSize, scale_factor=5): ''' Dynamically adjust the thickness of the lines according to the font size. ''' - return max(int(fontSize * scale_factor), 1) # Minimum thickness is 1. + return int(fontSize * scale_factor) # 5 is a scale factor to make sure the thickness is at least 1 (0.2 * 5 = 1) def draw_dotted_line(img, start, direction, length, color=(0, 255, 0), gap=7, dot_length=3, thickness=1): '''