Advertisement
here2share

# tk_list_nearest_images.py

Aug 6th, 2023 (edited)
1,361
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 6.63 KB | None | 0 0
  1. # tk_list_nearest_images2.py
  2.  
  3. # work in progress, this is not yet a similarity search whereas it is of ordering by just color brightness...
  4.  
  5. import itertools
  6. import math
  7. import tkinter as tk
  8. from tkinter import filedialog
  9. from PIL import Image, ImageTk, ImageOps, ImageDraw
  10. import os
  11. import threading
  12. import shutil
  13.  
  14. def select_target_image():
  15.     filename = filedialog.askopenfilename(title="Select Target Image", filetypes=(("Image files", "*.jpg *.jpeg *.png"),))
  16.  
  17.     if filename:
  18.         target.filename = filename
  19.         foldername, target.name = filename.rsplit("/", 1)
  20.         source.foldername = foldername
  21.         img = get_img(filename)        
  22.         target.data = get_img_data(img)
  23.         target.img = resize_image(img)
  24.         update_canvas(target)
  25.  
  26. def update_canvas(active):
  27.     target_img_canvas.delete("all")
  28.  
  29.     if active.img:
  30.         tk_img = ImageTk.PhotoImage(active.img)
  31.         target_img_canvas.create_image(2, 2, anchor=tk.NW, image=tk_img)
  32.         target_img_canvas.image = tk_img
  33.     target_img_canvas.update()
  34.  
  35. def get_img(file_path):
  36.     img = Image.open(file_path)
  37.     if img.mode == "RGBA":
  38.         img = img.convert("RGB")
  39.     return img
  40.  
  41. def get_img_data(img, resize=24):
  42.     old_size = img.size
  43.     ratio = float(resize)/max(old_size)
  44.     new_size = tuple([int(x*ratio) for x in old_size])
  45.     resized_img = img.resize(new_size, Image.ANTIALIAS)
  46.     delta_w = resize - new_size[0]
  47.     delta_h = resize - new_size[1]
  48.     padding = (delta_w//2, delta_h//2, delta_w-(delta_w//2), delta_h-(delta_h//2))
  49.     resized_img = ImageOps.expand(resized_img, padding, fill='white')
  50.     rgb_data = list(resized_img.getdata())
  51.     return rgb_data
  52.  
  53. def resize_image(img, target_width=640, target_height=640):
  54.     width, height = img.size
  55.     aspect_ratio = width / height
  56.  
  57.     if aspect_ratio > target_width / target_height:
  58.         new_width = target_width
  59.         new_height = int(target_width / aspect_ratio)
  60.     else:
  61.         new_width = int(target_height * aspect_ratio)
  62.         new_height = target_height
  63.  
  64.     resized_image = img.resize((new_width, new_height))
  65.  
  66.     return resized_image
  67.  
  68. def select_source_folder():
  69.     foldername = filedialog.askdirectory(title="Select Source Folder")
  70.  
  71.     if foldername:
  72.         source.foldername = foldername
  73.  
  74. def move_selected_files():
  75.     foldername = filedialog.askdirectory(title="Move To Folder")
  76.     if foldername:
  77.         for item in selected_items:
  78.             filename = item["text"]
  79.             shutil.move(filename, foldername)
  80.         # Clear selection after moving files
  81.         selected_items.clear()
  82.  
  83. def calculate_progress(val, total):
  84.     val = 1 + val*1.05
  85.     if val >= total:
  86.         return f"100%"
  87.     else:
  88.         progress = (val / total) * 100
  89.         return f"{progress:.2f}%"
  90.  
  91. def on_item_selected(event):
  92.     selected_items = search_results_listbox.curselection()
  93.  
  94.     if selected_items:
  95.         filename = search_results_listbox.get(selected_items[0]).split(None, 1)[-1]
  96.         img = paths[filename]
  97.        
  98.         update_canvas(img)
  99.  
  100. def on_item_enter(event):
  101.     try:
  102.         source = paths[event.widget.get(event.widget.curselection()[0]).split(None, 1)[-1]]
  103.         update_canvas(source)
  104.     except:
  105.         0
  106.  
  107. def on_item_leave(event):
  108.     try:
  109.         update_canvas(target)
  110.     except:
  111.         0
  112.  
  113. def calculate_distance(img1, img2):
  114.     distance = 0
  115.     for i in range(len(img1)):
  116.         for j in (0, 1, 2):
  117.             distance += abs(img1[i][j] - img2[i][j])
  118.     return distance
  119.  
  120. def search():
  121.    
  122.     if not (target.filename and source.foldername):
  123.         return
  124.  
  125.     search_results_listbox.delete(0, tk.END)
  126.    
  127.     search_progress_label = tk.Label(text="", width=10, bg="yellow", font=('Arial', 50))
  128.     search_progress_label.place(x=850, y=50)
  129.  
  130.     distances = {}
  131.  
  132.     for root, dirs, files in os.walk(source.foldername):
  133.         break
  134.     L = len(files)
  135.     for idx, file in enumerate(files):
  136.         if file.lower().endswith(('.jpg', '.jpeg', '.png')) and target.name != file:
  137.             filename = os.path.join(root, file)
  138.  
  139.             paths[file] = CV()
  140.             img = resize_image(get_img(filename))
  141.             paths[file].img = img
  142.             paths[file].path = filename
  143.             data = get_img_data(img)
  144.            
  145.             distance = calculate_distance(target.data, data)
  146.             distances[file] = distance
  147.  
  148.             progress_text = calculate_progress(idx, L)
  149.             search_progress_label.config(text=progress_text)
  150.  
  151.     search_progress_label.destroy()
  152.  
  153.     sorted_distances = sorted(distances.items(), key=lambda x: x[1])
  154.    
  155.     for filename, distance in sorted_distances[:2000]:
  156.    
  157.         percentage = max(0.0, 100 - ((distance / 1000000) * 100))
  158.  
  159.         line = f'{percentage:.8f}% {filename}'
  160.         search_results_listbox.insert(tk.END, line)
  161.  
  162. root = tk.Tk()
  163. root.title("TK List Nearest Images")
  164. root.geometry(f"{root.winfo_screenwidth()+2}x{root.winfo_screenheight()}+-10+0")
  165.  
  166. class CV(): pass
  167.  
  168. target = CV()
  169. source = CV()
  170. target.filename = None
  171. source.foldername = None
  172. paths = {}
  173. selected_items = set()
  174. show_images = False
  175. halfwidth = root.winfo_screenwidth()//2
  176. images = []
  177.  
  178. name = "SIMILARITY IMAGE SEARCH"
  179. yyy = 30
  180. for t in name.split():
  181.     title_label = tk.Label(root, text=t, font=('Arial', 20, 'bold'))
  182.     title_label.place(x=10, y=yyy)
  183.     yyy += 35
  184.  
  185. select_target_btn = tk.Button(root, text="Select Target Image", bg='yellow', width=24, command=lambda: select_target_image())
  186. select_target_btn.place(x=10, y=215)
  187.  
  188. select_source_btn = tk.Button(root, text="Select Source Folder", bg='yellow', width=24, command=lambda: select_source_folder())
  189. select_source_btn.place(x=10, y=260)
  190.  
  191. search_btn = tk.Button(root, text="SEARCH", fg="white", bg="green", font=('Arial', 14, "bold"),
  192.         width=14, command=lambda: threading.Thread(target=search, args=()).start())
  193. search_btn.place(x=10, y=350)
  194.  
  195. move_to_folder_btn = tk.Button(root, text="Move To Folder", bg='yellow', width=24, command=move_selected_files)
  196. move_to_folder_btn.place(x=10, y=540)
  197.  
  198. target_img_frame = tk.Frame(root)
  199. target_img_frame.place(x=190)
  200.  
  201. target_img_canvas = tk.Canvas(target_img_frame, width=640, height=640, bg='skyblue')
  202. target_img_canvas.pack(side=tk.LEFT)
  203.  
  204. search_results_scrollbar = tk.Scrollbar(target_img_frame, orient=tk.VERTICAL)
  205. search_results_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
  206.  
  207. search_results_scrollbar2 = tk.Scrollbar(target_img_frame, orient=tk.HORIZONTAL)
  208. search_results_scrollbar2.pack(side=tk.BOTTOM, fill=tk.X)
  209.  
  210. search_results_listbox = tk.Listbox(target_img_frame, width=60, height=30, selectmode="extended",
  211.         yscrollcommand=search_results_scrollbar.set, xscrollcommand=search_results_scrollbar2.set, font=('Arial', 10))
  212.        
  213. search_results_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 0))
  214.  
  215. search_results_scrollbar.config(command=search_results_listbox.yview)
  216. search_results_scrollbar2.config(command=search_results_listbox.xview)
  217.  
  218. search_results_listbox.bind("<<ListboxSelect>>", on_item_selected)
  219. search_results_listbox.bind("<Enter>", on_item_enter)
  220. search_results_listbox.bind("<Leave>", on_item_leave)
  221.  
  222. root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement