Skip to content
Snippets Groups Projects
Commit c369f483 authored by Marc Feger's avatar Marc Feger
Browse files

Add 2.a and 2.b

parent 863b5b76
No related branches found
No related tags found
Loading
A2/GUI.py 0 → 100644
from tkinter import StringVar, Label, OptionMenu, Tk, Button, Entry, IntVar
from tkinter.filedialog import askopenfilename
from tokenize import String
from PIL import ImageTk, Image
from histogram import Histogram
from histogram_enum import HISTOGRAMS
class GUI(object):
def __init__(self, master):
"""
This class defines the GUI as one.
:param master: The Tk root.
"""
self.master = master
self.master.title('Filter')
self.image_label_width = 500
self.image_label_height = 500
self.filter_choices = {HISTOGRAMS.h1.value,
HISTOGRAMS.h2.value}
self.filter_name = StringVar(root)
self.filter_name.set(HISTOGRAMS.empty.value)
self.filter_name.trace('w', self.change_filter)
# Images
self.image_path = './images/original.jpeg'
self.edit_path = './images/histogram.jpeg'
self.image = self.read_image(self.image_path)
# Labels
self.original_image_label = Label(self.master, image=self.image)
self.original_image_label.pack()
self.filtered_image_label = Label(self.master, image=self.image)
self.filtered_image_label.pack()
# Buttons
self.option_menu = OptionMenu(self.master, self.filter_name, *self.filter_choices)
self.file_dialog = Button(master, text='Choose', command=lambda: self.set_new_file())
# Spinner
self.b_value = IntVar(self.master)
self.b_value.set(1)
self.b_menu = Entry(self.master, textvariable=self.b_value)
# Layout
self.file_dialog.grid(row=0, column=0)
self.option_menu.grid(row=0, column=1)
self.b_menu.grid(row=0, column=2)
self.original_image_label.grid(row=1, column=0)
self.filtered_image_label.grid(row=1, column=2)
def read_image(self, path: String) -> ImageTk.PhotoImage:
"""
This reads an image from a given path and resize it.
:param path: The path to the image.
:return: A image to be used in the frontend
"""
return ImageTk.PhotoImage(
Image.open(path).resize(
(self.image_label_width, self.image_label_height),
Image.ANTIALIAS
)
)
def _update_label_image(self, label: Label, new_image, row: int, column: int) -> None:
"""
This method updates to label with a new image.
:param label: The reference to the label which should be changes.
:param new_image: The reference to the new image.
:param row: Row in the GUI.
:param column: Column in the GUI.
:return: None
"""
label.destroy()
label = Label(self.master, image=new_image)
label.image = new_image
label.pack()
label.grid(row=row, column=column)
def set_new_file(self, *args) -> None:
"""
This sets the new file and refreshed the paths as well with the lables.
:return: None
"""
self.image_path: String = askopenfilename(initialdir='/', title='Select file')
new_image = self.read_image(self.image_path)
self._update_label_image(self.original_image_label, new_image, 1, 0)
self.filter_name.set(HISTOGRAMS.empty.value)
self.b_value.set(1)
self._update_label_image(self.filtered_image_label, new_image, 1, 2)
def change_filter(self, *args) -> None:
"""
This changes the filter and updates the label for the edited images.
:param args: Arguments of the listener.
:return: None
"""
self.edit_image()
edited_image = self.read_image(self.edit_path)
self._update_label_image(self.filtered_image_label, edited_image, 1, 2)
def edit_image(self) -> None:
"""
This method edits a given image and saves it as a grey-scale image.
:return: None
"""
print('From: ' + self.image_path +
' to ' + self.edit_path +
' with ' + self.filter_name.get() +
' and sigma: '
+ str(self.b_value.get()))
Histogram(
self.image_path, self.edit_path, self.b_value.get()
).get_histogram(self.filter_name.get())
# print('Done...')
if __name__ == '__main__':
"""
This program is for editing images with a given filter.
The user can choose between all filters defined in the FILTER enum.
The user can choose between all images defined in the IMAGE enum.
Preparation:
Make sure you have already installed all packages by running:
$ pip3 install -r requirements.txt
To use the program run:
$ python3 GUI.py
Notice: The edited image will be saved in ./images/edited.py. Each new filter will overwrite this image. This may
take a while.
This version uses a padding-method with mean. It makes the usage of the Kirsch-operator much faster.
"""
root = Tk()
root.resizable(False, False)
my_gui = GUI(root)
root.mainloop()
from tokenize import String
from typing import Dict, List
import imageio
import matplotlib.pyplot as plt
import numpy as np
from skimage import color
from histogram_enum import HISTOGRAMS
class Histogram(object):
def __init__(self, origin_path: String, edit_path: String, b: int = 0):
"""
This class is the editor which edits a given image and stores a new one.
:param origin_path: The original image which should be edited.
:param edit_path: The edited image which should be stored.
:param b: Is only used if the LoG-Operator is used.
"""
self.image_path = origin_path
self.edit_path = edit_path
self.b = b
@staticmethod
def __get_bins(image: imageio.core.util.Array) -> Dict:
"""
This method counts each value in the image.
h(i) = card{(u,v) | I(u,v) = i}
0 <= i <= K - 1
:param image: the greyscale image
:return: Dict where the keys are the values and the key-value is the count
"""
K = 256
count = {}
for k in range(K):
count[str(k)] = 0
height, width = image.shape
for v in range(height):
for u in range(width):
count[str(image[v, u])] += 1
return count
@staticmethod
def __get_intervals(B: int):
intervals = {}
splits = np.arange(0, 256, 255 / B)
for b in range(B):
intervals[str(b)] = list(splits[b:b + 2])
return intervals
def __get_bins_in_interval(self, image: imageio.core.util.Array, B: int) -> Dict:
"""
This method counts each value in the image.
h(i) = card{(u,v) | a_j < I(u,v) < a_j+1}
0 <= j <= B
:param image: the greyscale image
:return: Dict where the keys are the values and the key-value is the count
"""
intervals = self.__get_intervals(B)
count = {}
for b in range(B):
count[str(b)] = 0
height, width = image.shape
for v in range(height):
for u in range(width):
for b in range(B):
if intervals[str(b)][0] < image[v, u] < intervals[str(b)][1]:
count[str(b)] += 1
return count
@staticmethod
def __bins_to_list(bins: Dict) -> List:
"""
This method converts a dict into a sorted list of tuples.
:param bins: Bins of the histogram
:return: Sorted list of tuples containing all key and key-value pairs.
"""
bins_list = []
for key in bins.keys():
bins_list += [(int(key), bins[str(key)])]
return bins_list
def __plot_h1(self, keys: List, values: List, option: String):
ticks = 6
indices = np.arange(len(keys))
plt.bar(indices, values, color='black')
if option == HISTOGRAMS.h1.value:
plt.xticks(np.arange(min(keys), 256, step=255 / (ticks - 1)))
elif option == HISTOGRAMS.h2.value:
plt.xticks(np.arange(0, self.b))
plt.savefig('images/histogram.jpeg', dpi=100)
def get_histogram(self, option: String) -> None:
"""
This method iterates over the image and changes each pixel by a given method.
Notice, that the image writes the result as a grey-scale image.
:param option: The options defined in HISTOGRAMS.
:return: None
"""
image = imageio.imread(uri=self.image_path)
plt.imshow(image)
plt.show()
grey_scale_image = color.rgb2gray(image)
# convert greyscale to interval
result = np.multiply(255, grey_scale_image).astype(int)
bins = {'4': '2'}
if option == HISTOGRAMS.h1.value:
bins = self.__get_bins(result)
elif option == HISTOGRAMS.h2.value:
bins = self.__get_bins_in_interval(result, self.b)
bins = self.__bins_to_list(bins)
keys, values = zip(*bins)
self.__plot_h1(keys, values, option)
from enum import Enum
class HISTOGRAMS(Enum):
"""
This enum defines all filters.
"""
empty = '---'
h1 = 'H1'
h2 = 'H2'
A2/images/chalsea/Kadse.jpeg

47 KiB

A2/images/histogram.jpeg

36.3 KiB

A2/images/martian/martian.jpg

202 KiB

A2/images/original.jpeg

39.4 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment