Thursday, March 28, 2024

FRAME ANALYSIS AND PROCESSING IN DIGITAL VIDEO USING PYTHON AND TKINTER by Vivian Siahaan & Rismon Hasiholan Sianipar

 


 

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

Vivian Siahaan and Rismon Hasiholan Sianipar

Balige City

 

          Amazon KDP

          Google Books

         KOBO STORE


The first project in chapter one which is Canny Edge Detector presented here is a graphical user interface (GUI) application built using Tkinter in Python. This application allows users to open video files (of formats like mp4, avi, or mkv) and view them along with their corresponding Canny edge detection frames. The application provides functionalities such as playing, pausing, stopping, navigating through frames, and jumping to specific times within the video.

This second project in chapter one implements a graphical user interface (GUI) application for performing edge detection using the Prewitt operator on videos. The purpose of the code is to provide users with a tool to visualize videos, apply the Prewitt edge detection algorithm, and interactively control playback and visualization parameters.

The third project in chapter one which is "Sobel Edge Detector" is implemented in Python using Tkinter and OpenCV serves as a graphical user interface (GUI) for viewing and analyzing videos with real-time Sobel edge detection capabilities.

The "Frei-Chen Edge Detection" project as fourth project in chapter one is a graphical user interface (GUI) application built using Python and the Tkinter library. The application is designed to process and visualize video files by detecting edges using the Frei-Chen edge detection algorithm.

The "KIRSCH EDGE DETECTOR" project as the fifth project in chapter one is a Python application built using Tkinter, OpenCV, and NumPy libraries for performing edge detection on video files. It handles the visualization of the edge-detected frames in real-time. It retrieves the current frame from the video, applies Gaussian blur for noise reduction, performs Kirsch edge detection, and applies thresholding to obtain the binary edge image. The processed frame is then displayed on the canvas alongside the original video.

This "SCHARR EDGE DETECTOR" as the sixth project in chapter one is creating a graphical user interface (GUI) to visualize edge detection in videos using the Scharr algorithm. It allows users to open video files, play/pause video playback, navigate frame by frame, and apply Scharr edge detection in real-time.

The first project in chapter two is designed to provide a user-friendly interface for processing video frames using Gaussian filtering techniques. It encompasses various components and functionalities tailored towards efficient video analysis and processing. The GaussianFilter Class serves as the backbone of the application, managing GUI initialization and video processing functionalities. The GUI layout is constructed with Tkinter widgets, comprising two main panels for video display and control buttons. Key functionalities include opening video files, controlling playback, adjusting zoom levels, navigating frames, and interacting with video frames via mouse events. Additionally, users can process frames using OpenCV for Gaussian filtering to enhance video quality and reduce noise. Time navigation functionality allows users to jump to specific time points in the video. Moreover, the application supports multiple instances for simultaneous video analysis in independent windows. Overall, this project offers a comprehensive toolset for video analysis and processing, empowering users with an intuitive interface and diverse functionalities.

The second project in chapter two presents a Tkinter application tailored for video frame filtering utilizing a mean filter. It offers comprehensive functionalities including opening, playing/pausing, and stopping video playback, alongside options to navigate to previous and next frames, jump to specified times, and adjust zoom scale. Displayed on separate canvases, the original and filtered video frames are showcased distinctly. Upon video file opening, the application utilizes imageio.get_reader() for video reading, while play_video() and play_filtered_video() methods handle frame display....


DIGITAL VIDEO PROCESSING PROJECTS USING PYTHON AND TKINTER Kindle Edition by Vivian Siahaan (Author), Rismon Hasiholan Sianipar (Author) Format: Kindle Edition

 



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

Vivian Siahaan and Rismon Hasiholan Sianipar

Balige City


Amazon KDP

Google Book

Kobo Store

The first project is a video player application with an additional feature to compute and display the MD5 hash of each frame in a video. The user interface is built using Tkinter, a Python GUI toolkit, providing buttons for opening a video file, playing, pausing, and stopping the video playback. Upon opening a video file, the application displays metadata such as filename, duration, resolution, FPS, and codec information in a table. The video can be navigated using a slider to seek to a specific time point.


When the video is played, the application iterates through each frame, extracts it from the video clip, calculates its MD5 hash, and displays the frame along with its histogram and MD5 hash. The histogram represents the pixel intensity distribution of each color channel (red, green, blue) in the frame. The computed MD5 hash for each frame is displayed in a label below the video frame. Additionally, the frame hash along with its index is saved to a text file for further analysis or verification purposes.

The class encapsulates the functionality of the application, providing methods for opening a video file, playing and controlling video playback, updating metadata, computing frame histogram, plotting histogram, calculating MD5 hash for each frame, and saving frame hashes to a file. The main function initializes the Tkinter root window, instantiates the class, and starts the Tkinter event loop to handle user interactions and update the GUI accordingly.

The second project is a video player application with additional features for frame extraction and visualization of RGB histograms for each frame. Developed using Tkinter, a Python GUI toolkit, the application provides functionalities such as opening a video file, playing, pausing, and stopping video playback. The user interface includes buttons for controlling video playback, a combobox for selecting zoom scale, an entry for specifying a time point to jump to, and buttons for frame extraction and opening another instance of the application.

Upon opening a video file, the application loads it using the imageio library and displays the frames in a canvas. Users can play, pause, and stop the video using dedicated buttons. The zoom scale can be adjusted, and the video can be navigated using scrollbar or time entry. Additionally, users can extract a specific frame by entering its frame number, which opens a new window displaying the extracted frame along with its RGB histograms and MD5 hash value.

The class encapsulates the application's functionalities, including methods for opening a video file, playing/pausing/stopping video, updating zoom scale, displaying frames, handling mouse events for dragging and scrolling, jumping to a specified time, and extracting frames. The main function initializes the Tkinter root window and starts the application's event loop to handle user interactions and update the GUI accordingly. Users can also open multiple instances of the application simultaneously to work with different video files concurrently.

The third project is a GUI application built with Tkinter for calculating hash values of video frames and displaying them in a listbox. The interface consists of different frames for video display and hash values, along with buttons for controlling video playback, calculating hashes, saving hash values to a file, and opening a new instance of the application. Users can open a video file using the "Open Video" button, after which they can play, pause, or stop the video using corresponding buttons.

The fourth project is a GUI application developed using Tkinter for analyzing video frames through frame hashing and histogram visualization. The interface presents a canvas for displaying the video frames along with control buttons for video playback, frame extraction, and ...






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()