Advertisement
here2share

# tk_list_nearest_images2.py

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