This commit is contained in:
Tom Selier 2023-09-23 21:56:45 +02:00
commit 387cdb1247
22 changed files with 197 additions and 86 deletions

59
.gitignore vendored
View File

@ -1 +1,58 @@
out # Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
# C extensions
*.so
# Distribution / packaging
bin/
build/
develop-eggs/
dist/
eggs/
lib/
lib64/
parts/
sdist/
var/
out/
*.egg-info/
.installed.cfg
*.egg
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
.tox/
.coverage
.cache
nosetests.xml
coverage.xml
# Translations
*.mo
# Mr Developer
.mr.developer.cfg
.project
.pydevproject
# Rope
.ropeproject
# Django stuff:
*.log
*.pot
# Sphinx documentation
docs/_build/
# Temp
.venv/
.vscode/
# Config file
src/config/config.json

View File

@ -1,18 +0,0 @@
### Jullie gaan noten herkennen
Hoe de neuk? Nut.
1. Hoe gaan we de noten herkennen (beeld, smaak, geluid, text)?
- Beeldherkenning lol
2. Wat zijn de visuele kenmerken van de noten?
- Vorm, kleur, textuur, grootte
3. Hoeveel noten willen we herkennen
- Qua type, hoeveel verschillende noten
- Qua tijd, hoeveel noten tegelijkertijd
4. Wat is de achtergrond
5. Met wat voor camera worden de noten bekeken
6. Is de noot verwerkt
De deelvragen moeten sequentieel zijn
Wij moeten presenteren volgende week

View File

@ -0,0 +1,4 @@
{
"path": "",
"size": 750
}

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 1.8 MiB

After

Width:  |  Height:  |  Size: 1.8 MiB

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,10 +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/gui/main.ui" PROJECT_UI = "./src/helpers/gui/main.ui"
## 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()
@ -21,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 = None 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:
@ -60,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:
@ -67,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()
@ -75,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):
@ -120,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
@ -141,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']:
@ -181,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()