from PIL import Image, ImageDraw, ImageFont # Import PIL modules for image creation and drawing import cv2 as cv # Import OpenCV library for computer vision tasks import math # Import math module for mathematical functions class Draw: def __init__(self, height, width): self.height = height # Height of the drawing area self.width = width # Width of the drawing area # Create an image to draw on self.image = Image.new("RGB", (self.height, self.width)) # Create a new RGB image self.draw = ImageDraw.Draw(self.image) # Create a drawing object self.font = ImageFont.load_default() # Load the default font self.align = 'center' # Default alignment self.background = (255, 0, 0) # Background color (B, G, R) self.font_color = (255, 255, 255) # Font color (white) # Draws a message at the specified position (x, y) def draw_msg(self, message, position): # Calculate bounding box for the text message_bbox = self.draw.textbbox(position, message, font=self.font) message_width = message_bbox[2] - message_bbox[0] message_height = message_bbox[3] - message_bbox[1] message_x = position[0] - message_width / 2 message_y = position[1] - message_height / 2 # Draw the text on the image self.draw.text((message_x, message_y), message, font=self.font, fill=self.font_color) # Clears the image by drawing a rectangle with the background color def clear_img(self): self.draw.rectangle([0, 0, self.height, self.width], fill=self.background) # Returns the current image def rtrn_img(self): return self.image # Converts an OpenCV image to a PIL image def convert(self, image): pil_image = Image.fromarray(cv.cvtColor(image, cv.COLOR_BGR2RGB)) pil_image = pil_image.resize((self.height, self.width), Image.LANCZOS) return pil_image # Draws a message with a bounding box at the specified position (x, y) with the specified color def bound_mssg(self, message, position, color): # Calculate bounding box for the text message_bbox = self.draw.textbbox(position, message, font=self.font) message_width = message_bbox[2] - message_bbox[0] message_height = message_bbox[3] - message_bbox[1] message_x = position[0] - message_width / 2 message_y = position[1] - message_height / 2 padding = 3 # Padding around the text pos = (message_x, message_y) bbox = self.draw.textbbox(pos, message, font=self.font) expanded_bbox = (bbox[0] - padding, bbox[1] - padding, bbox[2] + padding, bbox[3] + padding) # Draw the bounding box around the text self.draw.rectangle(expanded_bbox, outline=color, width=1) # Draws an arc with text placed along it def draw_arc_with_text(self, xy, start, end, fill='white', width=2, text_list=[], font=None): self.draw.arc(xy, start, end, fill=fill, width=width) # Draw the arc position = [] # Compute the bounding box center x0, y0, x1, y1 = xy cx = (x0 + x1) / 2 cy = (y0 + y1) / 2 rx = (x1 - x0) / 2 ry = (y1 - y0) / 2 # Number of text items n = len(text_list) if n > 0: # Generate angles for text placement angles = [start + (end - start) * (i) / (n - 1) for i in range(n)] for i, text in enumerate(text_list): angle = angles[i] angle_rad = math.radians(angle) # Position of the text tx = cx + (rx) * math.cos(angle_rad) + 1 ty = cy - (ry + 42) * math.sin(angle_rad) + 10 position.append((tx, ty)) tick_length = 5 tick_width = 1 tick_start_x = cx + (rx - tick_length) * math.cos(angle_rad) tick_start_y = cy - (ry - tick_length) * math.sin(angle_rad) tick_end_x = cx + (rx + tick_length) * math.cos(angle_rad) tick_end_y = cy - (ry + tick_length) * math.sin(angle_rad) # Draw the tick self.draw.line([(tick_start_x, tick_start_y), (tick_end_x, tick_end_y)], fill=fill, width=tick_width) # Draw the text self.draw_msg(text, (tx, ty)) return position