from jinja2 import Environment, FileSystemLoader import pickle import os import numpy as np from PIL import Image, ImageDraw from io import BytesIO import cv2 import base64 from pathlib import Path import torch import gradio as gr ############ Generate GIF functions ################################################################################### def generate_gif(local_directory, image_names, speed_factor=1, loop=0): """ Generate a GIF from a sequence of images paths saved in a local directory. Parameters: - local_directory (str): Directory path where the images are located - image_paths (list): List of filenames of the input images. - speed_factor (int): How fast the GIF is, the higher the less the delay is between frames - loop (int): Number of loops (0 for infinite loop). Returns: - Bytes of GIF """ images = [] durations = [] for image_name in image_names: img = Image.open(os.path.join(local_directory, image_name)) images.append(img) try: duration = img.info['duration'] except KeyError: duration = 100 # Default duration in case 'duration' is not available durations.append(duration) # Calculate the adjusted durations based on the speed factor adjusted_durations = [int(duration / speed_factor) for duration in durations] # Save as GIF to an in-memory buffer gif_buffer = BytesIO() images[0].save(gif_buffer, format='GIF', save_all=True, append_images=images[1:], duration=adjusted_durations, loop=loop) # Get the content of the buffer as bytes gif_content = gif_buffer.getvalue() gif_content = base64.b64encode(gif_content).decode('utf-8') return gif_content def generate_gif_from_frames(frames, speed_factor=1, loop=0, progress=gr.Progress()): """ Generate a GIF from a sequence of images. Parameters: - frames (list): List of cv2 frames - speed_factor (int): How fast the GIF is, the higher the less the delay is between frames - loop (int): Number of loops (0 for infinite loop). Returns: - Bytes of GIF """ durations = [] images = [] i = 0 for frame in frames: # progress((len(frames)+i)/(2*len(frames)), desc="Abstracting Symbols") image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) images.append(image) duration = 100 # Default duration in case 'duration' is not available durations.append(duration) i+=1 # Calculate the adjusted durations based on the speed factor adjusted_durations = [int(duration / speed_factor) for duration in durations] # images[0].save('test.gif', # save_all = True, append_images = images[1:], # optimize = False, duration =adjusted_durations, loop=loop) # Save as GIF to an in-memory buffer gif_buffer = BytesIO() images[0].save(gif_buffer, format='GIF', save_all=True, append_images=images[1:], duration=adjusted_durations, loop=loop) # Get the content of the buffer as bytes gif_content = gif_buffer.getvalue() gif_content = base64.b64encode(gif_content).decode('utf-8') return gif_content ########################################################################################################## ############ Overlay Symbols on Frames ###################################################################### SKELETON = [ [1,2],[1,0],[2,6],[3,6],[4,5],[3,4],[6,7],[7,8],[9,8],[7,12],[7,13],[11,12],[13,14],[14,15],[10,11] ] CocoColors = [[255, 0, 0], [255, 85, 0], [255, 170, 0], [255, 255, 0], [170, 255, 0], [85, 255, 0], [0, 255, 0], [0, 255, 85], [0, 255, 170], [0, 255, 255], [0, 170, 255], [0, 85, 255], [0, 0, 255], [85, 0, 255], [170, 0, 255], [255, 0, 255], [255, 0, 170], [255, 0, 85]] NUM_KPTS = 16 def draw_pose(keypoints,img, board_end_coord): """draw the keypoints and the skeletons. :params keypoints: the shape should be equal to [17,2] :params img: """ assert keypoints.shape == (NUM_KPTS,2) for i in range(len(SKELETON)): kpt_a, kpt_b = SKELETON[i][0], SKELETON[i][1] x_a, y_a = keypoints[kpt_a][0],keypoints[kpt_a][1] x_b, y_b = keypoints[kpt_b][0],keypoints[kpt_b][1] cv2.circle(img, (int(x_a), int(y_a)), 6, CocoColors[i], -1) cv2.circle(img, (int(x_b), int(y_b)), 6, CocoColors[i], -1) cv2.line(img, (int(x_a), int(y_a)), (int(x_b), int(y_b)), CocoColors[i], 2) # cv2.circle(img, board_end_coord, 4, [0, 0, 0], -1) def draw_symbols(opencv_image, pose_preds, board_end_coord, plat_outputs, splash_pred_mask, above_board=None): # Open image using openCV2 # opencv_image = cv2.imread(image_path) if pose_preds is not None: draw_pose(np.array(pose_preds)[0],opencv_image, board_end_coord) if above_board is None or above_board==1: draw_platform(opencv_image, plat_outputs) draw_splash(opencv_image, splash_pred_mask) # # Notice the COLOR_BGR2RGB which means that the color is # # converted from BGR to RGB # color_converted = cv2.cvtColor(opencv_image, cv2.COLOR_BGR2RGB) # # Displaying the converted image # pil_image = Image.fromarray(color_converted) return opencv_image def draw_platform(opencv_image, output): pred_classes = output['instances'].pred_classes.cpu().numpy() platforms = np.where(pred_classes == 0)[0] scores = output['instances'].scores[platforms] if len(scores) == 0: return pred_masks = output['instances'].pred_masks[platforms] max_instance = torch.argmax(scores) pred_mask = np.array(pred_masks[max_instance].cpu()) # Convert the mask to a binary image binary_mask = pred_mask.squeeze().astype(np.uint8) contours, hierarchy = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) cv2.drawContours(opencv_image, contours[0], -1, (36, 255, 12), thickness=5) def draw_splash(opencv_image, pred_mask): # Convert the mask to a binary image if pred_mask is None: return binary_mask = pred_mask.squeeze().astype(np.uint8) contours, hierarchy = cv2.findContours(binary_mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE) cv2.drawContours(opencv_image, contours[0], -1, (0, 0, 0), thickness=5) ########################################################################################################## ############ Generate HTML template ###################################################################### def generate_report(template_path, data, directory, local_directory, progress=gr.Progress()): # Load the template environment env = Environment(loader=FileSystemLoader('.')) file_names = os.listdir(local_directory) file_names.sort() file_names = np.array(file_names) progress(0.9, desc="Generating Score Report") # Load the template is_twister = data['twist_position_tightness']['raw_score'] is not None overall_score_desc = data['overall_score']['description'] overall_score = '%.1f' % data['overall_score']['raw_score'] feet_apart_score = round(float('%.2f' % data['feet_apart']['raw_score'])) feet_apart_peaks = file_names[data['feet_apart']['peaks']] feet_apart_gif = None has_feet_apart_peaks = False if len(feet_apart_peaks) > 0: has_feet_apart_peaks = True feet_apart_gif = generate_gif(local_directory, feet_apart_peaks, speed_factor = 0.05) feet_apart_percentile = round(float('%.2f' % (data['feet_apart']['percentile'] *100))) feet_apart_percentile_divided_by_ten = '%.1f' % (data['feet_apart']['percentile'] *10) include_height_off_platform = False height_off_board_score = data['height_off_board']['raw_score'] height_off_board_percentile = data['height_off_board']['percentile'] height_off_board_description = None height_off_board_percentile_divided_by_ten = None encoded_height_off_board_frame = None if height_off_board_score is not None: include_height_off_platform = True height_off_board_score = round(float('%.2f' % data['height_off_board']['raw_score'])) height_off_board_frame = file_names[data['height_off_board']['frame_index']] height_off_board_frame_path = os.path.join(local_directory, height_off_board_frame) with open(height_off_board_frame_path, "rb") as image_file: encoded_height_off_board_frame = base64.b64encode(image_file.read()).decode('utf-8') height_off_board_percentile = round(float('%.2f' % (data['height_off_board']['percentile'] *100))) height_off_board_percentile_divided_by_ten = '%.1f' % (data['height_off_board']['percentile'] *10) if float(height_off_board_percentile_divided_by_ten) > 5: height_off_board_description = "good" else: height_off_board_description = "a bit on the lower side" dist_from_board_score = '%.2f' % data['distance_from_board']['raw_score'] dist_from_board_frame = file_names[data['distance_from_board']['frame_index']] dist_from_board_frame_path = os.path.join(local_directory, dist_from_board_frame) with open(dist_from_board_frame_path, "rb") as image_file: encoded_dist_from_board_frame = base64.b64encode(image_file.read()).decode('utf-8') dist_from_board_percentile = data['distance_from_board']['percentile'] if 'good' in dist_from_board_percentile: dist_from_board_percentile_status = "Good" elif 'far' in dist_from_board_percentile: dist_from_board_percentile_status = "Too Far" else: dist_from_board_percentile_status = "Too Close" knee_bend_score = data['knee_bend']['raw_score'] knee_bend_percentile = data['knee_bend']['percentile'] knee_bend_frames = [] knee_bend_percentile_divided_by_ten = None if knee_bend_score is not None: knee_bend_score = round(float('%.2f' % (data['knee_bend']['raw_score']))) knee_bend_frames = file_names[data['knee_bend']['frame_indices']] knee_bend_percentile = round(float('%.2f' % (knee_bend_percentile * 100))) knee_bend_percentile_divided_by_ten = '%.1f' % (data['knee_bend']['percentile'] * 10) som_position_tightness_score = data['som_position_tightness']['raw_score'] som_position_tightness_percentile = data['som_position_tightness']['percentile'] som_position_tightness_position = data['som_position_tightness']['position'] som_position_tightness_frames = file_names[data['som_position_tightness']['frame_indices']] som_position_tightness_gif = None som_position_tightness_percentile_divided_by_ten = None if som_position_tightness_score is not None: if is_twister: som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score'] + 15))) else: som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score']))) som_position_tightness_gif = generate_gif(local_directory, som_position_tightness_frames) som_position_tightness_percentile = round(float('%.2f' % (som_position_tightness_percentile * 100))) som_position_tightness_percentile_divided_by_ten = '%.1f' % (data['som_position_tightness']['percentile'] * 10) twist_position_tightness_score = data['twist_position_tightness']['raw_score'] twist_position_tightness_frames = [] twist_position_tightness_gif = None twist_position_tightness_percentile = None twist_position_tightness_percentile_divided_by_ten = None if twist_position_tightness_score is not None: twist_position_tightness_score = round(float('%.2f' % twist_position_tightness_score)) twist_position_tightness_frames = file_names[data['twist_position_tightness']['frame_indices']] twist_position_tightness_gif = generate_gif(local_directory, twist_position_tightness_frames) twist_position_tightness_percentile = round(float('%.2f' % (data['twist_position_tightness']['percentile'] * 100))) twist_position_tightness_percentile_divided_by_ten = '%.1f' % (data['twist_position_tightness']['percentile'] * 10) over_under_rotation_score = round(float('%.2f' % data['over_under_rotation']['raw_score'])) over_under_rotation_frame = file_names[data['over_under_rotation']['frame_index']] over_under_rotation_percentile = round(float('%.2f' % (data['over_under_rotation']['percentile'] * 100))) over_under_rotation_percentile_divided_by_ten = '%.1f' % (data['over_under_rotation']['percentile'] * 10) straightness_during_entry_score = round(float('%.2f' % data['straightness_during_entry']['raw_score'])) straightness_during_entry_frames = file_names[data['straightness_during_entry']['frame_indices']] straightness_during_entry_gif = generate_gif(local_directory, straightness_during_entry_frames, speed_factor = 0.5) straightness_during_entry_percentile = round(float('%.2f' % (data['straightness_during_entry']['percentile'] * 100))) straightness_during_entry_percentile_divided_by_ten = '%.1f' % (data['straightness_during_entry']['percentile'] * 10) splash_score = round(float('%.2f' % data['splash']['raw_score'])) splash_frame = file_names[data['splash']['maximum_index']] splash_indices = file_names[data['splash']['frame_indices']] splash_gif = None if len(splash_indices) > 0: splash_gif = generate_gif(local_directory, splash_indices) splash_percentile = round(float('%.2f' % (data['splash']['percentile'] * 100))) splash_percentile_divided_by_ten = '%.1f' % (data['splash']['percentile'] * 10) if float(splash_percentile) < 50: splash_description = 'on the larger side' else: splash_description = 'small' template = env.get_template(template_path) data = { 'directory' : directory, 'local_directory': local_directory, 'is_twister' : is_twister, 'overall_score_desc' : overall_score_desc, 'overall_score' : overall_score, 'feet_apart_score' : feet_apart_score, 'feet_apart_peaks' : feet_apart_peaks, 'has_feet_apart_peaks' : has_feet_apart_peaks, 'feet_apart_gif' : feet_apart_gif, 'feet_apart_percentile' : feet_apart_percentile, 'feet_apart_percentile_divided_by_ten': feet_apart_percentile_divided_by_ten, 'include_height_off_platform': include_height_off_platform, 'height_off_board_score' : height_off_board_score, 'height_off_board_percentile' : height_off_board_percentile, 'encoded_height_off_board_frame' : encoded_height_off_board_frame, 'height_off_board_percentile_divided_by_ten': height_off_board_percentile_divided_by_ten, 'height_off_board_description' : height_off_board_description, 'dist_from_board_score' : dist_from_board_score, 'dist_from_board_frame' : dist_from_board_frame, 'encoded_dist_from_board_frame': encoded_dist_from_board_frame, 'dist_from_board_percentile' : dist_from_board_percentile, 'dist_from_board_percentile_status': dist_from_board_percentile_status, 'knee_bend_score' : knee_bend_score, 'knee_bend_frames' : knee_bend_frames, 'knee_bend_percentile' : knee_bend_percentile, 'knee_bend_percentile_divided_by_ten' : knee_bend_percentile_divided_by_ten, 'som_position_tightness_score' : som_position_tightness_score, 'som_position_tightness_frames' : som_position_tightness_frames, 'som_position_tightness_gif' : som_position_tightness_gif, 'som_position_tightness_position' : som_position_tightness_position, 'som_position_tightness_percentile' : som_position_tightness_percentile, 'som_position_tightness_percentile_divided_by_ten' : som_position_tightness_percentile_divided_by_ten, 'twist_position_tightness_score' : twist_position_tightness_score, 'twist_position_tightness_frames': twist_position_tightness_frames, 'twist_position_tightness_percentile' : twist_position_tightness_percentile, 'twist_position_tightness_percentile_divided_by_ten' : twist_position_tightness_percentile_divided_by_ten, 'twist_position_tightness_gif' : twist_position_tightness_gif, 'over_under_rotation_score' : over_under_rotation_score, 'over_under_rotation_frame' : over_under_rotation_frame, 'over_under_rotation_percentile' : over_under_rotation_percentile, 'over_under_rotation_percentile_divided_by_ten' : over_under_rotation_percentile_divided_by_ten, 'straightness_during_entry_score' : straightness_during_entry_score, 'straightness_during_entry_gif' : straightness_during_entry_gif, 'straightness_during_entry_percentile' : straightness_during_entry_percentile, 'straightness_during_entry_percentile_divided_by_ten': straightness_during_entry_percentile_divided_by_ten, 'splash_score' : splash_score, 'splash_frame' : splash_frame, 'splash_gif' : splash_gif, 'splash_percentile' : splash_percentile, 'splash_percentile_divided_by_ten': splash_percentile_divided_by_ten, 'splash_description' : splash_description, } # Render the template with the provided data report_content = template.render(data) return report_content def generate_report_from_frames(template_path, data, frames): # Load the template environment env = Environment(loader=FileSystemLoader('.')) frames = np.array(frames) # Load the template is_twister = data['twist_position_tightness']['raw_score'] is not None overall_score_desc = data['overall_score']['description'] overall_score = '%.1f' % data['overall_score']['raw_score'] feet_apart_score = round(float('%.2f' % data['feet_apart']['raw_score'])) feet_apart_peaks = frames[data['feet_apart']['peaks']] feet_apart_gif = None has_feet_apart_peaks = False if len(feet_apart_peaks) > 0: has_feet_apart_peaks = True feet_apart_gif = generate_gif_from_frames(feet_apart_peaks, speed_factor = 0.05) feet_apart_percentile = round(float('%.2f' % (data['feet_apart']['percentile'] *100))) feet_apart_percentile_divided_by_ten = '%.1f' % (data['feet_apart']['percentile'] *10) include_height_off_platform = False height_off_board_score = data['height_off_board']['raw_score'] height_off_board_frame = None height_off_board_percentile = None height_off_board_percentile_divided_by_ten = None height_off_board_description = None encoded_height_off_board_frame = None if height_off_board_score is not None: include_height_off_platform = True height_off_board_score = round(float('%.2f' % data['height_off_board']['raw_score'])) height_off_board_frame = Image.fromarray(cv2.cvtColor(frames[data['height_off_board']['frame_index']], cv2.COLOR_BGR2RGB)) height_buffer = BytesIO() height_off_board_frame.save(height_buffer, format='JPEG') encoded_height_off_board_frame = base64.b64encode(height_buffer.getvalue()).decode('utf-8') height_off_board_percentile = round(float('%.2f' % (data['height_off_board']['percentile'] *100))) height_off_board_percentile_divided_by_ten = '%.1f' % (data['height_off_board']['percentile'] *10) if float(height_off_board_percentile_divided_by_ten) > 5: height_off_board_description = "good" else: height_off_board_description = "a bit on the lower side" dist_from_board_score = '%.2f' % data['distance_from_board']['raw_score'] dist_from_board_frame = Image.fromarray(cv2.cvtColor(frames[data['distance_from_board']['frame_index']], cv2.COLOR_BGR2RGB)) dist_buffer = BytesIO() dist_from_board_frame.save(dist_buffer, format='JPEG') encoded_dist_from_board_frame = base64.b64encode(dist_buffer.getvalue()).decode('utf-8') dist_from_board_percentile = data['distance_from_board']['percentile'] if 'good' in dist_from_board_percentile: dist_from_board_percentile_status = "Good" elif 'far' in dist_from_board_percentile: dist_from_board_percentile_status = "Too Far" else: dist_from_board_percentile_status = "Too Close" knee_bend_score = data['knee_bend']['raw_score'] knee_bend_percentile = data['knee_bend']['percentile'] knee_bend_frames = [] knee_bend_percentile_divided_by_ten = None if knee_bend_score is not None: knee_bend_score = round(float('%.2f' % knee_bend_score)) knee_bend_percentile = round(float('%.2f' % (knee_bend_percentile * 100))) knee_bend_frames = frames[data['knee_bend']['frame_indices']] knee_bend_percentile_divided_by_ten = '%.1f' % (data['knee_bend']['percentile'] * 10) som_position_tightness_score = data['som_position_tightness']['raw_score'] som_position_tightness_percentile = data['som_position_tightness']['percentile'] som_position_tightness_position = data['som_position_tightness']['position'] som_position_tightness_frames = [] som_position_tightness_gif = None som_position_tightness_percentile_divided_by_ten = None if som_position_tightness_score is not None: if is_twister: som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score'] + 15))) else: som_position_tightness_score = round(float('%.2f' % (data['som_position_tightness']['raw_score']))) som_position_tightness_frames = frames[data['som_position_tightness']['frame_indices']] som_position_tightness_gif = generate_gif_from_frames(som_position_tightness_frames) som_position_tightness_percentile = round(float('%.2f' % (som_position_tightness_percentile * 100))) som_position_tightness_percentile_divided_by_ten = '%.1f' % (data['som_position_tightness']['percentile'] * 10) twist_position_tightness_score = data['twist_position_tightness']['raw_score'] twist_position_tightness_frames = [] twist_position_tightness_gif = None twist_position_tightness_percentile = None twist_position_tightness_percentile_divided_by_ten = None if twist_position_tightness_score is not None: twist_position_tightness_score = round(float('%.2f' % twist_position_tightness_score)) twist_position_tightness_frames = frames[data['twist_position_tightness']['frame_indices']] twist_position_tightness_gif = generate_gif_from_frames(twist_position_tightness_frames) twist_position_tightness_percentile = round(float('%.2f' % (data['twist_position_tightness']['percentile'] * 100))) twist_position_tightness_percentile_divided_by_ten = '%.1f' % (data['twist_position_tightness']['percentile'] * 10) over_under_rotation_score = round(float('%.2f' % data['over_under_rotation']['raw_score'])) over_under_rotation_frame = frames[data['over_under_rotation']['frame_index']] over_under_rotation_percentile = round(float('%.2f' % (data['over_under_rotation']['percentile'] * 100))) over_under_rotation_percentile_divided_by_ten = '%.1f' % (data['over_under_rotation']['percentile'] * 10) straightness_during_entry_score = round(float('%.2f' % data['straightness_during_entry']['raw_score'])) straightness_during_entry_frames = frames[data['straightness_during_entry']['frame_indices']] straightness_during_entry_gif = generate_gif_from_frames(straightness_during_entry_frames, speed_factor = 0.5) straightness_during_entry_percentile = round(float('%.2f' % (data['straightness_during_entry']['percentile'] * 100))) straightness_during_entry_percentile_divided_by_ten = '%.1f' % (data['straightness_during_entry']['percentile'] * 10) splash_score = round(float('%.2f' % data['splash']['raw_score'])) splash_frame = frames[data['splash']['maximum_index']] splash_indices = frames[data['splash']['frame_indices']] splash_gif = None if len(splash_indices) > 0: splash_gif = generate_gif_from_frames(splash_indices) splash_percentile = round(float('%.2f' % (data['splash']['percentile'] * 100))) splash_percentile_divided_by_ten = '%.1f' % (data['splash']['percentile'] * 10) if float(splash_percentile) < 50: splash_description = 'on the larger side' else: splash_description = 'small' template = env.get_template(template_path) data = { 'is_twister' : is_twister, 'overall_score_desc' : overall_score_desc, 'overall_score' : overall_score, 'feet_apart_score' : feet_apart_score, 'feet_apart_peaks' : feet_apart_peaks, 'has_feet_apart_peaks' : has_feet_apart_peaks, 'feet_apart_gif' : feet_apart_gif, 'feet_apart_percentile' : feet_apart_percentile, 'feet_apart_percentile_divided_by_ten': feet_apart_percentile_divided_by_ten, 'include_height_off_platform': include_height_off_platform, 'height_off_board_score' : height_off_board_score, 'height_off_board_percentile' : height_off_board_percentile, 'encoded_height_off_board_frame' : encoded_height_off_board_frame, 'height_off_board_percentile_divided_by_ten': height_off_board_percentile_divided_by_ten, 'height_off_board_description' : height_off_board_description, 'dist_from_board_score' : dist_from_board_score, 'dist_from_board_frame' : dist_from_board_frame, 'encoded_dist_from_board_frame': encoded_dist_from_board_frame, 'dist_from_board_percentile' : dist_from_board_percentile, 'dist_from_board_percentile_status': dist_from_board_percentile_status, 'knee_bend_score' : knee_bend_score, 'knee_bend_frames' : knee_bend_frames, 'knee_bend_percentile' : knee_bend_percentile, 'knee_bend_percentile_divided_by_ten' : knee_bend_percentile_divided_by_ten, 'som_position_tightness_score' : som_position_tightness_score, 'som_position_tightness_frames' : som_position_tightness_frames, 'som_position_tightness_gif' : som_position_tightness_gif, 'som_position_tightness_position' : som_position_tightness_position, 'som_position_tightness_percentile' : som_position_tightness_percentile, 'som_position_tightness_percentile_divided_by_ten' : som_position_tightness_percentile_divided_by_ten, 'twist_position_tightness_score' : twist_position_tightness_score, 'twist_position_tightness_frames': twist_position_tightness_frames, 'twist_position_tightness_percentile' : twist_position_tightness_percentile, 'twist_position_tightness_percentile_divided_by_ten' : twist_position_tightness_percentile_divided_by_ten, 'twist_position_tightness_gif' : twist_position_tightness_gif, 'over_under_rotation_score' : over_under_rotation_score, 'over_under_rotation_frame' : over_under_rotation_frame, 'over_under_rotation_percentile' : over_under_rotation_percentile, 'over_under_rotation_percentile_divided_by_ten' : over_under_rotation_percentile_divided_by_ten, 'straightness_during_entry_score' : straightness_during_entry_score, 'straightness_during_entry_gif' : straightness_during_entry_gif, 'straightness_during_entry_percentile' : straightness_during_entry_percentile, 'straightness_during_entry_percentile_divided_by_ten': straightness_during_entry_percentile_divided_by_ten, 'splash_score' : splash_score, 'splash_frame' : splash_frame, 'splash_gif' : splash_gif, 'splash_percentile' : splash_percentile, 'splash_percentile_divided_by_ten': splash_percentile_divided_by_ten, 'splash_description' : splash_description, } # Render the template with the provided data report_content = template.render(data) return report_content def generate_symbols_report(template_path, dive_data, frames): # Load the template environment env = Environment(loader=FileSystemLoader('.')) template = env.get_template(template_path) pose_frames = [] for i in range(len(dive_data['pose_pred'])): # if dive_data['pose_pred'][i] is not None: pose_frame = draw_symbols(frames[i], dive_data['pose_pred'][i], dive_data['board_end_coords'][i], dive_data['plat_outputs'][i], dive_data['splash_pred_masks'][i]) pose_frames.append(pose_frame) pose_gif = generate_gif_from_frames(pose_frames, speed_factor=2) # image_buffer = BytesIO() # pose_frame.save(image_buffer, format='JPEG') # encoded_pose_frame = base64.b64encode(image_buffer.getvalue()).decode('utf-8') pose_data = {} pose_data['pose_gif'] = pose_gif html = template.render(pose_data) return html def generate_symbols_report_precomputed(template_path, dive_data, local_directory, progress=gr.Progress()): # Load the template environment file_names = os.listdir(local_directory) file_names.sort() file_names = np.array(file_names) if 'above_boards' in dive_data: above_boards = dive_data['above_boards'] else: above_boards = [None] * len(file_names) env = Environment(loader=FileSystemLoader('.')) template = env.get_template(template_path) pose_frames = [] counter = 0 for i in range(len(file_names)): progress(i/(len(file_names)+10), desc="Abstracting Symbols") if file_names[i][-4:] != ".jpg": continue # if dive_data['pose_pred'][i] is not None: opencv_image = cv2.imread(local_directory+file_names[i]) pose_frame = draw_symbols(opencv_image, dive_data['pose_pred'][counter], dive_data['board_end_coords'][counter], dive_data['plat_outputs'][counter], dive_data['splash_pred_masks'][counter], above_board=above_boards[counter]) pose_frames.append(pose_frame) counter +=1 pose_gif = generate_gif_from_frames(pose_frames, speed_factor=2, progress=progress) # image_buffer = BytesIO() # pose_frame.save(image_buffer, format='JPEG') # encoded_pose_frame = base64.b64encode(image_buffer.getvalue()).decode('utf-8') pose_data = {} pose_data['pose_gif'] = pose_gif html = template.render(pose_data) return html