From 9b0c14129cbcd9b4495a5256dc967f9955bb4e03 Mon Sep 17 00:00:00 2001 From: vb Date: Sat, 11 Oct 2025 13:33:50 +0200 Subject: [PATCH 1/3] demo.py -> main.py --- main.py | 217 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 main.py diff --git a/main.py b/main.py new file mode 100644 index 0000000..5281843 --- /dev/null +++ b/main.py @@ -0,0 +1,217 @@ + +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() From 0741b85b24f151b45a5a0ab573bd6ba35f84be82 Mon Sep 17 00:00:00 2001 From: vb Date: Sat, 11 Oct 2025 13:33:58 +0200 Subject: [PATCH 2/3] deleted: demo.py --- app/__init__.py | 0 app/functions.py | 0 demo.py | 218 ----------------------------------------------- 3 files changed, 218 deletions(-) create mode 100644 app/__init__.py create mode 100644 app/functions.py delete mode 100644 demo.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/app/functions.py b/app/functions.py new file mode 100644 index 0000000..e69de29 diff --git a/demo.py b/demo.py deleted file mode 100644 index 1b0396e..0000000 --- a/demo.py +++ /dev/null @@ -1,218 +0,0 @@ - -import os -import cv2 -import numpy as np -import tkinter as tk -from tkinter import filedialog -from PIL import Image, ImageTk - - -CURRENT_IMAGE_BASENAME = None # Track the basename of the currently opened image - -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 CURRENT_IMAGE_BASENAME - CURRENT_IMAGE_BASENAME = os.path.basename(file_path) - 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(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - 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(f"cache/{CURRENT_IMAGE_BASENAME}", border_width=50) if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Crop", command=lambda: crop(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Resize", command=lambda: resize(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Copy", command=lambda: copy(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Greyscale", command=lambda: grayscale(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Hsv", command=lambda: hsv(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Hue Shifted", command=lambda: hue_shifted(f"cache/{CURRENT_IMAGE_BASENAME}", hue=50) if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Smoothed", command=lambda: smoothing(f"cache/{CURRENT_IMAGE_BASENAME}") if CURRENT_IMAGE_BASENAME else print("No image opened.")) - test_menu.add_command(label="Rotated", command=lambda: rotation(f"cache/{CURRENT_IMAGE_BASENAME}", rotation_angle=90) if CURRENT_IMAGE_BASENAME 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() From bef5f5edb3011b12125400da8e9b979fe85e8675 Mon Sep 17 00:00:00 2001 From: vb Date: Sat, 11 Oct 2025 13:34:23 +0200 Subject: [PATCH 3/3] deleted: app/__init__.py deleted: app/functions.py --- app/__init__.py | 0 app/functions.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 app/__init__.py delete mode 100644 app/functions.py diff --git a/app/__init__.py b/app/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/app/functions.py b/app/functions.py deleted file mode 100644 index e69de29..0000000