""" Drawing Primitives Library Draw shapes, text, and characters on images. """ import numpy as np import cv2 from PIL import Image, ImageDraw, ImageFont # Default font (will be loaded lazily) _default_font = None def _get_default_font(size=16): """Get default font, creating if needed.""" global _default_font if _default_font is None or _default_font.size != size: try: _default_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSansMono.ttf", size) except: _default_font = ImageFont.load_default() return _default_font def prim_draw_char(img, char, x, y, font_size=16, color=None): """Draw a single character at (x, y).""" if color is None: color = [255, 255, 255] pil_img = Image.fromarray(img) draw = ImageDraw.Draw(pil_img) font = _get_default_font(font_size) draw.text((x, y), char, fill=tuple(color), font=font) return np.array(pil_img) def prim_draw_text(img, text, x, y, font_size=16, color=None): """Draw text string at (x, y).""" if color is None: color = [255, 255, 255] pil_img = Image.fromarray(img) draw = ImageDraw.Draw(pil_img) font = _get_default_font(font_size) draw.text((x, y), text, fill=tuple(color), font=font) return np.array(pil_img) def prim_fill_rect(img, x, y, w, h, color=None): """Fill a rectangle with color.""" if color is None: color = [255, 255, 255] result = img.copy() x, y, w, h = int(x), int(y), int(w), int(h) result[y:y+h, x:x+w] = color return result def prim_draw_rect(img, x, y, w, h, color=None, thickness=1): """Draw rectangle outline.""" if color is None: color = [255, 255, 255] result = img.copy() cv2.rectangle(result, (int(x), int(y)), (int(x+w), int(y+h)), tuple(color), thickness) return result def prim_draw_line(img, x1, y1, x2, y2, color=None, thickness=1): """Draw a line from (x1, y1) to (x2, y2).""" if color is None: color = [255, 255, 255] result = img.copy() cv2.line(result, (int(x1), int(y1)), (int(x2), int(y2)), tuple(color), thickness) return result def prim_draw_circle(img, cx, cy, radius, color=None, thickness=1, fill=False): """Draw a circle.""" if color is None: color = [255, 255, 255] result = img.copy() t = -1 if fill else thickness cv2.circle(result, (int(cx), int(cy)), int(radius), tuple(color), t) return result def prim_draw_ellipse(img, cx, cy, rx, ry, angle=0, color=None, thickness=1, fill=False): """Draw an ellipse.""" if color is None: color = [255, 255, 255] result = img.copy() t = -1 if fill else thickness cv2.ellipse(result, (int(cx), int(cy)), (int(rx), int(ry)), angle, 0, 360, tuple(color), t) return result def prim_draw_polygon(img, points, color=None, thickness=1, fill=False): """Draw a polygon from list of [x, y] points.""" if color is None: color = [255, 255, 255] result = img.copy() pts = np.array(points, dtype=np.int32).reshape((-1, 1, 2)) if fill: cv2.fillPoly(result, [pts], tuple(color)) else: cv2.polylines(result, [pts], True, tuple(color), thickness) return result PRIMITIVES = { # Text 'draw-char': prim_draw_char, 'draw-text': prim_draw_text, # Rectangles 'fill-rect': prim_fill_rect, 'draw-rect': prim_draw_rect, # Lines and shapes 'draw-line': prim_draw_line, 'draw-circle': prim_draw_circle, 'draw-ellipse': prim_draw_ellipse, 'draw-polygon': prim_draw_polygon, }