diff --git a/README.md b/README.md
index 9966a10..f74e256 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,12 @@ $ ./.venv/Scripts/activate(.bat/.ps1)
$ pip install -r ./requirements.txt
```
+### Fix relative imports
+1. Install the local package as editable using `pip`:
+```sh
+$ pip install -e .
+```
+
### Create a dataset
1. Rename all images to include a tag and unique id, seperated by an underscore '_'
- e.g. `accasia_1210262`
@@ -84,6 +90,9 @@ $ python ./src/helpers/test/knn.py -i ./out/result-(date/time).csv -o ./out/mode
```
4. Edit your `config.json` to include the newly created model
+> :memo: **Please note:**
+> The KNN Training script also generates the scaler required to make the decision tree model
+
---
Arne van Iterson
diff --git a/requirements.txt b/requirements.txt
index 56caf5e..3bb7058 100644
Binary files a/requirements.txt and b/requirements.txt differ
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..6f05aa2
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,2 @@
+from setuptools import setup, find_packages
+setup(name='CVSuite', version='1.0', packages=find_packages())
\ No newline at end of file
diff --git a/src/helpers/__init__.py b/src/helpers/__init__.py
new file mode 100644
index 0000000..8b32d5c
--- /dev/null
+++ b/src/helpers/__init__.py
@@ -0,0 +1,2 @@
+from .logger import *
+from .tags import *
\ No newline at end of file
diff --git a/src/helpers/test/decision_tree.py b/src/helpers/test/decision_tree.py
index 4bede1d..05209e9 100644
--- a/src/helpers/test/decision_tree.py
+++ b/src/helpers/test/decision_tree.py
@@ -7,27 +7,14 @@ import csv
import argparse
import os
+from ..tags import Tree
+
parser = argparse.ArgumentParser(prog='DecisionTree CLI')
parser.add_argument('-i', '--input', help='Input CSV file', required=True)
parser.add_argument('-o', '--output', help='Output model folder', required=True)
-parser.add_argument(
- '-m',
- '--model',
- help='Chosen model (\'dectree\', \'randforest\' or \'extratree\')',
- required=True
- )
+parser.add_argument('-m', '--model', help='Chosen model (\'dectree\', \'randforest\' or \'extratree\')', required=True)
parser.add_argument('-s', '--scaler', help='Scaler preprocesser', required=True)
-class Tree(Enum):
- ACCASIA = 0
- BERK = 1
- EIK = 2
- ELS = 3
- ESDOORN = 4
- ES = 5
- LINDE = 6
- PLATAAN = 7
-
class CVSuiteTestTree:
def __init__(self, model_path = None):
self.model_path = model_path
@@ -40,12 +27,11 @@ class CVSuiteTestTree:
reader = csv.reader(file, delimiter= ',')
matrix = list(reader)
- i = 0
labels = []
data = [[] for x in range(len(matrix)-1)]
# Load all but the headers
- for row in matrix[1:]:
+ for ridx, row in enumerate(matrix[1:]):
## append data to lists
label = row.pop(0).upper()
labels.append(Tree[label].value)
@@ -54,12 +40,12 @@ class CVSuiteTestTree:
row.pop(0)
# append all but ID and tree
- for element in row:
- data[i].append(float(element))
- i += 1
+ for idx, element in enumerate(row):
+ value = self.scaler[idx].transform([[float(element)]])
+ data[ridx].append(value[0][0])
- # normalize data
- #TODO: Arne help
+ # normalize data has been included in code above :D
+ #TODO: Check if data is normalized correctly
# train model
self.train(data, labels, output)
diff --git a/src/helpers/test/knn.py b/src/helpers/test/knn.py
index c5c1969..6620578 100644
--- a/src/helpers/test/knn.py
+++ b/src/helpers/test/knn.py
@@ -9,20 +9,13 @@ import joblib
import datetime
import os
+from ..logger import C_DBUG
+from ..tags import Tree
+
parser = argparse.ArgumentParser(prog='KNN Train CLI')
parser.add_argument('-i', '--input', help='Input CSV file', required=True)
parser.add_argument('-o', '--output', help='Output model file', required=True)
-class Tree(Enum):
- ACCASIA = 0
- BERK = 1
- EIK = 2
- ELS = 3
- ESDOORN = 4
- ES = 5
- LINDE = 6
- PLATAAN = 7
-
class CVSuiteTestKNN:
def __init__(self, model = None):
self.scale = []
@@ -113,7 +106,12 @@ class CVSuiteTestKNN:
self.knn.save(os.path.join(output, F"model_knn_{now.strftime('%Y-%m-%dT%H.%M.%S')}.yaml"))
def predict(self, data, nr = 3):
- return self.knn.findNearest(data, nr)
+ ret, results, neighbours ,dist = self.knn.findNearest(data, nr)
+ print(C_DBUG, "KNN Raw:")
+ print("\t\tresult: \t{}".format(results) )
+ print("\t\tneighbours:\t{}".format(neighbours) )
+ print("\t\tdistance:\t{}".format(dist) )
+ return neighbours[0]
if __name__ == "__main__":
args = parser.parse_args()
diff --git a/src/suite.py b/src/suite.py
index c2b2629..24401ec 100644
--- a/src/suite.py
+++ b/src/suite.py
@@ -28,14 +28,13 @@ import matplotlib.pyplot as plt
# Helpers
from helpers.statistics import imgStats
-from helpers.logger import CVSuiteLogger, C_DBUG, C_WARN
+from helpers.logger import CVSuiteLogger, C_INFO, C_DBUG, C_WARN, C_DONE
from helpers.canvas import CVSuiteCanvas
from helpers.sift import getSiftData
from helpers.tags import Tree
# Tests
from helpers.test.knn import CVSuiteTestKNN
-
from helpers.test.decision_tree import CVSuiteTestDecisionTree
## UI config load
@@ -48,10 +47,18 @@ CONFIG_PATH = "./src/config/config.json"
config_file = open(CONFIG_PATH, encoding="utf-8")
config_json = json.load(config_file)
+print(
+ f"""
+Welcome to CVSuite aka {TITLE}!
+Powered by ARNweb.nl and TomSelier.com
+"""
+)
+
## UI class setup
class CVSuite:
def __init__(self, master=None):
+ ### UI setup ###
# Pygubu builder
self.builder = builder = pygubu.Builder()
builder.add_resource_path(PROJECT_PATH)
@@ -102,28 +109,45 @@ class CVSuite:
)
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"])
+
+ ### End of UI setup ###
+
+ ### Model tests setup ###
# Attempt to load scaler
if config_json["scaler"] != "":
self.scaler = joblib.load(config_json["scaler"])
else:
self.scaler = None
- # Model tests
- if self.scaler is not None and config_json["models"]["knn"] != "":
- self.test_knn = CVSuiteTestKNN(config_json["models"]["knn"])
- else:
- self.test_knn = None
+ self.models = []
+ if self.scaler is not None:
+ for model in config_json["models"]:
+ if config_json["models"][model] != "":
+ print(C_INFO, f"Loading model {model}")
+ if model == "knn":
+ self.models.append(
+ ("KNN", CVSuiteTestKNN(config_json["models"]["knn"]))
+ )
+ elif model == "dectree":
+ self.models.append(
+ (
+ "Decision Tree",
+ CVSuiteTestDecisionTree(
+ config_json["models"]["dectree"]
+ ),
+ )
+ )
+ else:
+ print(C_WARN, f"Model {model} does not exist!")
+ else:
+ print(C_WARN, f"Model {model} not configured!")
+ print(C_DONE, f"{len(self.models)} models loaded!")
- if config_json["models"]["dectree"] != "":
- self.test_dectree = CVSuiteTestDecisionTree(
- config_json["models"]["dectree"]
- )
- else:
- self.test_dectree = None
-
- # Load values from config after UI has been initialised
- self.img_path.set(config_json["path"])
- self.img_size.set(config_json["size"])
+ print(C_DONE, "CVSuite initialised!\n")
+ ### End of model tests setup ###
def on_quit(self, event=None):
"""
@@ -311,7 +335,7 @@ class CVSuite:
# Don't run the test if there's no scaler
if self.scaler is None:
return
-
+
output = self.builder.get_object("testdata")
output.configure(state="normal")
output.delete(1.0, "end")
@@ -319,42 +343,26 @@ class CVSuite:
# Remove tag and photoId
tag = data.pop(0)
photoId = data.pop(1)
-
- # Add actual name
- output.insert("end", f"Actual:\n\t{tag.upper()}\n")
+
+ # Add actual name
+ output.insert("end", f"Actual type:\n\t{tag.upper()}\n")
# Normalise data using loaded scalers
for idx, value in enumerate(data):
d = np.array(value)
data[idx] = self.scaler[idx].transform(d.astype(np.float32).reshape(1, -1))[0][0]
-
+
data = np.array([data], dtype=np.float32)
-
- if self.test_knn is not None:
- # Do knn test
- output.insert("end", "KNN Result:\n")
- ret, results, neighbours ,dist = self.test_knn.predict(data)
+ for name, ins in self.models:
+ output.insert("end", f"{name} Result:\n")
- for idx, res_id in enumerate(neighbours[0]):
- output.insert("end", f" {idx}:\t{Tree(res_id).name}\n")
-
- print(C_DBUG, "KNN Result:")
- print("\t\tresult: \t{}".format(results) )
- print("\t\tneighbours:\t{}".format(neighbours) )
- print("\t\tdistance:\t{}".format(dist) )
- else:
- print(C_WARN, "KNN Model not configured!")
+ # Predict result using model instance
+ result = ins.predict(data)
- if self.test_dectree is not None:
- result = self.test_dectree.predict(data)
- output.insert("end", "Decision Tree Result:\n")
- output.insert("end", f"\t{Tree(result).name}\n")
-
- print(C_DBUG, "Decision Tree Result:")
- print("\t\t result: \t{}".format(result))
- else:
- print(C_WARN, "Decison Tree Model not configured!")
+ # Prediciton result should be an array
+ for idx, value in enumerate(result):
+ output.insert("end", f" [{idx + 1}]\t{Tree(value).name}\n")
output.configure(state="disabled")
@@ -381,9 +389,8 @@ class CVSuite:
def update(self, event=None, part_update=None):
## Check if hist and canny hm have to be rerendered
- if (
- part_update is None
- ): ## If partial update has not been forced, check if full update is required
+ if part_update is None:
+ ## If partial update has not been forced, check if full update is required
if self.img_current != self.img_old or self.img_size != self.img_size_old:
part_update = False
self.img_old = self.img_current
@@ -397,7 +404,7 @@ class CVSuite:
print("Full update forced!")
if self.updatePath():
- print(C_DBUG, f"Processing {self.img_name}")
+ print(C_INFO, f"Processing {self.img_name}")
self.mainwindow.title(f"{TITLE} - {self.img_name}")
self.log.add("Tree", self.img_name.split("_")[0])