import numpy as np from PIL import Image, ImageDraw # Parameters R = 9.0 # mm H = 20.0 # mm fov_half = np.radians(75) # 75 degrees half-angle pixels_per_mm = 100 # Texture dimensions width = int(np.pi * 2 * R * pixels_per_mm) # circumference height = int(H * pixels_per_mm) # Desired dot pattern in image space (normalized) delta_theta = np.radians(10) # 10° azimuth spacing delta_r = 0.1 # radial spacing in normalized units rho = 0.08 # normalized dot radius (from reference) # Generate dot centers in image space r_vals = np.arange(R/H, np.tan(fov_half), delta_r) theta_vals = np.arange(0, 2*np.pi, delta_theta) # Create empty texture (white background) img = Image.new('L', (width, height), color=255) draw = ImageDraw.Draw(img) for r_img in r_vals: z = R / r_img v = z / H # Ellipse axes in texture coordinates a_u = (rho * z) / (2 * np.pi * R) a_v = (rho * z**2) / (R * H) # Convert to pixels a_u_px = a_u * width a_v_px = a_v * height for theta in theta_vals: u = theta / (2 * np.pi) cx = u * width cy = v * height # Draw ellipse (bounding box) bbox = [cx - a_u_px, cy - a_v_px, cx + a_u_px, cy + a_v_px] draw.ellipse(bbox, fill=0) # black dot img.save('cylinder_marker_texture.png')