Advertisement
here2share

# tk_Image_Enhance_GUI.py

Feb 24th, 2025 (edited)
220
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 10.02 KB | None | 0 0
  1. # tk_Image_Enhance_GUI.py ZZZ? Most likely needs more work
  2.  
  3. from PIL import Image
  4. from tkinter import Tk, Button, Canvas, PhotoImage, Frame
  5. from tkinter.filedialog import askopenfilename
  6. import os
  7. import pickle
  8. import time
  9.  
  10. def select_and_process_image():
  11.     filename = askopenfilename(filetypes=[("JPG files", "*.jpg")])
  12.     if not filename:
  13.         print("No file selected")
  14.         return
  15.    
  16.     if not filename.lower().endswith('.jpg'):
  17.         print(f"Error: {filename} is not a JPG file")
  18.         return
  19.    
  20.     try:
  21.         original_img = Image.open(filename)
  22.         original_img = original_img.convert('RGB')
  23.     except Exception as e:
  24.         print(f"Error loading image: {e}")
  25.         return
  26.    
  27.     # Build or load patch dictionary
  28.     dictionaries = build_patch_dictionary(original_img, filename)
  29.    
  30.     # Enhance image (default scale factor t=2, can be changed)
  31.     enhanced_img = enhance_image(original_img, dictionaries, t=2)
  32.    
  33.     # Save enhanced image
  34.     enhanced_filename = f"enhanced_{os.path.basename(filename)}"
  35.     enhanced_img.save(enhanced_filename)
  36.     print(f"Enhanced image saved as {enhanced_filename}")
  37.    
  38.     # Display on canvas (resize to fit 640x640)
  39.     display_size = (640, 640)
  40.     enhanced_img_display = enhanced_img.resize(display_size, Image.BICUBIC)
  41.     photo = PhotoImage(enhanced_img_display)
  42.    
  43.     canvas.delete("all")
  44.     canvas.create_image(320, 320, image=photo)
  45.     canvas.image = photo  # Keep a reference to avoid garbage collection
  46.     print("Image displayed on canvas")
  47.    
  48. def progress_meter(i):
  49.     canvas.delete('meter')
  50.     canvas.create_rectangle(8, 8, 632, 42, outline="black", fill="yellow", tags='meter')
  51.     canvas.create_rectangle(10, 10, i % 630, 40, outline="", fill="lime", tags='meter')
  52.    
  53.     # Calculate text position to be centered in the progress bar
  54.     text_x = 320
  55.     text_y = 25
  56.    
  57.     canvas.create_text(text_x, text_y, text="Progress...", fill="black", tags='meter', font=("Arial", 14))
  58.     canvas.update()
  59.  
  60. # Helper function to convert a 2D list patch to a PIL Image
  61. def list_to_image(patch):
  62.     height = len(patch)
  63.     width = len(patch[0])
  64.     img = Image.new('RGB', (width, height))
  65.     for i in range(height):
  66.         for j in range(width):
  67.             img.putpixel((j, i), tuple(patch[i][j]))
  68.     return img
  69.  
  70. # Helper function to convert a PIL Image to a 2D list
  71. def image_to_list(img):
  72.     width, height = img.size
  73.     return [[list(img.getpixel((j, i))) for j in range(width)] for i in range(height)]
  74.  
  75. # Helper function to upsample a patch by factor t
  76. def upsample_patch(patch, t):
  77.     img = list_to_image(patch)
  78.     new_size = (len(patch[0]) * t, len(patch) * t)
  79.     img_up = img.resize(new_size, Image.BICUBIC)
  80.     return image_to_list(img_up)
  81.  
  82. # Helper function to downscale a patch to 4x4
  83. def downscale_patch(patch, t):
  84.     img = list_to_image(patch)
  85.     img_down = img.resize((4, 4), Image.BICUBIC)
  86.     return image_to_list(img_down)
  87.  
  88. # Flatten a patch for dot product computation (4x4 RGB -> 192 elements)
  89. def flatten_patch(patch):
  90.     flat = []
  91.     for i in range(4):
  92.         for j in range(4):
  93.             flat.extend(patch[i][j])
  94.     return flat
  95.  
  96. # Compute dot product between two flattened patches
  97. def dot_product(a, b):
  98.     return sum(a[i] * b[i] for i in range(len(a)))
  99.  
  100. # Subtract two patches element-wise (4x4)
  101. def subtract_patches(p1, p2):
  102.     return [[[p1[i][j][k] - p2[i][j][k] for k in range(3)] for j in range(4)] for i in range(4)]
  103.  
  104. # Add two patches element-wise with clamping to [0, 255]
  105. def add_patches(p1, p2):
  106.     height = len(p1)
  107.     width = len(p1[0])
  108.     return [[[min(max(p1[i][j][k] + p2[i][j][k], 0), 255) for k in range(3)] for j in range(width)] for i in range(height)]
  109.  
  110. # Extract non-overlapping 4x4 patches from an image list
  111. def extract_patches(img_list, width, height):
  112.     patches = []
  113.     positions = []
  114.     for i in range(0, height - 3, 4):
  115.         for j in range(0, width - 3, 4):
  116.             patch = [[img_list[i + di][j + dj] for dj in range(4)] for di in range(4)]
  117.             patches.append(patch)
  118.             positions.append((i, j))
  119.     return patches, positions
  120.  
  121. # Log message to file
  122. def log(message):
  123.     with open('processing_log.txt', 'a') as f:
  124.         f.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} - {message}\n")
  125.    
  126. # build_patch_dictionary.py
  127.  
  128. def build_patch_dictionary(original_img, filename):
  129.     cache_filename = f"cache_{os.path.splitext(os.path.basename(filename))[0]}.pkl"
  130.  
  131.     # Check cache
  132.     if os.path.exists(cache_filename):
  133.         print(f"Loading cached dictionary from {cache_filename}")
  134.         with open(cache_filename, 'rb') as f:
  135.             dictionaries = pickle.load(f)
  136.         return dictionaries
  137.  
  138.     print(f"Building patch dictionary from {filename}")
  139.     width, height = original_img.size
  140.     original_list = image_to_list(original_img)
  141.  
  142.     # Dictionary to store patches for each scale
  143.     dictionaries = {}
  144.     scale_factors = [2, 4, 6, 8]
  145.  
  146.     for s in scale_factors:
  147.         # Downscale image
  148.         downscaled_size = (width // s, height // s)
  149.         I_s = original_img.resize(downscaled_size, Image.BICUBIC)
  150.         # Upsample back to original size
  151.         I_s_up = I_s.resize((width, height), Image.BICUBIC)
  152.         I_s_up_list = image_to_list(I_s_up)
  153.        
  154.         # Extract non-overlapping 4x4 patches
  155.         high_res_patches, positions = extract_patches(original_list, width, height)
  156.         low_res_patches, _ = extract_patches(I_s_up_list, width, height)
  157.        
  158.         # Flatten low-res patches for similarity computation
  159.         low_res_flat = [flatten_patch(patch) for patch in low_res_patches]
  160.        
  161.         # Compute top 250 similar patches for each low-res patch
  162.         neighbors = []
  163.        
  164.         k = 0
  165.         for i in range(len(low_res_flat)):
  166.             similarities = []
  167.             for j in range(len(low_res_flat)):
  168.                 if i != j:
  169.                     sim = dot_product(low_res_flat[i], low_res_flat[j])
  170.                     similarities.append((sim, j))
  171.                     k += 1
  172.                     progress_meter(k)
  173.             similarities.sort(reverse=True)
  174.             top_neighbors = [idx for _, idx in similarities[:250]]
  175.             neighbors.append(top_neighbors)
  176.         canvas.delete('meter')
  177.        
  178.         # Store in dictionary
  179.         dictionaries[s] = {
  180.             'low_res_patches': low_res_patches,
  181.             'high_res_patches': high_res_patches,
  182.             'positions': positions,
  183.             'neighbors': neighbors
  184.         }
  185.  
  186.     # Save to cache
  187.     with open(cache_filename, 'wb') as f:
  188.         pickle.dump(dictionaries, f)
  189.     print(f"Saved patch dictionary to {cache_filename}")
  190.  
  191.     return dictionaries
  192.    
  193. # enhance_image.py
  194.  
  195. def enhance_image(original_img, dictionaries, t):
  196.     print(f"Enhancing image with scale factor {t}")
  197.     width, height = original_img.size
  198.    
  199.     # Upsample original image by t
  200.     upsampled_size = (width * t, height * t)
  201.     I_up = original_img.resize(upsampled_size, Image.BICUBIC)
  202.     I_up_list = image_to_list(I_up)
  203.    
  204.     # Get dictionary for scale t
  205.     if t not in dictionaries:
  206.         print(f"No dictionary for scale factor {t}, using nearest available")
  207.         t_available = min(dictionaries.keys(), key=lambda x: abs(x - t))
  208.     else:
  209.         t_available = t
  210.     dict_data = dictionaries[t_available]
  211.     low_res_patches = dict_data['low_res_patches']
  212.     high_res_patches = dict_data['high_res_patches']
  213.     low_res_flat = [flatten_patch(patch) for patch in low_res_patches]
  214.    
  215.     # Initialize output image list
  216.     output_list = [[I_up_list[i][j] for j in range(upsampled_size[0])] for i in range(upsampled_size[1])]
  217.    
  218.     # Extract non-overlapping patches of size (4*t)x(4*t)
  219.     patch_size = 4 * t
  220.     for i in range(0, upsampled_size[1] - patch_size + 1, patch_size):
  221.         for j in range(0, upsampled_size[0] - patch_size + 1, patch_size):
  222.             # Extract patch Q
  223.             Q = [[I_up_list[i + di][j + dj] for dj in range(patch_size)] for di in range(patch_size)]
  224.            
  225.             # Downscale Q to 4x4
  226.             Q_down = downscale_patch(Q, t)
  227.             Q_down_flat = flatten_patch(Q_down)
  228.            
  229.             # Find top K similar low-res patches (K=5 for robustness)
  230.             K = 5
  231.             similarities = []
  232.             for idx in range(len(low_res_flat)):
  233.                 sim = dot_product(Q_down_flat, low_res_flat[idx])
  234.                 similarities.append((sim, idx))
  235.             similarities.sort(reverse=True)
  236.             top_k = similarities[:K]
  237.            
  238.             # Compute weights
  239.             total_sim = sum(sim for sim, _ in top_k) + 1e-10  # Avoid division by zero
  240.             weights = [sim / total_sim for sim, _ in top_k]
  241.            
  242.             # Compute enhanced patch using weighted average of differences
  243.             D_acc = [[ [0 for k in range(3)] for j in range(4)] for i in range(4)]
  244.             for (sim, idx), w in zip(top_k, weights):
  245.                 P_low = low_res_patches[idx]
  246.                 P_high = high_res_patches[idx]
  247.                 D = subtract_patches(P_high, P_low)
  248.                 # Scale difference by weight
  249.                 D_scaled = [[[D[i][j][k] * w for k in range(3)] for j in range(4)] for i in range(4)]
  250.                 D_acc = add_patches(D_acc, D_scaled)
  251.            
  252.             # Upsample D_acc to patch_size x patch_size
  253.             D_up = upsample_patch(D_acc, t)
  254.            
  255.             # Add to Q with clamping
  256.             Q_enhanced = add_patches(Q, D_up)
  257.            
  258.             # Place enhanced patch in output image
  259.             for di in range(patch_size):
  260.                 for dj in range(patch_size):
  261.                     if i + di < upsampled_size[1] and j + dj < upsampled_size[0]:
  262.                         output_list[i + di][j + dj] = Q_enhanced[di][dj]
  263.    
  264.     enhanced_img = list_to_image(output_list)
  265.     print("Image enhancement completed")
  266.     return enhanced_img
  267.  
  268. # Set up GUI
  269. root = Tk()
  270. root.title("Image Enhance GUI")
  271. root.geometry("+0+0")
  272.  
  273. canvas = Canvas(root, width=640, height=640, bg="white")
  274. canvas.pack(side="left")
  275.  
  276. right_frame = Frame(root)
  277. right_frame.pack(side="right", padx=10, pady=10, fill="both", expand=True)
  278.  
  279. select_button = Button(right_frame, text="Select JPG Image", command=select_and_process_image)
  280. select_button.pack(pady=10)
  281.  
  282. print("Started image enhancement application")
  283.  
  284. root.mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement