EV5_Beeldherk_Bomen/src/suite.py

292 lines
9.4 KiB
Python
Raw Normal View History

2023-09-14 14:24:12 +02:00
#!/usr/bin/python3
import pathlib
import pygubu
2023-09-22 13:45:34 +02:00
import glob
2023-09-14 14:24:12 +02:00
from tkinter import *
from PIL import ImageTk, Image
import numpy as np
import cv2
2023-09-22 13:45:34 +02:00
import time
2023-09-22 15:23:22 +02:00
import matplotlib.pyplot as plt
2023-09-23 21:02:30 +02:00
import json
2023-09-25 14:57:34 +02:00
from helpers.statistics import imgStats
2023-09-14 14:24:12 +02:00
2023-09-23 21:02:30 +02:00
## UI config load
2023-09-14 14:24:12 +02:00
PROJECT_PATH = pathlib.Path(__file__).parent
2023-09-23 18:35:51 +02:00
PROJECT_UI = "./src/helpers/gui/main.ui"
2023-09-23 21:02:30 +02:00
## Config file load
2023-09-23 18:35:51 +02:00
CONFIG_PATH = "./src/config/config.json"
2023-09-23 21:02:30 +02:00
config_file = open(CONFIG_PATH)
config_json = json.load(config_file)
2023-09-14 14:24:12 +02:00
2023-09-23 21:02:30 +02:00
## UI class setup
2023-09-14 14:24:12 +02:00
class MainApp:
def __init__(self, master=None):
self.builder = builder = pygubu.Builder()
builder.add_resource_path(PROJECT_PATH)
builder.add_from_file(PROJECT_UI)
2023-09-22 15:23:22 +02:00
2023-09-14 14:24:12 +02:00
# Main widget
self.mainwindow = builder.get_object("main", master)
2023-09-23 21:02:30 +02:00
# Canvas for output images
2023-09-14 14:24:12 +02:00
self.canvas = builder.get_object("output_canvas")
2023-09-23 21:02:30 +02:00
self.tk_imgs = [] # Required or python will forget
self.output = [[] for x in range(2)]
self.meta = builder.get_object("dataset")
# Keep track of images in dataset
2023-09-22 13:45:34 +02:00
self.img_current = 0
self.img_max = 0
2023-09-22 15:23:22 +02:00
# Plots
self.axs = self.createPlot(2, 2)
2023-09-23 21:02:30 +02:00
# UI Variables
self.canny_thr1 = None
self.canny_thr2 = None
self.img_path = None
2023-09-14 14:24:12 +02:00
self.blur_rate = None
2023-09-23 21:02:30 +02:00
self.img_size = None
2023-09-14 14:24:12 +02:00
self.sobel_select = None
2023-09-22 13:45:34 +02:00
self.export_id = None
2023-09-23 21:02:30 +02:00
builder.import_variables(self, ['canny_thr1','canny_thr2','img_path','blur_rate','img_size', 'sobel_select', 'export_id'])
2023-09-14 14:24:12 +02:00
builder.connect_callbacks(self)
2023-09-23 21:02:30 +02:00
# 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();
2023-09-14 14:24:12 +02:00
def run(self):
2023-09-23 21:02:30 +02:00
'''
Run loop
'''
2023-09-14 14:24:12 +02:00
self.mainwindow.mainloop()
2023-09-22 13:45:34 +02:00
def img_prev(self, event=None):
2023-09-23 21:02:30 +02:00
'''
Open previous image from path
'''
2023-09-22 13:45:34 +02:00
if self.img_current == 0:
self.img_current = self.img_max - 1
else:
self.img_current = self.img_current - 1
self.update(self)
def img_next(self, event=None):
2023-09-23 21:02:30 +02:00
'''
Open next image from path
'''
2023-09-22 13:45:34 +02:00
if self.img_current == (self.img_max - 1):
self.img_current = 0
else:
self.img_current = self.img_current + 1
self.update(self)
def apply(self, event=None):
2023-09-23 21:02:30 +02:00
'''
Export current dataset
'''
2023-09-22 13:45:34 +02:00
img_arr = self.tk_imgs
img_id = self.export_id.get()
if (img_id >= 0 and img_id < len(img_arr)):
print("export")
else:
print("Nothing to export!")
2023-09-14 14:24:12 +02:00
2023-09-23 21:02:30 +02:00
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()
2023-09-22 15:23:22 +02:00
def createPlot(self, columns, rows):
fig, axs = plt.subplots(columns, rows)
return axs
2023-09-23 21:02:30 +02:00
2023-09-22 15:23:22 +02:00
def drawHist(self, image, labels, column, row):
self.axs[column, row].clear()
for i,lab in enumerate(labels):
hist = cv2.calcHist(
[image],
[i],
None,
[256],
[0, 256],
)
self.axs[column, row].plot(hist, label=lab)
self.axs[column, row].grid()
self.axs[column, row].legend()
2023-09-22 16:15:57 +02:00
def drawCannyHM(self, img, column, row):
self.axs[column, row].clear()
canny_max = 500
canny_step = 20
results = [[] for x in range((int)(canny_max / canny_step))]
2023-09-22 15:23:22 +02:00
2023-09-22 16:15:57 +02:00
for th1 in range(0, canny_max, canny_step):
for th2 in range(0, canny_max, canny_step):
# Canny Edge Detection
edges = cv2.Canny(image=img, threshold1=th1, threshold2=th2)
w_res = cv2.countNonZero(edges)
y_ind = (int)(th1 / canny_step)
x_ind = (int)(th2 / canny_step)
results[y_ind].append(w_res)
# print(f"Result at thres {th1}, {th2}; \tIndex {y_ind}, {x_ind} \t= {w_res}")
# print(results[y_ind])
self.axs[column, row].imshow(results)
self.axs[column, row].xaxis.set_major_formatter(lambda x, pos: str(x*canny_step))
self.axs[column, row].yaxis.set_major_formatter(lambda x, pos: str(x*canny_step))
2023-09-25 14:57:34 +02:00
def writeStats(self, img, labels, column, row):
mean, std = imgStats(img)
self.axs[column, row].title.set_text(
"mean: %c:%d %c:%d %c:%d \n std: %c:%d %c:%d %c:%d"
%(labels[0], mean[0], labels[1], mean[1], labels[2], mean[2],
labels[0], std[0], labels[1], std[1], labels[2], std[2]))
2023-09-22 16:15:57 +02:00
2023-09-14 14:24:12 +02:00
def update(self, event=None):
path = self.img_path.get()
if path != None and path != "":
2023-09-22 13:45:34 +02:00
# Get all images at current path
images = []
for file in glob.glob(path + "/*.png"):
images.append(file)
self.img_max = len(images)
2023-09-14 14:24:12 +02:00
# Get all user vars
ct1 = self.canny_thr1.get()
2023-09-22 16:15:57 +02:00
ct2 = self.canny_thr2.get()
2023-09-14 14:24:12 +02:00
br = self.blur_rate.get()
sxy = self.sobel_select.get()
size = self.img_size.get()
# Import and resize image
2023-09-22 13:45:34 +02:00
img = cv2.imread(images[self.img_current])
2023-09-14 14:24:12 +02:00
img = cv2.resize(img, (size, size), interpolation = cv2.INTER_AREA)
2023-09-23 21:02:30 +02:00
self.add_output(img, "Original")
2023-09-14 14:24:12 +02:00
# Set grayscale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
2023-09-23 21:02:30 +02:00
self.add_output(img_gray, "Grayscale")
2023-09-14 14:24:12 +02:00
# Blurred edition
if (br == 0):
img_blur = img_gray
elif (br % 2 == 1):
img_blur = cv2.GaussianBlur(img_gray, (br, br), 0)
else:
print(f"Blur rate changed to {br - 1}")
img_blur = cv2.GaussianBlur(img_gray, (br-1, br-1), 0)
2023-09-23 21:02:30 +02:00
self.add_output(img_blur, "Blurred")
2023-09-14 14:24:12 +02:00
# Sobel edge
if sxy in ['x', 'y', 'both']:
if sxy == 'x':
dx = 1
dy = 0
elif sxy == 'y':
dx = 0
dy = 1
elif sxy == 'both':
dx = 1
dy = 1
img_sobel = cv2.Sobel(src=img_blur, ddepth=cv2.CV_8U, dx=dx, dy=dy, ksize=5)
else:
2023-09-23 21:02:30 +02:00
img_sobel = img_gray
self.add_output(img_sobel, "Sobel Edge")
2023-09-14 14:24:12 +02:00
# Canny edge
img_canny = cv2.Canny(image=img_blur,threshold1=ct1,threshold2=ct2)
2023-09-23 21:02:30 +02:00
self.add_output(img_canny, "Canny Edge")
2023-09-22 15:23:22 +02:00
# BGR
2023-09-23 21:02:30 +02:00
self.add_output(img[:, :, 0], "BGR B")
self.add_output(img[:, :, 1], "BGR G")
self.add_output(img[:, :, 2], "BGR R")
2023-09-22 15:23:22 +02:00
if img is not None:
self.drawHist(img, ('B', 'G', 'R'), 0, 0)
2023-09-25 14:57:34 +02:00
self.writeStats(img, ('B', 'G', 'R'), 0, 0)
2023-09-22 15:23:22 +02:00
# HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
2023-09-23 21:02:30 +02:00
self.add_output(img_hsv, "HSV")
self.add_output(img_hsv[:, :, 0], "HSV H") # H
self.add_output(img_hsv[:, :, 1], "HSV S") # S
self.add_output(img_hsv[:, :, 2], "HSV V") # V
2023-09-22 15:23:22 +02:00
if img_hsv is not None:
self.drawHist(img_hsv, ('H', 'S', 'V'), 0, 1)
2023-09-25 14:57:34 +02:00
self.writeStats(img_hsv, ('H', 'S', 'V'), 0, 1)
2023-09-22 16:15:57 +02:00
2023-09-23 21:02:30 +02:00
# Canny Heatmap
2023-09-22 16:15:57 +02:00
self.drawCannyHM(img, 1, 1)
2023-09-14 14:24:12 +02:00
2023-09-23 21:02:30 +02:00
# Show all data
plt.show(block=False) ## Graphs
self.draw_output(size) ## Images
2023-09-14 14:24:12 +02:00
if __name__ == "__main__":
app = MainApp()
app.run()