Merge branch 'main' of https://arnweb.nl/gitea/arne/EV5_Beeldherk_Bomen
59
.gitignore
vendored
@ -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
|
18
md/nuts.md
@ -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
|
4
src/config/config.template.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"path": "",
|
||||
"size": 750
|
||||
}
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
Before Width: | Height: | Size: 1.8 MiB After Width: | Height: | Size: 1.8 MiB |
@ -5,6 +5,7 @@
|
||||
<property name="height">800</property>
|
||||
<property name="title" translatable="yes">Tree Recogniser 7000</property>
|
||||
<property name="width">200</property>
|
||||
<bind sequence="<Destroy>" handler="on_quit" add="" />
|
||||
<containerlayout manager="pack">
|
||||
<property name="propagate">false</property>
|
||||
</containerlayout>
|
||||
@ -175,9 +176,9 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="ttk.Button" id="button1">
|
||||
<property name="text" translatable="yes">Next img</property>
|
||||
<bind sequence="<ButtonPress>" handler="img_next" add="" />
|
||||
<object class="ttk.Button" id="prev" named="True">
|
||||
<property name="text" translatable="yes">Prev img</property>
|
||||
<bind sequence="<ButtonPress>" handler="img_prev" add="" />
|
||||
<layout manager="grid">
|
||||
<property name="column">1</property>
|
||||
<property name="ipadx">10</property>
|
||||
@ -186,9 +187,9 @@
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="ttk.Button" id="button2">
|
||||
<property name="text" translatable="yes">Prev img</property>
|
||||
<bind sequence="<ButtonPress>" handler="img_prev" add="" />
|
||||
<object class="ttk.Button" id="next" named="True">
|
||||
<property name="text" translatable="yes">Next img</property>
|
||||
<bind sequence="<ButtonPress>" handler="img_next" add="" />
|
||||
<layout manager="grid">
|
||||
<property name="column">2</property>
|
||||
<property name="ipadx">10</property>
|
||||
@ -213,7 +214,7 @@
|
||||
<bind sequence="<ButtonPress>" handler="apply" add="" />
|
||||
<layout manager="grid">
|
||||
<property name="column">2</property>
|
||||
<property name="columnspan">2</property>
|
||||
<property name="columnspan">1</property>
|
||||
<property name="ipadx">0</property>
|
||||
<property name="row">6</property>
|
||||
</layout>
|
||||
@ -238,6 +239,22 @@
|
||||
</layout>
|
||||
</object>
|
||||
</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>
|
||||
</child>
|
||||
<child>
|
165
src/suite.py
@ -8,10 +8,18 @@ import numpy as np
|
||||
import cv2
|
||||
import time
|
||||
import matplotlib.pyplot as plt
|
||||
import json
|
||||
|
||||
## UI config load
|
||||
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:
|
||||
def __init__(self, master=None):
|
||||
self.builder = builder = pygubu.Builder()
|
||||
@ -21,38 +29,51 @@ class MainApp:
|
||||
# Main widget
|
||||
self.mainwindow = builder.get_object("main", master)
|
||||
|
||||
# Canvas for output images
|
||||
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.meta = builder.get_object("dataset")
|
||||
|
||||
self.canny_thr1 = None
|
||||
self.canny_thr2 = None
|
||||
|
||||
self.img_path = None
|
||||
# Keep track of images in dataset
|
||||
self.img_current = 0
|
||||
self.img_max = 0
|
||||
|
||||
# Plots
|
||||
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.img_size = None
|
||||
self.sobel_select = None
|
||||
self.export_id = None
|
||||
builder.import_variables(self,
|
||||
['canny_thr1',
|
||||
'canny_thr2',
|
||||
'img_path',
|
||||
'blur_rate',
|
||||
'img_size',
|
||||
'sobel_select',
|
||||
'export_id'])
|
||||
builder.import_variables(self, ['canny_thr1','canny_thr2','img_path','blur_rate','img_size', 'sobel_select', 'export_id'])
|
||||
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):
|
||||
'''
|
||||
Run loop
|
||||
'''
|
||||
self.mainwindow.mainloop()
|
||||
|
||||
def img_prev(self, event=None):
|
||||
'''
|
||||
Open previous image from path
|
||||
'''
|
||||
if self.img_current == 0:
|
||||
self.img_current = self.img_max - 1
|
||||
else:
|
||||
@ -60,6 +81,9 @@ class MainApp:
|
||||
self.update(self)
|
||||
|
||||
def img_next(self, event=None):
|
||||
'''
|
||||
Open next image from path
|
||||
'''
|
||||
if self.img_current == (self.img_max - 1):
|
||||
self.img_current = 0
|
||||
else:
|
||||
@ -67,6 +91,9 @@ class MainApp:
|
||||
self.update(self)
|
||||
|
||||
def apply(self, event=None):
|
||||
'''
|
||||
Export current dataset
|
||||
'''
|
||||
img_arr = self.tk_imgs
|
||||
img_id = self.export_id.get()
|
||||
|
||||
@ -75,6 +102,54 @@ class MainApp:
|
||||
else:
|
||||
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):
|
||||
fig, axs = plt.subplots(columns, rows)
|
||||
return axs
|
||||
@ -120,11 +195,6 @@ class MainApp:
|
||||
|
||||
def update(self, event=None):
|
||||
path = self.img_path.get()
|
||||
print(path)
|
||||
|
||||
drawW = self.canvas.winfo_width()
|
||||
drawX = 0
|
||||
drawY = 0
|
||||
|
||||
if path != None and path != "":
|
||||
# Get all images at current path
|
||||
@ -141,31 +211,24 @@ class MainApp:
|
||||
sxy = self.sobel_select.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
|
||||
img = cv2.imread(images[self.img_current])
|
||||
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
|
||||
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
|
||||
output.append(img_gray) # Second output is grayscale
|
||||
self.add_output(img_gray, "Grayscale")
|
||||
|
||||
# Blurred edition
|
||||
if (br == 0):
|
||||
# Disable
|
||||
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)
|
||||
output.append(img_blur)
|
||||
self.add_output(img_blur, "Blurred")
|
||||
|
||||
# Sobel edge
|
||||
if sxy in ['x', 'y', 'both']:
|
||||
@ -182,48 +245,36 @@ class MainApp:
|
||||
img_sobel = cv2.Sobel(src=img_blur, ddepth=cv2.CV_8U, dx=dx, dy=dy, ksize=5)
|
||||
else:
|
||||
img_sobel = img_gray
|
||||
output.append(img_sobel)
|
||||
self.add_output(img_sobel, "Sobel Edge")
|
||||
|
||||
# Canny edge
|
||||
img_canny = cv2.Canny(image=img_blur,threshold1=ct1,threshold2=ct2)
|
||||
output.append(img_canny)
|
||||
self.add_output(img_canny, "Canny Edge")
|
||||
|
||||
# BGR
|
||||
output.append(img[:, :, 0]) # B
|
||||
output.append(img[:, :, 1]) # G
|
||||
output.append(img[:, :, 2]) # R
|
||||
self.add_output(img[:, :, 0], "BGR B")
|
||||
self.add_output(img[:, :, 1], "BGR G")
|
||||
self.add_output(img[:, :, 2], "BGR R")
|
||||
|
||||
if img is not None:
|
||||
self.drawHist(img, ('B', 'G', 'R'), 0, 0)
|
||||
|
||||
# HSV
|
||||
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
|
||||
output.append(img_hsv)
|
||||
output.append(img_hsv[:, :, 0]) # H
|
||||
output.append(img_hsv[:, :, 1]) # S
|
||||
output.append(img_hsv[:, :, 2]) # V
|
||||
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
|
||||
|
||||
if img_hsv is not None:
|
||||
self.drawHist(img_hsv, ('H', 'S', 'V'), 0, 1)
|
||||
|
||||
# Canny Heatmap
|
||||
self.drawCannyHM(img, 1, 1)
|
||||
|
||||
plt.show(block=False)
|
||||
|
||||
# Draw all output images
|
||||
for idx, data in enumerate(output):
|
||||
# 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
|
||||
self.canvas.draw()
|
||||
# Show all data
|
||||
plt.show(block=False) ## Graphs
|
||||
self.draw_output(size) ## Images
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = MainApp()
|
||||
|