Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # tk_list_nearest_images2.py
- # still work in progress, it didn't go anywhere near as expected...
- import itertools
- import math
- import tkinter as tk
- from tkinter import filedialog
- from PIL import Image, ImageTk, ImageOps, ImageDraw
- import os
- import threading
- import shutil
- def select_target_image():
- filename = filedialog.askopenfilename(title="Select Target Image", filetypes=(("Image files", "*.jpg *.jpeg *.png"),))
- if filename:
- target.filename = filename
- foldername, target.name = filename.rsplit("/", 1)
- source.foldername = foldername
- img = get_img(filename)
- target.data = get_img_data(img)
- target.pairs = get_pairs(target.data)
- target.img = resize_image(img)
- update_canvas(target)
- def update_canvas(active):
- target_img_canvas.delete("all")
- if active.img:
- tk_img = ImageTk.PhotoImage(active.img)
- target_img_canvas.create_image(2, 2, anchor=tk.NW, image=tk_img)
- target_img_canvas.image = tk_img
- target_img_canvas.update()
- def get_img(file_path):
- img = Image.open(file_path)
- if img.mode == "RGBA":
- img = img.convert("RGB")
- return img
- def get_img_data(img, resize=24):
- old_size = img.size
- ratio = float(resize)/max(old_size)
- new_size = tuple([int(x*ratio) for x in old_size])
- resized_img = img.resize(new_size, Image.ANTIALIAS)
- delta_w = resize - new_size[0]
- delta_h = resize - new_size[1]
- padding = (delta_w//2, delta_h//2, delta_w-(delta_w//2), delta_h-(delta_h//2))
- resized_img = ImageOps.expand(resized_img, padding, fill='white')
- rgb_data = list(resized_img.getdata())
- return rgb_data
- def resize_image(img, target_width=640, target_height=640):
- width, height = img.size
- aspect_ratio = width / height
- if aspect_ratio > target_width / target_height:
- new_width = target_width
- new_height = int(target_width / aspect_ratio)
- else:
- new_width = int(target_height * aspect_ratio)
- new_height = target_height
- resized_image = img.resize((new_width, new_height))
- return resized_image
- def select_source_folder():
- foldername = filedialog.askdirectory(title="Select Source Folder")
- if foldername:
- source.foldername = foldername
- def move_selected_files():
- foldername = filedialog.askdirectory(title="Move To Folder")
- if foldername:
- for item in selected_items:
- filename = item["text"]
- shutil.move(filename, foldername)
- # Clear selection after moving files
- selected_items.clear()
- def calculate_progress(val, total):
- val = 1 + val*1.05
- if val >= total:
- return f"100%"
- else:
- progress = (val / total) * 100
- return f"{progress:.2f}%"
- def on_item_selected(event):
- selected_items = search_results_listbox.curselection()
- if selected_items:
- filename = search_results_listbox.get(selected_items[0]).split(None, 1)[-1]
- img = paths[filename]
- update_canvas(img)
- def on_item_enter(event):
- try:
- source = paths[event.widget.get(event.widget.curselection()[0]).split(None, 1)[-1]]
- update_canvas(source)
- except:
- 0
- def on_item_leave(event):
- try:
- update_canvas(target)
- except:
- 0
- def calculate_score(rgb):
- return 257 - abs(abs(rgb[0] - rgb[1]) - rgb[2]) # score based on color intensity
- scores = {}
- def get_pairs(rgb):
- pairs = {}
- score = calculate_score(rgb[0])
- t = 40
- for col in range(0, 24):
- for row in range(0, 24):
- idx = row * 24 + col
- pair = tuple(rgb[idx][z]//t for z in (0, 1, 2))
- scores[pair] = score
- try:
- pairs[pair] += [(row, col)]
- except:
- pairs[pair] = [(row, col)]
- return pairs
- MAX_SCORE = 10000
- def calculate_similarity(target_pairs, source_pairs):
- common_keys = target_pairs.keys() & source_pairs.keys()
- similarity = 0
- for key in common_keys:
- x1, y1 = target_pairs[key][0]
- score = scores[key]
- for x2, y2 in source_pairs[key]:
- spatial_weight = ((y1 - x2)**2 + (y1 - y2)**2)**0.5 ** score
- similarity -= spatial_weight
- return MAX_SCORE - similarity
- def search():
- if not (target.filename and source.foldername):
- return
- search_results_listbox.delete(0, tk.END)
- search_progress_label = tk.Label(text="", width=10, bg="yellow", font=('Arial', 50))
- search_progress_label.place(x=850, y=50)
- distances = {}
- for root, dirs, files in os.walk(source.foldername):
- break
- L = len(files)
- for idx, file in enumerate(files):
- if file.lower().endswith(('.jpg', '.jpeg', '.png')) and target.name != file:
- filename = os.path.join(root, file)
- paths[file] = CV()
- img = resize_image(get_img(filename))
- paths[file].img = img
- paths[file].path = filename
- data = get_img_data(img)
- pairs = get_pairs(data)
- distance = calculate_similarity(target.pairs, pairs)
- distances[file] = distance
- progress_text = calculate_progress(idx, L)
- search_progress_label.config(text=progress_text)
- search_progress_label.destroy()
- sorted_distances = sorted(distances.items(), key=lambda x: x[1])[::-1]
- for filename, distance in sorted_distances[:2000]:
- # percentage = 100 - (distance / MAX_SCORE * 100)
- line = f'{int(distance * MAX_SCORE)} {filename}'
- search_results_listbox.insert(tk.END, line)
- root = tk.Tk()
- root.title("TK List Nearest Images")
- root.geometry(f"{root.winfo_screenwidth()+2}x{root.winfo_screenheight()}+-10+0")
- class CV(): pass
- target = CV()
- source = CV()
- target.filename = None
- source.foldername = None
- paths = {}
- selected_items = set()
- show_images = False
- halfwidth = root.winfo_screenwidth()//2
- images = []
- name = "SIMILARITY IMAGE SEARCH"
- yyy = 30
- for t in name.split():
- title_label = tk.Label(root, text=t, font=('Arial', 20, 'bold'))
- title_label.place(x=10, y=yyy)
- yyy += 35
- select_target_btn = tk.Button(root, text="Select Target Image", bg='yellow', width=24, command=lambda: select_target_image())
- select_target_btn.place(x=10, y=215)
- select_source_btn = tk.Button(root, text="Select Source Folder", bg='yellow', width=24, command=lambda: select_source_folder())
- select_source_btn.place(x=10, y=260)
- search_btn = tk.Button(root, text="SEARCH", fg="white", bg="green", font=('Arial', 14, "bold"),
- width=14, command=lambda: threading.Thread(target=search, args=()).start())
- search_btn.place(x=10, y=350)
- move_to_folder_btn = tk.Button(root, text="Move To Folder", bg='yellow', width=24, command=move_selected_files)
- move_to_folder_btn.place(x=10, y=540)
- target_img_frame = tk.Frame(root)
- target_img_frame.place(x=190)
- target_img_canvas = tk.Canvas(target_img_frame, width=640, height=640, bg='skyblue')
- target_img_canvas.pack(side=tk.LEFT)
- search_results_scrollbar = tk.Scrollbar(target_img_frame, orient=tk.VERTICAL)
- search_results_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
- search_results_scrollbar2 = tk.Scrollbar(target_img_frame, orient=tk.HORIZONTAL)
- search_results_scrollbar2.pack(side=tk.BOTTOM, fill=tk.X)
- search_results_listbox = tk.Listbox(target_img_frame, width=60, height=30, selectmode="extended",
- yscrollcommand=search_results_scrollbar.set, xscrollcommand=search_results_scrollbar2.set, font=('Arial', 10))
- search_results_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(5, 0))
- search_results_scrollbar.config(command=search_results_listbox.yview)
- search_results_scrollbar2.config(command=search_results_listbox.xview)
- search_results_listbox.bind("<<ListboxSelect>>", on_item_selected)
- search_results_listbox.bind("<Enter>", on_item_enter)
- search_results_listbox.bind("<Leave>", on_item_leave)
- root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement