Thursday, October 19, 2023

START FROM SCRATCH DIGITAL IMAGE PROCESSING WITH TKINTER

This book is on the writing process by Balige Publishing Team.

Vivian Siahaan and Rismon Hasiholan Sianipar

Balige City


Google Book

Amazon KDP

Kobo Store

SUPPORT OUR YOUTUBE CHANNEL























Saturday, October 14, 2023

TKINTER: COLOR SPACE

This is the product of BALIGE ACADEMY TEAM: Vivian Siahaan and Rismon Hasiholan Sianipar.

SEMANGAT BELAJAR dan HORAS!!!

BALIGE CITY, NORTH SUMATERA


SUPPORT OUR CHANNEL BY SUBSCRIBING TO IT:




TKINTER: COLOR SPACE

Amazon KDP

Amazon Paperback

Google Book

Kobo Store









FULL SOURCE CODE


#main_program.py
import tkinter as tk from main_form import Main_Form from plot_utils import Plot_Utils class Main_Program(): def __init__(self, root): self.initialize(root) def initialize(self, root): self.root = root width = 1520 height = 400 self.root.geometry(f"{width}x{height}") self.root.title("START FROM FROM SCRATCH DIGITAL IMAGE PROCESSING WITH TKINTER") #Creates necessary objects self.obj_main_form = Main_Form() self.obj_plot_utils = Plot_Utils() #Places widgets in root self.obj_main_form.add_widgets(self.root) #Binds events self.binds_event() def binds_event(self): self.obj_plot_utils.binds_fundamentals(self.obj_main_form) if __name__ == "__main__": root = tk.Tk() app = Main_Program(root) root.mainloop() #main_form.py import tkinter as tk from tkinter import ttk class Main_Form: def add_widgets(self, root): #Adds menu self.add_menu(root) def add_menu(self, root): self.menu_bar = tk.Menu(root) #Creates a image fundamentals menu self.fundamentals = tk.Menu(self.menu_bar, tearoff=0) self.fundamentals.add_command(label="Color Space") self.fundamentals.add_command(label="Fast Fourier Transform") self.fundamentals.add_command(label="Discrete Cosine Transform") self.fundamentals.add_command(label="Discrete Sine Transform") self.fundamentals.add_command(label="Discrete Wavelet Transform") self.menu_bar.add_cascade(label="Fundamentals", menu=self.fundamentals) root.config(menu=self.menu_bar) #plot_utils.py import matplotlib.pyplot as plt import tkinter as tk from tkinter import * import seaborn as sns import numpy as np import pandas as pd from form_histogram import Form_Histogram from fundamental_utils import Fundamental_Utils class Plot_Utils: def __init__(self): self.fund_utils = Fundamental_Utils() def plot_histogram(self): win = tk.Toplevel() form_hist = Form_Histogram(win) win.title("Histogram of Color Space") def binds_fundamentals(self, window): window.fundamentals.entryconfigure("Color Space", command =lambda:self.plot_histogram()) #fundamental_utils.py import matplotlib.pyplot as plt import tkinter as tk from tkinter import * import seaborn as sns import numpy as np import pandas as pd import tkinter as tk from tkinter import filedialog import matplotlib.pyplot as plt from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from PIL import Image, ImageTk import colorsys import cv2 class Fundamental_Utils: def __init__(self): pass def open_image(self, ax, figure, canvas): file_path = filedialog.askopenfilename(filetypes=[("Image files", "*.png;*.jpg;*.jpeg;*.gif;*.bmp")]) if file_path: image = Image.open(file_path) photo = ImageTk.PhotoImage(image) ax.imshow(image) ax.axis('off') ax.set_title("RGB Color Space") figure.tight_layout() canvas.draw() return image def extract_rgb(self, image): # Convert the image to a NumPy array image_array = np.array(image) # Separate the channels r_channel = image_array[:, :, 0] g_channel = image_array[:, :, 1] b_channel = image_array[:, :, 2] return r_channel, g_channel, b_channel def histogram_rgb(self, image, range_val): r_channel, g_channel, b_channel = self.extract_rgb(image) # Calculate histograms for each channel r_hist, ch1_bins = np.histogram(r_channel, bins=range_val, range=(0, range_val)) g_hist, ch2_bins = np.histogram(g_channel, bins=range_val, range=(0, range_val)) b_hist, ch3_bins = np.histogram(b_channel, bins=range_val, range=(0, range_val)) return r_hist, g_hist, b_hist def extract_hsv(self, image): img2 = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) img_hsv = cv2.cvtColor(img2, cv2.COLOR_BGR2HSV) # Separate the channels h_channel = img_hsv[:, :, 0] s_channel = img_hsv[:, :, 1] v_channel = img_hsv[:, :, 2] return h_channel, s_channel, v_channel def histogram_hsv(self, image, range_val): h_channel, s_channel, v_channel = self.extract_hsv(image) h_hist, h_bins = np.histogram(h_channel, bins=range_val, range=(0, range_val)) s_hist, s_bins = np.histogram(s_channel, bins=range_val, range=(0, range_val)) v_hist, v_bins = np.histogram(v_channel, bins=range_val, range=(0, range_val)) return h_hist, s_hist, v_hist def extract_yuv(self, image): img_yuv = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2YUV) # Separate the channels y_channel = img_yuv[:, :, 0] u_channel = img_yuv[:, :, 1] v_channel = img_yuv[:, :, 2] return y_channel, u_channel, v_channel def histogram_yuv(self, image, range_val): y_channel, u_channel, v_channel = self.extract_yuv(image) y_hist, h_bins = np.histogram(y_channel, bins=range_val, range=(0, range_val)) u_hist, s_bins = np.histogram(u_channel, bins=range_val, range=(0, range_val)) v_hist, v_bins = np.histogram(v_channel, bins=range_val, range=(0, range_val)) return y_hist, u_hist, v_hist def extract_hsl(self, image): img_hsl = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2HLS) # Separate the channels h_channel = img_hsl[:, :, 0] s_channel = img_hsl[:, :, 1] l_channel = img_hsl[:, :, 2] return h_channel, s_channel, l_channel def histogram_hsl(self, image, range_val): h_channel, s_channel, l_channel = self.extract_hsl(image) h_hist, h_bins = np.histogram(h_channel, bins=range_val, range=(0, range_val)) s_hist, s_bins = np.histogram(s_channel, bins=range_val, range=(0, range_val)) l_hist, v_bins = np.histogram(l_channel, bins=range_val, range=(0, range_val)) return h_hist, s_hist, l_hist def show_histogram_bins(self, ch1, ch2, ch3, label1, label2, label3, title, num_bins, ax, figure, canvas): # Plot histograms for each channel ax.bar(range(num_bins), ch1, color='red', alpha=0.5, label=label1) ax.bar(range(num_bins), ch2, color='green', alpha=0.5, label=label2) ax.bar(range(num_bins), ch3, color='blue', alpha=0.5, label=label3) ax.set_title(title) ax.set_xlabel('Pixel Value') ax.set_ylabel('Frequency') ax.grid(True) ax.set_facecolor('#F0F0F0') ax.legend() figure.tight_layout() canvas.draw() def show_histogram_line(self, ch1, ch2, ch3, label1, label2, label3, title, num_bins, ax, figure, canvas): # Plot histograms for each channel ax.plot(range(num_bins), ch1, color='red', alpha=0.75, label=label1) ax.plot(range(num_bins), ch2, color='green', alpha=0.75, label=label2) ax.plot(range(num_bins), ch3, color='blue', alpha=0.75, label=label3) ax.set_title(title) ax.set_xlabel('Pixel Value') ax.set_ylabel('Frequency') ax.grid(True) ax.set_facecolor('#F0F0F0') ax.legend() figure.tight_layout() canvas.draw() def display_hsv_image(self, image, ax, figure, canvas): # Convert to HSV color space img_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV) # Convert to display format hsv_image = Image.fromarray(img_hsv) # Display the image on the canvas ax.imshow(hsv_image) ax.axis('off') ax.set_title("HSV Color Space") figure.tight_layout() canvas.draw() def display_yuv_image(self, image, ax, figure, canvas): # Convert to YUV color space img_bgr = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2BGR) img_yuv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YUV) # Convert to display format yuv_image = Image.fromarray(img_yuv) # Display the image on the canvas ax.imshow(yuv_image) ax.axis('off') ax.set_title("YUV Color Space") figure.tight_layout() canvas.draw() def display_hsl_image(self, image, ax, figure, canvas): # Convert to RGB color space (if not already in RGB) img_rgb = cv2.cvtColor(np.array(image), cv2.COLOR_BGR2RGB) # Convert to HSL color space img_hsl = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HLS) # Convert to display format hsl_image = Image.fromarray(img_hsl) # Display the image on the canvas ax.imshow(hsl_image) ax.axis('off') ax.set_title("HSL Color Space") figure.tight_layout() canvas.draw() def plot_each_channel(self, ch, title, ax, cmap, figure, canvas): # Convert to display format ret_im = Image.fromarray(ch) # Display the image on the canvas ax.imshow(ret_im, cmap=cmap) ax.axis('off') ax.set_title(title) figure.tight_layout() canvas.draw() #form_histogram.py import tkinter as tk from tkinter import ttk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg from fundamental_utils import Fundamental_Utils from form_channel import Form_Channel class Form_Histogram: def __init__(self, window): self.window = window width = 1520 height = 770 self.window.geometry(f"{width}x{height}") #Adds label widgets self.add_utilities(self.window) #Adds canvasses self.add_canvas(self.window) #Creates necessary objects self.fund_utils = Fundamental_Utils() #Initial value self.image = None #Binds events self.binds_event() def add_labels(self, master): # Create two labels self.label1 = tk.Label(master, text="MAX INTENSITY") self.label1.grid(row=1, column=0, padx=5, pady=5, sticky="w") self.label2 = tk.Label(master, text="COLOR SPACE") self.label2.grid(row=3, column=0, padx=5, pady=5, sticky="w") def add_button(self, master): #Adds button self.btn1 = tk.Button(master, height=2, width=17, text="CHOOSE IMAGE", command=lambda:self.show_rgb_image()) self.btn1.grid(row=0, column=0, padx=5, pady=5, sticky="w") def add_entries(self, master): # Create entry widgets self.num_bins = tk.Entry(master, width=20, bg="cyan") self.num_bins.grid(row=2, column=0, padx=5, pady=5, sticky="w") self.num_bins.insert(0, "256") self.num_bins.bind('<Return>', self.choose_color_space) def add_combobox(self, root): # Create ComboBoxes self.combo_space = ttk.Combobox(root, width=20) self.combo_space["values"] = ["RGB", "HSV", "YUV", "HSL"] self.combo_space.grid(row=4, column=0, padx=5, pady=5, sticky="w") def add_utilities(self, master): # Create a frame for canvas1 with a border frame1 = ttk.Frame(master, borderwidth=3, relief="groove") frame1.grid(row=0, column=0, padx=5, pady=10, sticky="n") self.add_button(frame1) self.add_labels(frame1) self.add_entries(frame1) self.add_combobox(frame1) def add_canvas(self, master): # Create a frame for canvas1 with a border frame1 = ttk.Frame(master, borderwidth=3, relief="groove") frame1.grid(row=0, column=1, padx=5, pady=5, sticky="n") # Adds canvas1 widget to frame1 self.figure1 = Figure(figsize=(3.7, 3.7), dpi=100) self.figure1.patch.set_facecolor('#F0F0F0') self.canvas1 = FigureCanvasTkAgg(self.figure1, master=frame1) self.canvas1.get_tk_widget().pack(fill=tk.BOTH, expand=True) # Create a frame for canvas2 with a border frame2 = ttk.Frame(master, borderwidth=3, relief="groove") frame2.grid(row=1, column=1, padx=5, pady=5, sticky="n") # Adds canvas2 widget to frame2 self.figure2 = Figure(figsize=(3.7, 3.7), dpi=100) self.figure2.patch.set_facecolor('#F0F0F0') self.canvas2 = FigureCanvasTkAgg(self.figure2, master=frame2) self.canvas2.get_tk_widget().pack(fill=tk.BOTH, expand=True) # Create a frame for canvas3 with a border frame3 = ttk.Frame(master, borderwidth=3, relief="groove") frame3.grid(row=0, column=2, columnspan=1, rowspan=25, padx=5, pady=5, sticky="n") # Adds canvas3 widget to frame3 self.figure3 = Figure(figsize=(9.5, 7.55), dpi=100) self.figure3.patch.set_facecolor('#F0F0F0') self.canvas3 = FigureCanvasTkAgg(self.figure3, master=frame3) self.canvas3.get_tk_widget().pack(fill=tk.BOTH, expand=True) def show_rgb_image(self): # Create figure and subplot self.figure1.clear() ax1 = self.figure1.add_subplot(1, 1, 1) self.image = self.fund_utils.open_image(ax1, self.figure1, self.canvas1) #Plot histogram of RGB channel self.plot_rgb_histogram() def read_and_check_input(self, bins): try: num_bins = int(bins) except ValueError: num_bins = 256 self.num_bins.delete(0, tk.END) self.num_bins.insert(0, "256") return num_bins def plot_rgb_histogram(self): #Reads param bins = self.num_bins.get() num_bins = self.read_and_check_input(bins) #Extract histogram of RGB channel r_channel, g_channel, b_channel = self.fund_utils.histogram_rgb(self.image, num_bins) # Create figure and subplot self.figure3.clear() ax1 = self.figure3.add_subplot(2, 1, 1) ax2 = self.figure3.add_subplot(2, 1, 2) self.fund_utils.show_histogram_bins(r_channel, g_channel, b_channel, "Red", "Green", "Blue", "Histogram of RGB Channel", num_bins, ax1, self.figure3, self.canvas3) self.fund_utils.show_histogram_line(r_channel, g_channel, b_channel, "Red", "Green", "Blue", "Histogram of RGB Channel", num_bins, ax2, self.figure3, self.canvas3) def plot_rgb_channel(self): win = tk.Toplevel() form_ch = Form_Channel(win) win.title("Each Channel of RGB Color Space") form_ch.figure1.clear() ax1 = form_ch.figure1.add_subplot(1, 3, 1) ax2 = form_ch.figure1.add_subplot(1, 3, 2) ax3 = form_ch.figure1.add_subplot(1, 3, 3) r_channel, g_channel, b_channel = self.fund_utils.extract_rgb(self.image) self.fund_utils.plot_each_channel(r_channel, "Red Channel", ax1, 'Reds', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(g_channel, "Green Channel", ax2, 'Greens', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(b_channel, "Blue Channel", ax3, 'Blues', form_ch.figure1, form_ch.canvas1) def plot_hsv_histogram(self): #Reads param bins = self.num_bins.get() num_bins = self.read_and_check_input(bins) #Extract histogram of HSV channel h_channel, s_channel, v_channel = self.fund_utils.histogram_hsv(self.image, num_bins) # Create figure and subplot self.figure3.clear() ax1 = self.figure3.add_subplot(2, 1, 1) ax2 = self.figure3.add_subplot(2, 1, 2) self.fund_utils.show_histogram_bins(h_channel, s_channel, v_channel, "Hue", "Saturation", "Value", "Histogram of HSV Channel", num_bins, ax1, self.figure3, self.canvas3) self.fund_utils.show_histogram_line(h_channel, s_channel, v_channel, "Hue", "Saturation", "Value", "Histogram of HSV Channel", num_bins, ax2, self.figure3, self.canvas3) def plot_hsv_channel(self): win = tk.Toplevel() form_ch = Form_Channel(win) win.title("Each Channel of HSV Color Space") form_ch.figure1.clear() ax1 = form_ch.figure1.add_subplot(1, 3, 1) ax2 = form_ch.figure1.add_subplot(1, 3, 2) ax3 = form_ch.figure1.add_subplot(1, 3, 3) h_channel, s_channel, v_channel = self.fund_utils.extract_hsv(self.image) self.fund_utils.plot_each_channel(h_channel, "Hue Channel", ax1, 'Reds', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(s_channel, "Saturation Channel", ax2, 'Greens', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(v_channel, "Value Channel", ax3, 'Blues', form_ch.figure1, form_ch.canvas1) def plot_hsl_histogram(self): #Reads param bins = self.num_bins.get() num_bins = self.read_and_check_input(bins) #Extract histogram of HSL channel h_channel, s_channel, l_channel = self.fund_utils.histogram_hsl(self.image, num_bins) # Create figure and subplot self.figure3.clear() ax1 = self.figure3.add_subplot(2, 1, 1) ax2 = self.figure3.add_subplot(2, 1, 2) self.fund_utils.show_histogram_bins(h_channel, s_channel, l_channel, "Hue", "Saturation", "Lightness", "Histogram of HSL Channel", num_bins, ax1, self.figure3, self.canvas3) self.fund_utils.show_histogram_line(h_channel, s_channel, l_channel, "Hue", "Saturation", "Lightness", "Histogram of HSL Channel", num_bins, ax2, self.figure3, self.canvas3) def plot_hsl_channel(self): win = tk.Toplevel() form_ch = Form_Channel(win) win.title("Each Channel of HSL Color Space") form_ch.figure1.clear() ax1 = form_ch.figure1.add_subplot(1, 3, 1) ax2 = form_ch.figure1.add_subplot(1, 3, 2) ax3 = form_ch.figure1.add_subplot(1, 3, 3) h_channel, s_channel, l_channel = self.fund_utils.extract_hsl(self.image) self.fund_utils.plot_each_channel(h_channel, "Hue Channel", ax1, 'Reds', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(s_channel, "Saturation Channel", ax2, 'Greens', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(l_channel, "Lightness Channel", ax3, 'Blues', form_ch.figure1, form_ch.canvas1) def plot_yuv_histogram(self): #Reads param bins = self.num_bins.get() num_bins = self.read_and_check_input(bins) #Extract histogram of YUV channel y_channel, u_channel, v_channel = self.fund_utils.histogram_yuv(self.image, num_bins) # Create figure and subplot self.figure3.clear() ax1 = self.figure3.add_subplot(2, 1, 1) ax2 = self.figure3.add_subplot(2, 1, 2) self.fund_utils.show_histogram_bins(y_channel, u_channel, v_channel, "Y (Luma)", "U (Chrominance Blue)", "V (Chrominance Red)", "Histogram of YUV Channel", num_bins, ax1, self.figure3, self.canvas3) self.fund_utils.show_histogram_line(y_channel, u_channel, v_channel, "Y (Luma)", "U (Chrominance Blue)", "V (Chrominance Red)", "Histogram of YUV Channel", num_bins, ax2, self.figure3, self.canvas3) def plot_yuv_channel(self): win = tk.Toplevel() form_ch = Form_Channel(win) win.title("Each Channel of YUV Color Space") form_ch.figure1.clear() ax1 = form_ch.figure1.add_subplot(1, 3, 1) ax2 = form_ch.figure1.add_subplot(1, 3, 2) ax3 = form_ch.figure1.add_subplot(1, 3, 3) y_channel, u_channel, v_channel = self.fund_utils.extract_yuv(self.image) self.fund_utils.plot_each_channel(y_channel, "Y (Luma) Channel", ax1, 'Greens', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(u_channel, "U (Chrominance Blue)", ax2, 'Blues', form_ch.figure1, form_ch.canvas1) self.fund_utils.plot_each_channel(v_channel, "V (Chrominance Red)", ax3, 'Reds', form_ch.figure1, form_ch.canvas1) def choose_color_space(self, event): #Reads color space self.chosen_space = self.combo_space.get() if self.chosen_space == "RGB": self.plot_rgb_histogram() self.plot_rgb_channel() if self.chosen_space == "HSV": self.figure2.clear() ax = self.figure2.add_subplot(1, 1, 1) self.fund_utils.display_hsv_image(self.image, ax, self.figure2, self.canvas2) self.plot_hsv_histogram() self.plot_hsv_channel() if self.chosen_space == "YUV": self.figure2.clear() ax = self.figure2.add_subplot(1, 1, 1) self.fund_utils.display_yuv_image(self.image, ax, self.figure2, self.canvas2) self.plot_yuv_histogram() self.plot_yuv_channel() if self.chosen_space == "HSL": self.figure2.clear() ax = self.figure2.add_subplot(1, 1, 1) self.fund_utils.display_hsl_image(self.image, ax, self.figure2, self.canvas2) self.plot_hsl_histogram() self.plot_hsl_channel() def binds_event(self): # Binds combo_wavelet to choose_wavelet() self.combo_space.bind("<<ComboboxSelected>>", self.choose_color_space) if __name__ == "__main__": window = tk.Tk() Form_Histogram(window) window.mainloop() #form_channel.py import tkinter as tk from tkinter import ttk from matplotlib.figure import Figure from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg class Form_Channel: def __init__(self, window): self.window = window width = 1500 height = 540 self.window.geometry(f"{width}x{height}") #Adds canvas self.add_canvas(self.window) def add_canvas(self, master): # Create a frame for canvas3 with a border frame1 = ttk.Frame(master, borderwidth=3, relief="groove") frame1.grid(row=0, column=0, columnspan=1, rowspan=25, padx=5, pady=5, sticky="n") # Adds canvas1 widget to frame1 self.figure1 = Figure(figsize=(14.7, 5), dpi=100) self.figure1.patch.set_facecolor('#F0F0F0') self.canvas1 = FigureCanvasTkAgg(self.figure1, master=frame1) self.canvas1.get_tk_widget().pack(fill=tk.BOTH, expand=True) if __name__ == "__main__": window = tk.Tk() Form_Channel(window) window.mainloop()