import os
import tkinter as tk
from tkinter import filedialog, ttk, messagebox
from PIL import Image, ImageTk
import imagehash
class ImageDuplicateFinder:
def __init__(self, root):
self.root = root
self.root.title("Image Duplicate Finder (Hash-Based)")
self.root.geometry("900x600")
self.image_hash_map = {}
self.duplicates = []
self.setup_ui()
# ---------------------------------------------------------
def setup_ui(self):
top_frame = tk.Frame(self.root)
top_frame.pack(fill=tk.X, pady=10)
tk.Button(top_frame, text="Select Folder", command=self.select_folder).pack(side=tk.LEFT, padx=10)
tk.Button(top_frame, text="Scan for Duplicates", command=self.scan_duplicates).pack(side=tk.LEFT, padx=10)
self.result_tree = ttk.Treeview(self.root, columns=("img1", "img2"), show="headings")
self.result_tree.heading("img1", text="Image 1")
self.result_tree.heading("img2", text="Duplicate Image")
self.result_tree.pack(fill="both", expand=True, pady=10)
self.result_tree.bind("<Double-1>", self.show_preview)
# ---------------------------------------------------------
def select_folder(self):
self.folder_path = filedialog.askdirectory()
if self.folder_path:
messagebox.showinfo("Selected Folder", self.folder_path)
# ---------------------------------------------------------
def scan_duplicates(self):
if not hasattr(self, "folder_path"):
messagebox.showerror("Error", "Please select a folder first!")
return
self.image_hash_map = {}
self.duplicates = []
self.result_tree.delete(*self.result_tree.get_children())
supported_ext = (".jpg", ".jpeg", ".png", ".bmp")
for filename in os.listdir(self.folder_path):
if filename.lower().endswith(supported_ext):
full_path = os.path.join(self.folder_path, filename)
try:
img = Image.open(full_path)
img_hash = imagehash.average_hash(img)
if img_hash in self.image_hash_map:
self.duplicates.append((self.image_hash_map[img_hash], full_path))
else:
self.image_hash_map[img_hash] = full_path
except Exception as e:
print("Error loading:", filename, e)
# Show results in table
for dup in self.duplicates:
self.result_tree.insert("", tk.END, values=dup)
if not self.duplicates:
messagebox.showinfo("Result", "No duplicates found!")
else:
messagebox.showinfo("Result", f"Found {len(self.duplicates)} duplicate pairs.")
# ---------------------------------------------------------
def show_preview(self, event):
selected = self.result_tree.focus()
if not selected:
return
img1_path, img2_path = self.result_tree.item(selected, "values")
self.preview_window(img1_path, img2_path)
# ---------------------------------------------------------
def preview_window(self, img1_path, img2_path):
win = tk.Toplevel(self.root)
win.title("Duplicate Image Preview")
win.geometry("850x450")
tk.Label(win, text=f"Image 1: {os.path.basename(img1_path)}", font=("Arial", 10)).pack(pady=5)
tk.Label(win, text=f"Image 2: {os.path.basename(img2_path)}", font=("Arial", 10)).pack(pady=5)
frame = tk.Frame(win)
frame.pack(expand=True)
# Load images
img1 = Image.open(img1_path).resize((350, 350))
img2 = Image.open(img2_path).resize((350, 350))
img1_tk = ImageTk.PhotoImage(img1)
img2_tk = ImageTk.PhotoImage(img2)
left_label = tk.Label(frame, image=img1_tk)
left_label.image = img1_tk
left_label.pack(side=tk.LEFT, padx=10)
right_label = tk.Label(frame, image=img2_tk)
right_label.image = img2_tk
right_label.pack(side=tk.RIGHT, padx=10)
# ---------------------------------------------------------
# RUN APP
# ---------------------------------------------------------
root = tk.Tk()
app = ImageDuplicateFinder(root)
root.mainloop()
No comments:
Post a Comment