Advertisement
here2share

# tk_pil_blob.py Starring Blobby Bobby

Aug 20th, 2024 (edited)
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 4.99 KB | None | 0 0
  1. # tk_pil_blob.py Starring Blobby Bobby
  2.  
  3. import tkinter as tk
  4. from PIL import Image, ImageDraw, ImageTk, ImageFilter, ImageChops
  5. import math
  6. import os
  7.  
  8. r0, g0, b0 = 180, 0, 180
  9. WW, HH = 400, 400
  10. x = y = 0
  11. mdrag = 0
  12.  
  13. points = [(25, 120), (120, 110), (180, 30), (230, 130), (370, 20), (290, 150), (370, 370), (280, 220), (100, 360), (220, 170)]
  14.  
  15. def get_xy():
  16.     return root.winfo_pointerx() - root.winfo_rootx(), root.winfo_pointery() - root.winfo_rooty()
  17.  
  18. def apply_color(value, threshold):
  19.     return (r0, g0, b0, 255) if value > threshold else (0, 0, 0, 0)
  20.  
  21. def blob(blur_amount, threshold):
  22.     image = Image.new("RGBA", (WW, HH), (255, 255, 255, 0))
  23.     draw = ImageDraw.Draw(image)
  24.     draw.polygon(points, fill=(255, 255, 255, 255))
  25.     blobby_image = image.filter(ImageFilter.GaussianBlur(blur_amount))
  26.     mask = blobby_image.point(lambda p: 255 if p > threshold else 0)
  27.     color = Image.new("RGBA", (WW, HH), (r0, g0, b0, 255))
  28.     blobby_image.paste(color, mask=mask)
  29.  
  30.     blobby_image = blobby_image.filter(ImageFilter.GaussianBlur(2))
  31.  
  32.     return blobby_image
  33.  
  34. def outline():
  35.     image = Image.new("RGBA", (WW, HH), (0, 0, 0, 0))
  36.     draw = ImageDraw.Draw(image)
  37.     draw.polygon(points, outline=(0, 255, 0, 128))
  38.  
  39.     return image
  40.  
  41. def update_image(*args):
  42.     global mdrag
  43.  
  44.     x, y = get_xy()
  45.     canvas.delete('all')
  46.     blur_amount = blur_scroll.get()
  47.     threshold = threshold_scroll.get()
  48.     blobby_image = blob(blur_amount, threshold)
  49.     canvas.image = ImageTk.PhotoImage(blobby_image)
  50.     canvas.create_image(WW//2, HH//2, image=canvas.image, anchor='center')
  51.  
  52.     canvas.create_polygon(points, fill='', outline='#00ff00', width=3)
  53.  
  54.     if mdrag and (x < WW) and not selected_point:
  55.         nearest_line_index = nearest_line(x, y)
  56.         x1, y1 = points[nearest_line_index]
  57.         x2, y2 = points[(nearest_line_index + 1) % (len(points))]
  58.         canvas.create_line(x1, y1, x2, y2, fill='#ffff00', width=7)
  59.         tag = {}
  60.         for i in range(-3, 4):
  61.             for j in range(-3, 4):
  62.                 color = '#fe9900'
  63.                 if i or j:
  64.                     color = '#ffffff'
  65.                 tag[(i, j)] = canvas.create_text(30 + i, 30 + j, text=nearest_line_index, font='verdana 30', fill=color)
  66.         canvas.tag_raise(tag[(0, 0)])
  67.  
  68.     for point in points:
  69.         x, y = point
  70.         canvas.create_rectangle((x-2, y-2, x+2, y+2), fill='#000000')
  71.  
  72.     mdrag = 0
  73.  
  74.    
  75. def nearest_line(x, y):
  76.     lines = {}
  77.     for i in range(len(points) - 1):
  78.         x1, y1 = points[i]
  79.         x2, y2 = points[i + 1]
  80.         distance = distance = get_distances(x, y, x1, y1, x2, y2)
  81.         lines[i] = distance
  82.  
  83.     x1, y1 = points[0]
  84.     x2, y2 = points[-1]
  85.     distance = get_distances(x, y, x1, y1, x2, y2)
  86.     lines[i + 1] = distance
  87.  
  88.     return min(lines, key=lines.get)
  89.    
  90. def nearest_point(x, y):
  91.     lines = {}
  92.     for i in range(len(points)):
  93.         x0, y0 = points[i]
  94.         distance = math.sqrt((x - x0) ** 2 + (y - y0) ** 2)
  95.         lines[i] = distance
  96.     closest_point = min(lines, key=lines.get)
  97.     del points[closest_point]
  98.    
  99. def get_distances(x, y, x1, y1, x2, y2):
  100.     line_distance = get_distance(x1, y1, x2, y2)
  101.     XYp1_distance = get_distance(x, y, x1, y1)
  102.     XYp2_distance = get_distance(x, y, x2, y2)
  103.     return (XYp1_distance + XYp2_distance) - line_distance
  104.    
  105. def get_distance(x1, y1, x2, y2):
  106.     return math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2)
  107.  
  108. def print_points(event):
  109.     os.system('cls' if os.name == 'nt' else 'clear')
  110.     print(f"points = {points}")
  111.  
  112. def on_drag(event):
  113.     global mdrag
  114.     mdrag = 1
  115.     if selected_point:
  116.         x, y = event.x, event.y
  117.         points[selected_point - 1] = (x, y)
  118.     update_image()
  119.  
  120. def on_right_click(event):
  121.     x, y = get_xy()
  122.     if event.state & 0x0001:  # Check if Shift key is pressed
  123.         nearest_point(x, y)
  124.     else:
  125.         closest_line = nearest_line(x, y)
  126.         points.insert(closest_line + 1, (x, y))
  127.     update_image()
  128.  
  129. def on_left_click(event):
  130.     global selected_point
  131.     x, y = get_xy()
  132.     min_distance = 9
  133.     selected_point = None
  134.     for i, point in enumerate(points):
  135.         distance = ((point[0] - x) ** 2 + (point[1] - y) ** 2) ** 0.5
  136.         if distance < min_distance:
  137.             min_distance = distance
  138.             selected_point = i + 1
  139.  
  140. def on_release(event):
  141.     update_image()
  142.  
  143. root = tk.Tk()
  144. root.title("Solid Blob")
  145.  
  146. frame = tk.Frame(root)
  147. frame.pack(fill=tk.BOTH, expand=True)
  148.  
  149. canvas = tk.Canvas(frame, width=WW, height=HH)
  150. canvas.grid(row=0, column=0)
  151.  
  152. scroll_frame = tk.Frame(frame)
  153. scroll_frame.grid(row=0, column=1, sticky='ns')
  154.  
  155. blur_scroll = tk.Scale(scroll_frame, from_=0, to_=50, orient='vertical', label='Blur')
  156. blur_scroll.set(25)  # Default blur amount
  157. blur_scroll.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  158.  
  159. threshold_scroll = tk.Scale(scroll_frame, from_=0, to_=255, orient='vertical', label='Threshold')
  160. threshold_scroll.set(25)  # Default threshold
  161. threshold_scroll.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
  162.  
  163. blur_scroll.config(command=update_image)
  164. threshold_scroll.config(command=update_image)
  165.  
  166. update_image()
  167. root.bind("<Button-1>", on_left_click)
  168. root.bind("<Button-3>", on_right_click)
  169. root.bind("<B1-Motion>", on_drag)
  170. root.bind("<ButtonRelease-1>", on_release)
  171. root.bind("<space>", print_points)
  172.  
  173. root.mainloop()
  174.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement