import os import cv2 import numpy as np import tkinter as tk from tkinter import filedialog from PIL import Image, ImageTk OPENED_IMAGE = None def padding(file_path, border_width): image = cv2.imread(file_path) if image is None: print("Failed to load the image.") return padded_image = cv2.copyMakeBorder( image, top=border_width, bottom=border_width, left=border_width, right=border_width, borderType=cv2.BORDER_REFLECT ) _cache_image(padded_image, file_path) def crop(file_path): image = cv2.imread(file_path) height, width = image.shape[:2] # crop 80 px from top & left, 130 px from bottom & right x_0 = 80 x_1 = width - 130 y_0 = 80 y_1 = height - 130 cropped_image = image[y_0:y_1, x_0:x_1] _cache_image(cropped_image, file_path) def resize(file_path): width = 200 height = 200 image = cv2.imread(file_path) resized_image = cv2.resize(image, (width, height)) _cache_image(resized_image, file_path) def copy(file_path): image = cv2.imread(file_path) height, width, channels = image.shape emptyPictureArray = np.zeros((height, width, 3), dtype=np.uint8) for y in range(height): for x in range(width): for c in range(channels): emptyPictureArray[y, x, c] = image[y, x, c] _cache_image(emptyPictureArray, file_path) def grayscale(file_path): image = cv2.imread(file_path) gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) _cache_image(gray_image, file_path) def hsv(file_path): image = cv2.imread(file_path) hsv_image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) _cache_image(hsv_image, file_path) def hue_shifted(file_path, hue=50): image = cv2.imread(file_path) height, width, channels = image.shape emptyPictureArray = np.zeros((height, width, 3), dtype=np.uint8) for y in range(height): for x in range(width): for c in range(channels): new_value = image[y, x, c] + hue # Clip the value to stay within [0, 255] emptyPictureArray[y, x, c] = np.clip(new_value, 0, 255) _cache_image(emptyPictureArray, file_path) def smoothing(file_path): image = cv2.imread(file_path) smoothed_image = cv2.blur(image, ksize=(15, 15)) _cache_image(smoothed_image, file_path) def rotation(file_path, rotation_angle=90): image = cv2.imread(file_path) if rotation_angle == 90: rotated_image = cv2.rotate(image, cv2.ROTATE_90_CLOCKWISE) elif rotation_angle == 180: rotated_image = cv2.rotate(image, cv2.ROTATE_180) else: print("Invalid angle. Use 90 or 180.") return _cache_image(rotated_image, file_path) def open_image(): """ Function called from the menu to open an image. """ # Ask user to choose an image file file_path = filedialog.askopenfilename( filetypes=[("Image files", "*.jpg *.jpeg *.png *.gif *.bmp")] ) if file_path: _open_image(file_path) def _cache_image(image, file_path): opened_image_basename = os.path.basename(file_path) opened_image_path = os.path.dirname(file_path) newfname = "cache/" + opened_image_basename cv2.imwrite(newfname, image) print(f"Image cached as '{newfname}'.") _open_image(newfname) def _save_image(file_path): image = cv2.imread(file_path) opened_image_basename = os.path.basename(file_path) opened_image_path = os.path.dirname(file_path) newfname = opened_image_path + '/../' + opened_image_basename cv2.imwrite(newfname, image) print(f"Image saved as '{newfname}'.") _open_image(newfname) def _open_image(file_path): """ Open and display an image in the GUI. Params: - file_path: Path to the image file. """ # Open with cv2 to get dimensions imgcv2 = cv2.imread(file_path) height, width, channels = imgcv2.shape # Open and resize image (optional) img = Image.open(file_path) img = img.resize((height, width), Image.LANCZOS) # Resize to fit frame tk_img = ImageTk.PhotoImage(img) # Update label inside frame with the correct dimensions image_label.config(image=tk_img, height=height, width=width) global OPENED_IMAGE OPENED_IMAGE = file_path # Store opened image in global variable, to access later if needed print("Opened image:", file_path) if __name__ == "__main__": # Main window root = tk.Tk() root.title("Image Viewer") root.geometry("800x600") root.config(bg="white") icon = tk.PhotoImage(file='icon.png') root.tk.call('wm', 'iconphoto', root._w, icon) root.minsize(800, 600) # Menus menu = tk.Menu(root) root.config(menu=menu) file_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="File", menu=file_menu) file_menu.add_command(label="Open Image", command=open_image) file_menu.add_command(label="Save Image", command=lambda: _save_image(OPENED_IMAGE)) file_menu.add_command(label="Exit", command=root.quit) test_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Test", menu=test_menu) test_menu.add_command(label="Padding", command=lambda: padding(OPENED_IMAGE, border_width=50) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Crop", command=lambda: crop(OPENED_IMAGE) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Resize", command=lambda: resize(OPENED_IMAGE) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Copy", command=lambda: copy(OPENED_IMAGE) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Greyscale", command=lambda: grayscale(OPENED_IMAGE) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Hsv", command=lambda: hsv(OPENED_IMAGE) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Hue Shifted", command=lambda: hue_shifted(OPENED_IMAGE, hue=50) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Smoothed", command=lambda: smoothing(OPENED_IMAGE) if OPENED_IMAGE is not None else print("No image opened.")) test_menu.add_command(label="Rotated", command=lambda: rotation(OPENED_IMAGE, rotation_angle=90) if OPENED_IMAGE is not None else print("No image opened.")) clipboard_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Clipboard", menu=clipboard_menu) image_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Image", menu=image_menu) tools_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Tools", menu=tools_menu) shapes_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Shapes", menu=shapes_menu) colors_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Colors", menu=colors_menu) layer_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Layer", menu=layer_menu) filter_menu = tk.Menu(menu, tearoff=0) menu.add_cascade(label="Filter", menu=filter_menu) # # Frame to hold image imgframe = tk.Frame(root, width=500, height=500, bg="lightgray", relief="sunken", bd=2) imgframe.pack(side="top", pady=10) # Label to display image image_label = tk.Label(imgframe, width=500, height=500, bg="white") image_label.pack(expand=True) root.mainloop()