Suite QOL

This commit is contained in:
Arne van Iterson 2023-09-23 21:02:30 +02:00
parent 5b1b25bc13
commit 3ae6b41c62
3 changed files with 135 additions and 68 deletions

View File

@ -5,6 +5,7 @@
<property name="height">800</property> <property name="height">800</property>
<property name="title" translatable="yes">Tree Recogniser 7000</property> <property name="title" translatable="yes">Tree Recogniser 7000</property>
<property name="width">200</property> <property name="width">200</property>
<bind sequence="&lt;Destroy&gt;" handler="on_quit" add="" />
<containerlayout manager="pack"> <containerlayout manager="pack">
<property name="propagate">false</property> <property name="propagate">false</property>
</containerlayout> </containerlayout>
@ -175,9 +176,9 @@
</object> </object>
</child> </child>
<child> <child>
<object class="ttk.Button" id="button1"> <object class="ttk.Button" id="prev" named="True">
<property name="text" translatable="yes">Next img</property> <property name="text" translatable="yes">Prev img</property>
<bind sequence="&lt;ButtonPress&gt;" handler="img_next" add="" /> <bind sequence="&lt;ButtonPress&gt;" handler="img_prev" add="" />
<layout manager="grid"> <layout manager="grid">
<property name="column">1</property> <property name="column">1</property>
<property name="ipadx">10</property> <property name="ipadx">10</property>
@ -186,9 +187,9 @@
</object> </object>
</child> </child>
<child> <child>
<object class="ttk.Button" id="button2"> <object class="ttk.Button" id="next" named="True">
<property name="text" translatable="yes">Prev img</property> <property name="text" translatable="yes">Next img</property>
<bind sequence="&lt;ButtonPress&gt;" handler="img_prev" add="" /> <bind sequence="&lt;ButtonPress&gt;" handler="img_next" add="" />
<layout manager="grid"> <layout manager="grid">
<property name="column">2</property> <property name="column">2</property>
<property name="ipadx">10</property> <property name="ipadx">10</property>
@ -213,7 +214,7 @@
<bind sequence="&lt;ButtonPress&gt;" handler="apply" add="" /> <bind sequence="&lt;ButtonPress&gt;" handler="apply" add="" />
<layout manager="grid"> <layout manager="grid">
<property name="column">2</property> <property name="column">2</property>
<property name="columnspan">2</property> <property name="columnspan">1</property>
<property name="ipadx">0</property> <property name="ipadx">0</property>
<property name="row">6</property> <property name="row">6</property>
</layout> </layout>
@ -238,6 +239,22 @@
</layout> </layout>
</object> </object>
</child> </child>
<child>
<object class="tk.Text" id="dataset" named="True">
<property name="height">10</property>
<property name="pady">0</property>
<property name="state">disabled</property>
<property name="text" translatable="yes">Image metadata should appear here</property>
<property name="width">25</property>
<property name="wrap">word</property>
<layout manager="grid">
<property name="column">3</property>
<property name="columnspan">1</property>
<property name="row">0</property>
<property name="rowspan">8</property>
</layout>
</object>
</child>
</object> </object>
</child> </child>
<child> <child>

View File

@ -8,11 +8,18 @@ import numpy as np
import cv2 import cv2
import time import time
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
import json
## UI config load
PROJECT_PATH = pathlib.Path(__file__).parent PROJECT_PATH = pathlib.Path(__file__).parent
PROJECT_UI = "./src/helpers/gui/main.ui" PROJECT_UI = "./src/helpers/gui/main.ui"
CONFIG_PATH = "./src/config/config.json"
## Config file load
CONFIG_PATH = "./src/config/config.json"
config_file = open(CONFIG_PATH)
config_json = json.load(config_file)
## UI class setup
class MainApp: class MainApp:
def __init__(self, master=None): def __init__(self, master=None):
self.builder = builder = pygubu.Builder() self.builder = builder = pygubu.Builder()
@ -22,38 +29,51 @@ class MainApp:
# Main widget # Main widget
self.mainwindow = builder.get_object("main", master) self.mainwindow = builder.get_object("main", master)
# Canvas for output images
self.canvas = builder.get_object("output_canvas") self.canvas = builder.get_object("output_canvas")
self.tk_imgs = [] self.tk_imgs = [] # Required or python will forget
self.output = [[] for x in range(2)]
self.canny_thr1 = None self.meta = builder.get_object("dataset")
self.canny_thr2 = None
# Keep track of images in dataset
self.img_path = None
self.img_current = 0 self.img_current = 0
self.img_max = 0 self.img_max = 0
# Plots # Plots
self.axs = self.createPlot(2, 2) self.axs = self.createPlot(2, 2)
# UI # UI Variables
self.canny_thr1 = None
self.canny_thr2 = None
self.img_path = None
self.blur_rate = None self.blur_rate = None
self.img_size = 100 self.img_size = None
self.sobel_select = None self.sobel_select = None
self.export_id = None self.export_id = None
builder.import_variables(self, builder.import_variables(self, ['canny_thr1','canny_thr2','img_path','blur_rate','img_size', 'sobel_select', 'export_id'])
['canny_thr1',
'canny_thr2',
'img_path',
'blur_rate',
'img_size',
'sobel_select',
'export_id'])
builder.connect_callbacks(self) builder.connect_callbacks(self)
# Load values from config after UI has been initialised
self.img_path.set(config_json["path"])
self.img_size.set(config_json["size"])
def on_quit(self, event=None):
'''
Close PLT windows on main app quit
'''
plt.close()
self.mainwindow.quit();
def run(self): def run(self):
'''
Run loop
'''
self.mainwindow.mainloop() self.mainwindow.mainloop()
def img_prev(self, event=None): def img_prev(self, event=None):
'''
Open previous image from path
'''
if self.img_current == 0: if self.img_current == 0:
self.img_current = self.img_max - 1 self.img_current = self.img_max - 1
else: else:
@ -61,6 +81,9 @@ class MainApp:
self.update(self) self.update(self)
def img_next(self, event=None): def img_next(self, event=None):
'''
Open next image from path
'''
if self.img_current == (self.img_max - 1): if self.img_current == (self.img_max - 1):
self.img_current = 0 self.img_current = 0
else: else:
@ -68,6 +91,9 @@ class MainApp:
self.update(self) self.update(self)
def apply(self, event=None): def apply(self, event=None):
'''
Export current dataset
'''
img_arr = self.tk_imgs img_arr = self.tk_imgs
img_id = self.export_id.get() img_id = self.export_id.get()
@ -76,10 +102,58 @@ class MainApp:
else: else:
print("Nothing to export!") print("Nothing to export!")
def add_output(self, data, name: str):
'''
Add CV2 image to canvas output
'''
self.output[0].append(data)
self.output[1].append(name)
def draw_output(self, size):
# Check if size of canvas has updated
drawW = self.canvas.winfo_width()
# Reset drawing position
drawX = 0
drawY = 0
# Clear previously printed images
self.tk_imgs = []
self.meta.config(state=NORMAL)
self.meta.delete(1.0, END)
# Draw all output images
for idx, data in enumerate(self.output[0]):
# Create ui image
tk_img = cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
tk_img = ImageTk.PhotoImage(image=Image.fromarray(tk_img))
self.tk_imgs.append(tk_img)
## Check if next item will be out of range
if (drawX + size >= drawW):
drawY += size
drawX = 0
self.canvas.configure(height=(drawY+size))
self.canvas.create_image(drawX,drawY,anchor=NW,image=self.tk_imgs[idx],tags="og")
drawX += size
# Add name to text box
self.meta.insert(END, F"{idx}: {self.output[1][idx]}\n")
# Clear output
self.output = [[] for x in range(2)]
self.meta.config(state=DISABLED)
# Draw canvas
# TODO IDK volgens mij moet je deze wel callen maar het programma doet het nog (geen vragen stellen)
# self.canvas.draw()
def createPlot(self, columns, rows): def createPlot(self, columns, rows):
fig, axs = plt.subplots(columns, rows) fig, axs = plt.subplots(columns, rows)
return axs return axs
def drawHist(self, image, labels, column, row): def drawHist(self, image, labels, column, row):
self.axs[column, row].clear() self.axs[column, row].clear()
for i,lab in enumerate(labels): for i,lab in enumerate(labels):
@ -121,11 +195,6 @@ class MainApp:
def update(self, event=None): def update(self, event=None):
path = self.img_path.get() path = self.img_path.get()
print(path)
drawW = self.canvas.winfo_width()
drawX = 0
drawY = 0
if path != None and path != "": if path != None and path != "":
# Get all images at current path # Get all images at current path
@ -142,31 +211,24 @@ class MainApp:
sxy = self.sobel_select.get() sxy = self.sobel_select.get()
size = self.img_size.get() size = self.img_size.get()
# Keep array of cv2 images to output
output = []
# Clear previously printed images
self.tk_imgs = []
# Import and resize image # Import and resize image
img = cv2.imread(images[self.img_current]) img = cv2.imread(images[self.img_current])
img = cv2.resize(img, (size, size), interpolation = cv2.INTER_AREA) img = cv2.resize(img, (size, size), interpolation = cv2.INTER_AREA)
output.append(img) # First output image is original self.add_output(img, "Original")
# Set grayscale # Set grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
output.append(img_gray) # Second output is grayscale self.add_output(img_gray, "Grayscale")
# Blurred edition # Blurred edition
if (br == 0): if (br == 0):
# Disable
img_blur = img_gray img_blur = img_gray
elif (br % 2 == 1): elif (br % 2 == 1):
img_blur = cv2.GaussianBlur(img_gray, (br, br), 0) img_blur = cv2.GaussianBlur(img_gray, (br, br), 0)
else: else:
print(f"Blur rate changed to {br - 1}") print(f"Blur rate changed to {br - 1}")
img_blur = cv2.GaussianBlur(img_gray, (br-1, br-1), 0) img_blur = cv2.GaussianBlur(img_gray, (br-1, br-1), 0)
output.append(img_blur) self.add_output(img_blur, "Blurred")
# Sobel edge # Sobel edge
if sxy in ['x', 'y', 'both']: if sxy in ['x', 'y', 'both']:
@ -182,49 +244,37 @@ class MainApp:
img_sobel = cv2.Sobel(src=img_blur, ddepth=cv2.CV_8U, dx=dx, dy=dy, ksize=5) img_sobel = cv2.Sobel(src=img_blur, ddepth=cv2.CV_8U, dx=dx, dy=dy, ksize=5)
else: else:
img_sobel = img_gray img_sobel = img_gray
output.append(img_sobel) self.add_output(img_sobel, "Sobel Edge")
# Canny edge # Canny edge
img_canny = cv2.Canny(image=img_blur,threshold1=ct1,threshold2=ct2) img_canny = cv2.Canny(image=img_blur,threshold1=ct1,threshold2=ct2)
output.append(img_canny) self.add_output(img_canny, "Canny Edge")
# BGR # BGR
output.append(img[:, :, 0]) # B self.add_output(img[:, :, 0], "BGR B")
output.append(img[:, :, 1]) # G self.add_output(img[:, :, 1], "BGR G")
output.append(img[:, :, 2]) # R self.add_output(img[:, :, 2], "BGR R")
if img is not None: if img is not None:
self.drawHist(img, ('B', 'G', 'R'), 0, 0) self.drawHist(img, ('B', 'G', 'R'), 0, 0)
# HSV # HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
output.append(img_hsv) self.add_output(img_hsv, "HSV")
output.append(img_hsv[:, :, 0]) # H self.add_output(img_hsv[:, :, 0], "HSV H") # H
output.append(img_hsv[:, :, 1]) # S self.add_output(img_hsv[:, :, 1], "HSV S") # S
output.append(img_hsv[:, :, 2]) # V self.add_output(img_hsv[:, :, 2], "HSV V") # V
if img_hsv is not None: if img_hsv is not None:
self.drawHist(img_hsv, ('H', 'S', 'V'), 0, 1) self.drawHist(img_hsv, ('H', 'S', 'V'), 0, 1)
# Canny Heatmap
self.drawCannyHM(img, 1, 1) self.drawCannyHM(img, 1, 1)
plt.show(block=False)
# Draw all output images # Show all data
for idx, data in enumerate(output): plt.show(block=False) ## Graphs
# Create ui image self.draw_output(size) ## Images
tk_img = cv2.cvtColor(data, cv2.COLOR_BGR2RGB)
tk_img = ImageTk.PhotoImage(image=Image.fromarray(tk_img))
self.tk_imgs.append(tk_img)
## Check if next item will be out of range
if (drawX + size >= drawW):
drawY += size
drawX = 0
self.canvas.configure(height=(drawY+size))
self.canvas.create_image(drawX,drawY,anchor=NW,image=self.tk_imgs[idx],tags="og")
drawX += size
self.canvas.draw()
if __name__ == "__main__": if __name__ == "__main__":
app = MainApp() app = MainApp()