Label de parts with de arrows or lines
ls -la /home/daytona/workspace/ 2>/dev/null || echo "workspace empty or missing"
mkdir -p /home/daytona/workspace/mra-labeled && curl -s -o /home/daytona/workspace/mra-labeled/original.jpeg "https://d361swluvexzqs.cloudfront.net/chats-attachments/IMG_2339-1778694149117-2q2t2j.jpeg" && echo "Downloaded OK" && python3 -c "from PIL import Image; img = Image.open('/home/daytona/workspace/mra-labeled/original.jpeg'); print(img.size)"
python3 << 'EOF' from PIL import Image, ImageDraw, ImageFont import os img = Image.open('/home/daytona/workspace/mra-labeled/original.jpeg').convert('RGB') draw = ImageDraw.Draw(img) W, H = img.size # 1283 x 1567 # Try to get a decent font try: font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 26) font_sm = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 22) except: font = ImageFont.load_default() font_sm = font # Colors YELLOW = (255, 230, 0) WHITE = (255, 255, 255) CYAN = (0, 230, 255) ORANGE = (255, 140, 0) def arrow(draw, tip, tail, color=YELLOW, width=3): """Draw line from tail to tip with arrowhead at tip.""" import math draw.line([tail, tip], fill=color, width=width) # arrowhead dx = tip[0] - tail[0] dy = tip[1] - tail[1] length = math.sqrt(dx*dx + dy*dy) if length == 0: return ux, uy = dx/length, dy/length # perpendicular px, py = -uy, ux size = 14 p1 = (tip[0] - ux*size + px*size//2, tip[1] - uy*size + py*size//2) p2 = (tip[0] - ux*size - px*size//2, tip[1] - uy*size - py*size//2) draw.polygon([tip, p1, p2], fill=color) def label(draw, text, pos, font, color=YELLOW, bg=(0,0,0,180)): """Draw text with dark background box.""" bbox = draw.textbbox((0,0), text, font=font) tw = bbox[2] - bbox[0] th = bbox[3] - bbox[1] x, y = pos # background rectangle draw.rectangle([x-3, y-2, x+tw+3, y+th+2], fill=(20,20,20)) draw.text((x, y), text, fill=color, font=font) # ---- LABEL DEFINITIONS ---- # Each entry: (label_text, label_x, label_y, arrow_tip_x, arrow_tip_y, color) # Coordinates are in the 1283x1567 image space # The image shows a coronal MRA of head/neck vessels labels = [ # Intracranial vessels (top portion, ~y 100-400) ("Middle Cerebral Artery (MCA)", 700, 115, 490, 195, CYAN), ("Anterior Cerebral Artery (ACA)", 700, 160, 570, 230, CYAN), ("Internal Carotid Art. (ICA) - siphon", 700, 205, 505, 330, YELLOW), # Neck vessels # Right side (image right = patient left) ("Internal Carotid A. (ICA)", 700, 290, 610, 420, YELLOW), ("External Carotid A. (ECA)", 700, 340, 600, 490, ORANGE), ("Common Carotid A. (CCA)", 700, 430, 575, 600, YELLOW), # Lower neck / subclavian ("Vertebral Artery (VA)", 700, 520, 380, 620, CYAN), ("Common Carotid A. (CCA) - lower", 700, 590, 565, 750, YELLOW), # Chest / root vessels ("Subclavian Artery", 700, 800, 540, 920, ORANGE), ("Brachiocephalic Trunk", 700, 870, 480, 970, WHITE), ("Aortic Arch branches", 700, 940, 420, 1030, WHITE), ] # Draw all labels and arrows for (text, lx, ly, tx, ty, col) in labels: # label center-y for arrow tail bbox = draw.textbbox((0,0), text, font=font_sm) th = (bbox[3]-bbox[1]) tail = (lx - 8, ly + th//2) tip = (tx, ty) arrow(draw, tip, tail, color=col, width=2) label(draw, text, (lx, ly), font_sm, color=col) # Title draw.rectangle([50, 10, 800, 52], fill=(0,0,0)) draw.text((55, 14), "MRA Head & Neck — Labeled Vascular Anatomy", fill=WHITE, font=font) img.save('/home/daytona/workspace/mra-labeled/labeled_mra.jpeg', quality=92) print("Saved OK") EOF